- ofproto = bundle->ofproto;
- for (i = 0; i < MAX_MIRRORS; i++) {
- struct ofmirror *m = ofproto->mirrors[i];
- if (m) {
- if (m->out == bundle) {
- mirror_destroy(m);
- } else if (hmapx_find_and_delete(&m->srcs, bundle)
- || hmapx_find_and_delete(&m->dsts, bundle)) {
- ofproto->need_revalidate = REV_RECONFIGURE;
- }
- }
- }
-
- LIST_FOR_EACH_SAFE (port, next_port, bundle_node, &bundle->ports) {
- bundle_del_port(port);
- }
-
- bundle_flush_macs(bundle, true);
- hmap_remove(&ofproto->bundles, &bundle->hmap_node);
- free(bundle->name);
- free(bundle->trunks);
- lacp_destroy(bundle->lacp);
- bond_destroy(bundle->bond);
- free(bundle);
-}
-
-static int
-bundle_set(struct ofproto *ofproto_, void *aux,
- const struct ofproto_bundle_settings *s)
-{
- struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
- bool need_flush = false;
- struct ofport_dpif *port;
- struct ofbundle *bundle;
- unsigned long *trunks;
- int vlan;
- size_t i;
- bool ok;
-
- if (!s) {
- bundle_destroy(bundle_lookup(ofproto, aux));
- return 0;
- }
-
- assert(s->n_slaves == 1 || s->bond != NULL);
- assert((s->lacp != NULL) == (s->lacp_slaves != NULL));
-
- bundle = bundle_lookup(ofproto, aux);
- if (!bundle) {
- bundle = xmalloc(sizeof *bundle);
-
- bundle->ofproto = ofproto;
- hmap_insert(&ofproto->bundles, &bundle->hmap_node,
- hash_pointer(aux, 0));
- bundle->aux = aux;
- bundle->name = NULL;
-
- list_init(&bundle->ports);
- bundle->vlan_mode = PORT_VLAN_TRUNK;
- bundle->vlan = -1;
- bundle->trunks = NULL;
- bundle->use_priority_tags = s->use_priority_tags;
- bundle->lacp = NULL;
- bundle->bond = NULL;
-
- bundle->floodable = true;
-
- bundle->src_mirrors = 0;
- bundle->dst_mirrors = 0;
- bundle->mirror_out = 0;
- }
-
- if (!bundle->name || strcmp(s->name, bundle->name)) {
- free(bundle->name);
- bundle->name = xstrdup(s->name);
- }
-
- /* LACP. */
- if (s->lacp) {
- if (!bundle->lacp) {
- ofproto->need_revalidate = REV_RECONFIGURE;
- bundle->lacp = lacp_create();
- }
- lacp_configure(bundle->lacp, s->lacp);
- } else {
- lacp_destroy(bundle->lacp);
- bundle->lacp = NULL;
- }
-
- /* Update set of ports. */
- ok = true;
- for (i = 0; i < s->n_slaves; i++) {
- if (!bundle_add_port(bundle, s->slaves[i],
- s->lacp ? &s->lacp_slaves[i] : NULL,
- s->bond_stable_ids ? s->bond_stable_ids[i] : 0)) {
- ok = false;
- }
- }
- if (!ok || list_size(&bundle->ports) != s->n_slaves) {
- struct ofport_dpif *next_port;
-
- LIST_FOR_EACH_SAFE (port, next_port, bundle_node, &bundle->ports) {
- for (i = 0; i < s->n_slaves; i++) {
- if (s->slaves[i] == port->up.ofp_port) {
- goto found;
- }
- }
-
- bundle_del_port(port);
- found: ;
- }
- }
- assert(list_size(&bundle->ports) <= s->n_slaves);
-
- if (list_is_empty(&bundle->ports)) {
- bundle_destroy(bundle);
- return EINVAL;
- }
-
- /* Set VLAN tagging mode */
- if (s->vlan_mode != bundle->vlan_mode
- || s->use_priority_tags != bundle->use_priority_tags) {
- bundle->vlan_mode = s->vlan_mode;
- bundle->use_priority_tags = s->use_priority_tags;
- need_flush = true;
- }
-
- /* Set VLAN tag. */
- vlan = (s->vlan_mode == PORT_VLAN_TRUNK ? -1
- : s->vlan >= 0 && s->vlan <= 4095 ? s->vlan
- : 0);
- if (vlan != bundle->vlan) {
- bundle->vlan = vlan;
- need_flush = true;
- }
-
- /* Get trunked VLANs. */
- switch (s->vlan_mode) {
- case PORT_VLAN_ACCESS:
- trunks = NULL;
- break;
-
- case PORT_VLAN_TRUNK:
- trunks = CONST_CAST(unsigned long *, s->trunks);
- break;
-
- case PORT_VLAN_NATIVE_UNTAGGED:
- case PORT_VLAN_NATIVE_TAGGED:
- if (vlan != 0 && (!s->trunks
- || !bitmap_is_set(s->trunks, vlan)
- || bitmap_is_set(s->trunks, 0))) {
- /* Force trunking the native VLAN and prohibit trunking VLAN 0. */
- if (s->trunks) {
- trunks = bitmap_clone(s->trunks, 4096);
- } else {
- trunks = bitmap_allocate1(4096);
- }
- bitmap_set1(trunks, vlan);
- bitmap_set0(trunks, 0);
- } else {
- trunks = CONST_CAST(unsigned long *, s->trunks);
- }
- break;
-
- default:
- NOT_REACHED();
- }
- if (!vlan_bitmap_equal(trunks, bundle->trunks)) {
- free(bundle->trunks);
- if (trunks == s->trunks) {
- bundle->trunks = vlan_bitmap_clone(trunks);
- } else {
- bundle->trunks = trunks;
- trunks = NULL;
- }
- need_flush = true;
- }
- if (trunks != s->trunks) {
- free(trunks);
- }
-
- /* Bonding. */
- if (!list_is_short(&bundle->ports)) {
- bundle->ofproto->has_bonded_bundles = true;
- if (bundle->bond) {
- if (bond_reconfigure(bundle->bond, s->bond)) {
- ofproto->need_revalidate = REV_RECONFIGURE;
- }
- } else {
- bundle->bond = bond_create(s->bond);
- ofproto->need_revalidate = REV_RECONFIGURE;
- }
-
- LIST_FOR_EACH (port, bundle_node, &bundle->ports) {
- bond_slave_register(bundle->bond, port, port->bond_stable_id,
- port->up.netdev);
- }
- } else {
- bond_destroy(bundle->bond);
- bundle->bond = NULL;
- }
-
- /* If we changed something that would affect MAC learning, un-learn
- * everything on this port and force flow revalidation. */
- if (need_flush) {
- bundle_flush_macs(bundle, false);
- }
-
- return 0;
-}
-
-static void
-bundle_remove(struct ofport *port_)
-{
- struct ofport_dpif *port = ofport_dpif_cast(port_);
- struct ofbundle *bundle = port->bundle;
-
- if (bundle) {
- bundle_del_port(port);
- if (list_is_empty(&bundle->ports)) {
- bundle_destroy(bundle);
- } else if (list_is_short(&bundle->ports)) {
- bond_destroy(bundle->bond);
- bundle->bond = NULL;
- }
- }
-}
-
-static void
-send_pdu_cb(void *port_, const void *pdu, size_t pdu_size)
-{
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 10);
- struct ofport_dpif *port = port_;
- uint8_t ea[ETH_ADDR_LEN];
- int error;
-
- error = netdev_get_etheraddr(port->up.netdev, ea);
- if (!error) {
- struct ofpbuf packet;
- void *packet_pdu;
-
- ofpbuf_init(&packet, 0);
- packet_pdu = eth_compose(&packet, eth_addr_lacp, ea, ETH_TYPE_LACP,
- pdu_size);
- memcpy(packet_pdu, pdu, pdu_size);
-
- send_packet(port, &packet);
- ofpbuf_uninit(&packet);
- } else {
- VLOG_ERR_RL(&rl, "port %s: cannot obtain Ethernet address of iface "
- "%s (%s)", port->bundle->name,
- netdev_get_name(port->up.netdev), strerror(error));
- }
-}
-
-static void
-bundle_send_learning_packets(struct ofbundle *bundle)
-{
- struct ofproto_dpif *ofproto = bundle->ofproto;
- int error, n_packets, n_errors;
- struct mac_entry *e;
-
- error = n_packets = n_errors = 0;
- LIST_FOR_EACH (e, lru_node, &ofproto->ml->lrus) {
- if (e->port.p != bundle) {
- struct ofpbuf *learning_packet;
- struct ofport_dpif *port;
- void *port_void;
- int ret;
-
- /* The assignment to "port" is unnecessary but makes "grep"ing for
- * struct ofport_dpif more effective. */
- learning_packet = bond_compose_learning_packet(bundle->bond,
- e->mac, e->vlan,
- &port_void);
- port = port_void;
- ret = send_packet(port, learning_packet);
- ofpbuf_delete(learning_packet);
- if (ret) {
- error = ret;
- n_errors++;
- }
- n_packets++;
- }
- }
-
- if (n_errors) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
- VLOG_WARN_RL(&rl, "bond %s: %d errors sending %d gratuitous learning "
- "packets, last error was: %s",
- bundle->name, n_errors, n_packets, strerror(error));
- } else {
- VLOG_DBG("bond %s: sent %d gratuitous learning packets",
- bundle->name, n_packets);
- }
-}
-
-static void
-bundle_run(struct ofbundle *bundle)
-{
- if (bundle->lacp) {
- lacp_run(bundle->lacp, send_pdu_cb);
- }
- if (bundle->bond) {
- struct ofport_dpif *port;
-
- LIST_FOR_EACH (port, bundle_node, &bundle->ports) {
- bond_slave_set_may_enable(bundle->bond, port, port->may_enable);
- }
-
- bond_run(bundle->bond, &bundle->ofproto->revalidate_set,
- lacp_status(bundle->lacp));
- if (bond_should_send_learning_packets(bundle->bond)) {
- bundle_send_learning_packets(bundle);
- }
- }
-}
-
-static void
-bundle_wait(struct ofbundle *bundle)
-{
- if (bundle->lacp) {
- lacp_wait(bundle->lacp);
- }
- if (bundle->bond) {
- bond_wait(bundle->bond);
- }
-}
-\f
-/* Mirrors. */
-
-static int
-mirror_scan(struct ofproto_dpif *ofproto)
-{
- int idx;
-
- for (idx = 0; idx < MAX_MIRRORS; idx++) {
- if (!ofproto->mirrors[idx]) {
- return idx;
- }
- }
- return -1;
-}
-
-static struct ofmirror *
-mirror_lookup(struct ofproto_dpif *ofproto, void *aux)
-{
- int i;
-
- for (i = 0; i < MAX_MIRRORS; i++) {
- struct ofmirror *mirror = ofproto->mirrors[i];
- if (mirror && mirror->aux == aux) {
- return mirror;
- }
- }
-
- return NULL;
-}
-
-/* Update the 'dup_mirrors' member of each of the ofmirrors in 'ofproto'. */
-static void
-mirror_update_dups(struct ofproto_dpif *ofproto)
-{
- int i;
-
- for (i = 0; i < MAX_MIRRORS; i++) {
- struct ofmirror *m = ofproto->mirrors[i];
-
- if (m) {
- m->dup_mirrors = MIRROR_MASK_C(1) << i;
- }
- }
-
- for (i = 0; i < MAX_MIRRORS; i++) {
- struct ofmirror *m1 = ofproto->mirrors[i];
- int j;
-
- if (!m1) {
- continue;
- }
-
- for (j = i + 1; j < MAX_MIRRORS; j++) {
- struct ofmirror *m2 = ofproto->mirrors[j];
-
- if (m2 && m1->out == m2->out && m1->out_vlan == m2->out_vlan) {
- m1->dup_mirrors |= MIRROR_MASK_C(1) << j;
- m2->dup_mirrors |= m1->dup_mirrors;
- }
- }
- }
-}
-
-static int
-mirror_set(struct ofproto *ofproto_, void *aux,
- const struct ofproto_mirror_settings *s)
-{
- struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
- mirror_mask_t mirror_bit;
- struct ofbundle *bundle;
- struct ofmirror *mirror;
- struct ofbundle *out;
- struct hmapx srcs; /* Contains "struct ofbundle *"s. */
- struct hmapx dsts; /* Contains "struct ofbundle *"s. */
- int out_vlan;
-
- mirror = mirror_lookup(ofproto, aux);
- if (!s) {
- mirror_destroy(mirror);
- return 0;
- }
- if (!mirror) {
- int idx;
-
- idx = mirror_scan(ofproto);
- if (idx < 0) {
- VLOG_WARN("bridge %s: maximum of %d port mirrors reached, "
- "cannot create %s",
- ofproto->up.name, MAX_MIRRORS, s->name);
- return EFBIG;
- }
-
- mirror = ofproto->mirrors[idx] = xzalloc(sizeof *mirror);
- mirror->ofproto = ofproto;
- mirror->idx = idx;
- mirror->aux = aux;
- mirror->out_vlan = -1;
- mirror->name = NULL;
- }
-
- if (!mirror->name || strcmp(s->name, mirror->name)) {
- free(mirror->name);
- mirror->name = xstrdup(s->name);
- }
-
- /* Get the new configuration. */
- if (s->out_bundle) {
- out = bundle_lookup(ofproto, s->out_bundle);
- if (!out) {
- mirror_destroy(mirror);
- return EINVAL;
- }
- out_vlan = -1;
- } else {
- out = NULL;
- out_vlan = s->out_vlan;
- }
- bundle_lookup_multiple(ofproto, s->srcs, s->n_srcs, &srcs);
- bundle_lookup_multiple(ofproto, s->dsts, s->n_dsts, &dsts);
-
- /* If the configuration has not changed, do nothing. */
- if (hmapx_equals(&srcs, &mirror->srcs)
- && hmapx_equals(&dsts, &mirror->dsts)
- && vlan_bitmap_equal(mirror->vlans, s->src_vlans)
- && mirror->out == out
- && mirror->out_vlan == out_vlan)
- {
- hmapx_destroy(&srcs);
- hmapx_destroy(&dsts);
- return 0;
- }
-
- hmapx_swap(&srcs, &mirror->srcs);
- hmapx_destroy(&srcs);
-
- hmapx_swap(&dsts, &mirror->dsts);
- hmapx_destroy(&dsts);
-
- free(mirror->vlans);
- mirror->vlans = vlan_bitmap_clone(s->src_vlans);
-
- mirror->out = out;
- mirror->out_vlan = out_vlan;
-
- /* Update bundles. */
- mirror_bit = MIRROR_MASK_C(1) << mirror->idx;
- HMAP_FOR_EACH (bundle, hmap_node, &mirror->ofproto->bundles) {
- if (hmapx_contains(&mirror->srcs, bundle)) {
- bundle->src_mirrors |= mirror_bit;
- } else {
- bundle->src_mirrors &= ~mirror_bit;
- }
-
- if (hmapx_contains(&mirror->dsts, bundle)) {
- bundle->dst_mirrors |= mirror_bit;
- } else {
- bundle->dst_mirrors &= ~mirror_bit;
- }
-
- if (mirror->out == bundle) {
- bundle->mirror_out |= mirror_bit;
- } else {
- bundle->mirror_out &= ~mirror_bit;
- }
- }
-
- ofproto->need_revalidate = REV_RECONFIGURE;
- ofproto->has_mirrors = true;
- mac_learning_flush(ofproto->ml, &ofproto->revalidate_set);
- mirror_update_dups(ofproto);
-