Mercurial > illumos > illumos-gate
changeset 2047:e21b6f0a829b
6408047 DL_NOTE_LINK_DOWN might be missing when a port is removed from an aggregation
6423463 Bogus check of aggregation lg_closing flag when removing a port from the aggregation
6423580 The MAC address of an aggregated device isn't changed back when the aggregation is deleted
author | yz147064 |
---|---|
date | Wed, 24 May 2006 09:39:06 -0700 |
parents | ef717412c771 |
children | 8ceabdf91507 |
files | usr/src/uts/common/io/aggr/aggr_grp.c usr/src/uts/common/io/aggr/aggr_port.c usr/src/uts/common/sys/aggr_impl.h |
diffstat | 3 files changed, 191 insertions(+), 111 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/io/aggr/aggr_grp.c Tue May 23 15:29:12 2006 -0700 +++ b/usr/src/uts/common/io/aggr/aggr_grp.c Wed May 24 09:39:06 2006 -0700 @@ -69,7 +69,8 @@ static void aggr_m_ioctl(void *, queue_t *, mblk_t *); static aggr_port_t *aggr_grp_port_lookup(aggr_grp_t *, const char *, uint32_t); -static int aggr_grp_rem_port(aggr_grp_t *, aggr_port_t *, boolean_t *); +static int aggr_grp_rem_port(aggr_grp_t *, aggr_port_t *, boolean_t *, + boolean_t *); static void aggr_stats_op(enum mac_stat, uint64_t *, uint64_t *, boolean_t); static void aggr_grp_capab_set(aggr_grp_t *); static boolean_t aggr_grp_capab_check(aggr_grp_t *, aggr_port_t *); @@ -170,7 +171,7 @@ boolean_t aggr_grp_attach_port(aggr_grp_t *grp, aggr_port_t *port) { - boolean_t link_changed = B_FALSE; + boolean_t link_state_changed = B_FALSE; ASSERT(AGGR_LACP_LOCK_HELD(grp)); ASSERT(RW_WRITE_HELD(&grp->lg_lock)); @@ -199,7 +200,7 @@ * attached. */ grp->lg_ifspeed = port->lp_ifspeed; - link_changed = B_TRUE; + link_state_changed = B_TRUE; } else if (grp->lg_ifspeed != port->lp_ifspeed) { /* * The link speed of the MAC port must be the same as @@ -217,7 +218,7 @@ if (grp->lg_link_state != LINK_STATE_UP) { grp->lg_link_state = LINK_STATE_UP; grp->lg_link_duplex = LINK_DUPLEX_FULL; - link_changed = B_TRUE; + link_state_changed = B_TRUE; } aggr_grp_multicst_port(port, B_TRUE); @@ -245,13 +246,13 @@ else aggr_lacp_port_attached(port); - return (link_changed); + return (link_state_changed); } boolean_t aggr_grp_detach_port(aggr_grp_t *grp, aggr_port_t *port) { - boolean_t link_changed = B_FALSE; + boolean_t link_state_changed = B_FALSE; ASSERT(RW_WRITE_HELD(&grp->lg_lock)); ASSERT(RW_WRITE_HELD(&port->lp_lock)); @@ -277,10 +278,10 @@ grp->lg_ifspeed = 0; grp->lg_link_state = LINK_STATE_DOWN; grp->lg_link_duplex = LINK_DUPLEX_UNKNOWN; - link_changed = B_TRUE; + link_state_changed = B_TRUE; } - return (link_changed); + return (link_state_changed); } /* @@ -292,48 +293,73 @@ * that port was used for the MAC address of the group. * - after the MAC address of a port changed when the MAC address * of that port was used for the MAC address of the group. + * + * Return true if the link state of the aggregation changed, for example + * as a result of a failure changing the MAC address of one of the + * constituent ports. */ -void +boolean_t aggr_grp_update_ports_mac(aggr_grp_t *grp) { aggr_port_t *cport; + boolean_t link_state_changed = B_FALSE; ASSERT(RW_WRITE_HELD(&grp->lg_lock)); + if (grp->lg_closing) + return (link_state_changed); + for (cport = grp->lg_ports; cport != NULL; cport = cport->lp_next) { rw_enter(&cport->lp_lock, RW_WRITER); - if (aggr_port_unicst(cport, grp->lg_addr) != 0) - (void) aggr_grp_detach_port(grp, cport); + if (aggr_port_unicst(cport, grp->lg_addr) != 0) { + link_state_changed = link_state_changed || + aggr_grp_detach_port(grp, cport); + } else { + /* + * If a port was detached because of a previous + * failure changing the MAC address, the port is + * reattached when it successfully changes the MAC + * address now, and this might cause the link state + * of the aggregation to change. + */ + link_state_changed = link_state_changed || + aggr_grp_attach_port(grp, cport); + } rw_exit(&cport->lp_lock); - if (grp->lg_closing) - break; } + return (link_state_changed); } /* * Invoked when the MAC address of a port has changed. If the port's - * MAC address was used for the group MAC address, returns B_TRUE. - * In that case, it is the responsibility of the caller to - * invoke aggr_grp_update_ports_mac() after releasing the - * the port lock, and aggr_grp_notify() after releasing the - * group lock. + * MAC address was used for the group MAC address, set mac_addr_changedp + * to B_TRUE to indicate to the caller that it should send a MAC_NOTE_UNICST + * notification. If the link state changes due to detach/attach of + * the constituent port, set link_state_changedp to B_TRUE to indicate + * to the caller that it should send a MAC_NOTE_LINK notification. In both + * cases, it is the responsibility of the caller to invoke notification + * functions after releasing the the port lock. */ -boolean_t -aggr_grp_port_mac_changed(aggr_grp_t *grp, aggr_port_t *port) +void +aggr_grp_port_mac_changed(aggr_grp_t *grp, aggr_port_t *port, + boolean_t *mac_addr_changedp, boolean_t *link_state_changedp) { - boolean_t grp_addr_changed = B_FALSE; - ASSERT(AGGR_LACP_LOCK_HELD(grp)); ASSERT(RW_WRITE_HELD(&grp->lg_lock)); ASSERT(RW_WRITE_HELD(&port->lp_lock)); + ASSERT(mac_addr_changedp != NULL); + ASSERT(link_state_changedp != NULL); + + *mac_addr_changedp = B_FALSE; + *link_state_changedp = B_FALSE; if (grp->lg_addr_fixed) { /* * The group is using a fixed MAC address or an automatic * MAC address has not been set. */ - return (B_FALSE); + return; } if (grp->lg_mac_addr_port == port) { @@ -342,17 +368,25 @@ * MAC address. Update the group MAC address. */ bcopy(port->lp_addr, grp->lg_addr, ETHERADDRL); - grp_addr_changed = B_TRUE; + *mac_addr_changedp = B_TRUE; } else { /* * Update the actual port MAC address to the MAC address * of the group. */ - if (aggr_port_unicst(port, grp->lg_addr) != 0) - (void) aggr_grp_detach_port(grp, port); + if (aggr_port_unicst(port, grp->lg_addr) != 0) { + *link_state_changedp = aggr_grp_detach_port(grp, port); + } else { + /* + * If a port was detached because of a previous + * failure changing the MAC address, the port is + * reattached when it successfully changes the MAC + * address now, and this might cause the link state + * of the aggregation to change. + */ + *link_state_changedp = aggr_grp_attach_port(grp, port); + } } - - return (grp_addr_changed); } /* @@ -458,7 +492,8 @@ } /* update the MAC address of the constituent ports */ - aggr_grp_update_ports_mac(grp); + if (aggr_grp_update_ports_mac(grp)) + mac_link_update(&grp->lg_mac, grp->lg_link_state); bail: if (rc != 0) { @@ -472,7 +507,7 @@ aggr_port_stop(port); rw_exit(&port->lp_lock); } - (void) aggr_grp_rem_port(grp, port, NULL); + (void) aggr_grp_rem_port(grp, port, NULL, NULL); } } @@ -495,6 +530,7 @@ int rc = 0; aggr_grp_t *grp = NULL; boolean_t mac_addr_changed = B_FALSE; + boolean_t link_state_changed = B_FALSE; if (grp_arg == NULL) { /* get group corresponding to key */ @@ -550,7 +586,7 @@ } if (mac_addr_changed) - aggr_grp_update_ports_mac(grp); + link_state_changed = aggr_grp_update_ports_mac(grp); if (update_mask & AGGR_MODIFY_LACP_MODE) aggr_lacp_update_mode(grp, lacp_mode); @@ -559,15 +595,26 @@ aggr_lacp_update_timer(grp, lacp_timer); bail: + if (grp != NULL && !grp->lg_closing) { + /* + * If grp_arg is non-NULL, this function is called from + * mac_unicst_set(), and the MAC_NOTE_UNICST notification + * will be sent there. + */ + if ((grp_arg == NULL) && mac_addr_changed) + mac_unicst_update(&grp->lg_mac, grp->lg_addr); + + if (link_state_changed) + mac_link_update(&grp->lg_mac, grp->lg_link_state); + + } + if (grp_arg == NULL) { if (grp != NULL) { rw_exit(&grp->lg_lock); AGGR_LACP_UNLOCK(grp); } rw_exit(&aggr_grp_lock); - /* pass new unicast address up to MAC layer */ - if (grp != NULL && mac_addr_changed && !grp->lg_closing) - mac_unicst_update(&grp->lg_mac, grp->lg_addr); } if (grp != NULL) @@ -589,6 +636,7 @@ aggr_port_t *port; mac_t *mac; mac_info_t *mip; + boolean_t link_state_changed; int err; int i; @@ -612,7 +660,7 @@ rw_enter(&grp->lg_lock, RW_WRITER); grp->lg_refs = 1; - grp->lg_closing = 0; + grp->lg_closing = B_FALSE; grp->lg_key = key; grp->lg_ifspeed = 0; @@ -652,8 +700,13 @@ grp->lg_mac_addr_port = grp->lg_ports; } - /* update the MAC address of the constituent ports */ - aggr_grp_update_ports_mac(grp); + /* + * Update the MAC address of the constituent ports. + * None of the port is attached at this time, the link state of the + * aggregation will not change. + */ + link_state_changed = aggr_grp_update_ports_mac(grp); + ASSERT(!link_state_changed); /* update outbound load balancing policy */ aggr_send_update_policy(grp, policy); @@ -715,7 +768,7 @@ if (grp != NULL) { aggr_port_t *cport; - atomic_add_32(&grp->lg_closing, 1); + grp->lg_closing = B_TRUE; port = grp->lg_ports; while (port != NULL) { @@ -758,25 +811,28 @@ * Stop, detach and remove a port from a link aggregation group. */ static int -aggr_grp_rem_port(aggr_grp_t *grp, aggr_port_t *port, boolean_t *do_notify) +aggr_grp_rem_port(aggr_grp_t *grp, aggr_port_t *port, + boolean_t *mac_addr_changedp, boolean_t *link_state_changedp) { + int rc = 0; aggr_port_t **pport; - boolean_t grp_mac_addr_changed = B_FALSE; + boolean_t mac_addr_changed = B_FALSE; + boolean_t link_state_changed = B_FALSE; uint64_t val; uint_t i; ASSERT(AGGR_LACP_LOCK_HELD(grp)); ASSERT(RW_WRITE_HELD(&grp->lg_lock)); ASSERT(grp->lg_nports > 1); - - if (do_notify != NULL) - *do_notify = B_FALSE; + ASSERT(!grp->lg_closing); /* unlink port */ for (pport = &grp->lg_ports; *pport != port; pport = &(*pport)->lp_next) { - if (*pport == NULL) - return (ENOENT); + if (*pport == NULL) { + rc = ENOENT; + goto done; + } } *pport = port->lp_next; @@ -796,10 +852,10 @@ */ bcopy(grp->lg_ports->lp_addr, grp->lg_addr, ETHERADDRL); grp->lg_mac_addr_port = grp->lg_ports; - grp_mac_addr_changed = B_TRUE; + mac_addr_changed = B_TRUE; } - (void) aggr_grp_detach_port(grp, port); + link_state_changed = aggr_grp_detach_port(grp, port); /* * Add the statistics of the ports while it was aggregated @@ -829,17 +885,17 @@ * the remaining consistuent ports according to the new MAC * address of the group. */ - if (grp->lg_closing) { - *do_notify = B_FALSE; - } else { - if (grp_mac_addr_changed) - aggr_grp_update_ports_mac(grp); + if (mac_addr_changed) + link_state_changed = link_state_changed || + aggr_grp_update_ports_mac(grp); - if (do_notify != NULL) - *do_notify = grp_mac_addr_changed; - } +done: + if (mac_addr_changedp != NULL) + *mac_addr_changedp = mac_addr_changed; + if (link_state_changedp != NULL) + *link_state_changedp = link_state_changed; - return (0); + return (rc); } /* @@ -851,7 +907,8 @@ int rc = 0, i; aggr_grp_t *grp = NULL; aggr_port_t *port; - boolean_t notify = B_FALSE, grp_mac_addr_changed; + boolean_t mac_addr_update = B_FALSE, mac_addr_changed; + boolean_t link_state_update = B_FALSE, link_state_changed; /* get group corresponding to key */ rw_enter(&aggr_grp_lock, RW_READER); @@ -897,17 +954,21 @@ } /* remove port from group */ - rc = aggr_grp_rem_port(grp, port, &grp_mac_addr_changed); + rc = aggr_grp_rem_port(grp, port, &mac_addr_changed, + &link_state_changed); ASSERT(rc == 0); - notify = notify || grp_mac_addr_changed; + mac_addr_update = mac_addr_update || mac_addr_changed; + link_state_update = link_state_update || link_state_changed; } bail: rw_exit(&grp->lg_lock); AGGR_LACP_UNLOCK(grp); - if (notify && !grp->lg_closing) + if (mac_addr_update) mac_unicst_update(&grp->lg_mac, grp->lg_addr); - if (rc == 0 && !grp->lg_closing) + if (link_state_update) + mac_link_update(&grp->lg_mac, grp->lg_link_state); + if (rc == 0) mac_resource_update(&grp->lg_mac); AGGR_GRP_REFRELE(grp); @@ -929,11 +990,11 @@ return (ENOENT); } - atomic_add_32(&grp->lg_closing, 1); - AGGR_LACP_LOCK(grp); rw_enter(&grp->lg_lock, RW_WRITER); + grp->lg_closing = B_TRUE; + /* * Unregister from the MAC service module. Since this can * fail if a client hasn't closed the MAC port, we gracefully @@ -1176,11 +1237,14 @@ { aggr_grp_t *grp = arg; aggr_port_t *port; + boolean_t link_state_changed = B_FALSE; AGGR_LACP_LOCK(grp); rw_enter(&grp->lg_lock, RW_WRITER); AGGR_GRP_REFHOLD(grp); + ASSERT(!grp->lg_closing); + if (on == grp->lg_promisc) goto bail; @@ -1188,17 +1252,30 @@ rw_enter(&port->lp_lock, RW_WRITER); AGGR_PORT_REFHOLD(port); if (port->lp_started) { - if (aggr_port_promisc(port, on) != 0) - (void) aggr_grp_detach_port(grp, port); + if (aggr_port_promisc(port, on) != 0) { + link_state_changed = link_state_changed || + aggr_grp_detach_port(grp, port); + } else { + /* + * If a port was detached because of a previous + * failure changing the promiscuity, the port + * is reattached when it successfully changes + * the promiscuity now, and this might cause + * the link state of the aggregation to change. + */ + link_state_changed = link_state_changed || + aggr_grp_attach_port(grp, port); + } } rw_exit(&port->lp_lock); AGGR_PORT_REFRELE(port); - if (grp->lg_closing) - break; } grp->lg_promisc = on; + if (link_state_changed) + mac_link_update(&grp->lg_mac, grp->lg_link_state); + bail: rw_exit(&grp->lg_lock); AGGR_LACP_UNLOCK(grp);
--- a/usr/src/uts/common/io/aggr/aggr_port.c Tue May 23 15:29:12 2006 -0700 +++ b/usr/src/uts/common/io/aggr/aggr_port.c Wed May 24 09:39:06 2006 -0700 @@ -129,7 +129,6 @@ port->lp_port = portnum; (void) strlcpy(port->lp_devname, name, sizeof (port->lp_devname)); port->lp_closing = 0; - port->lp_set_grpmac = B_FALSE; /* get the port's original MAC address */ mac_unicst_get(port->lp_mh, port->lp_addr); @@ -208,7 +207,7 @@ { boolean_t do_attach = B_FALSE; boolean_t do_detach = B_FALSE; - boolean_t grp_link_changed = B_TRUE; + boolean_t link_state_changed = B_TRUE; uint64_t ifspeed; link_state_t link_state; link_duplex_t link_duplex; @@ -249,64 +248,75 @@ if (do_attach) { /* attempt to attach the port to the aggregation */ - grp_link_changed = aggr_grp_attach_port(grp, port); + link_state_changed = aggr_grp_attach_port(grp, port); } else if (do_detach) { /* detach the port from the aggregation */ - grp_link_changed = aggr_grp_detach_port(grp, port); + link_state_changed = aggr_grp_detach_port(grp, port); } rw_exit(&port->lp_lock); rw_exit(&grp->lg_lock); AGGR_LACP_UNLOCK(grp); - return (grp_link_changed); + return (link_state_changed); } /* * Invoked upon receiving a MAC_NOTE_UNICST for one of the constituent * ports of a group. */ -static boolean_t -aggr_port_notify_unicst(aggr_grp_t *grp, aggr_port_t *port) +static void +aggr_port_notify_unicst(aggr_grp_t *grp, aggr_port_t *port, + boolean_t *mac_addr_changedp, boolean_t *link_state_changedp) { - boolean_t grp_mac_changed; + boolean_t mac_addr_changed = B_FALSE; + boolean_t link_state_changed = B_FALSE; + uint8_t mac_addr[ETHERADDRL]; + + ASSERT(mac_addr_changedp != NULL); + ASSERT(link_state_changedp != NULL); + + AGGR_LACP_LOCK(grp); + rw_enter(&grp->lg_lock, RW_WRITER); + + rw_enter(&port->lp_lock, RW_WRITER); /* * If it is called when setting the MAC address to the * aggregation group MAC address, do nothing. */ - if (port->lp_set_grpmac) - return (B_FALSE); - - AGGR_LACP_LOCK(grp); - rw_enter(&grp->lg_lock, RW_WRITER); - rw_enter(&port->lp_lock, RW_WRITER); + mac_unicst_get(port->lp_mh, mac_addr); + if (bcmp(mac_addr, grp->lg_addr, ETHERADDRL) == 0) { + rw_exit(&port->lp_lock); + goto done; + } /* save the new port MAC address */ - mac_unicst_get(port->lp_mh, port->lp_addr); + bcopy(mac_addr, port->lp_addr, ETHERADDRL); - grp_mac_changed = aggr_grp_port_mac_changed(grp, port); + aggr_grp_port_mac_changed(grp, port, &mac_addr_changed, + &link_state_changed); rw_exit(&port->lp_lock); - if (grp->lg_closing) { - rw_exit(&grp->lg_lock); - AGGR_LACP_UNLOCK(grp); - return (B_FALSE); - } + if (grp->lg_closing) + goto done; /* * If this port was used to determine the MAC address of * the group, update the MAC address of the constituent * ports. */ - if (grp_mac_changed) - aggr_grp_update_ports_mac(grp); + if (mac_addr_changed) { + link_state_changed = link_state_changed || + aggr_grp_update_ports_mac(grp); + } +done: + *mac_addr_changedp = mac_addr_changed; + *link_state_changedp = link_state_changed; rw_exit(&grp->lg_lock); AGGR_LACP_UNLOCK(grp); - - return (grp_mac_changed); } /* @@ -318,6 +328,7 @@ { aggr_port_t *port = arg; aggr_grp_t *grp = port->lp_grp; + boolean_t mac_addr_changed, link_state_changed; /* * Do nothing if the aggregation or the port is in the deletion @@ -337,8 +348,12 @@ mac_link_update(&grp->lg_mac, grp->lg_link_state); break; case MAC_NOTE_UNICST: - if (aggr_port_notify_unicst(grp, port)) + aggr_port_notify_unicst(grp, port, &mac_addr_changed, + &link_state_changed); + if (mac_addr_changed) mac_unicst_update(&grp->lg_mac, grp->lg_addr); + if (link_state_changed) + mac_link_update(&grp->lg_mac, grp->lg_link_state); break; case MAC_NOTE_PROMISC: port->lp_txinfo = mac_tx_get(port->lp_mh); @@ -414,16 +429,8 @@ ASSERT(RW_WRITE_HELD(&port->lp_lock)); - /* - * set lp_set_grpmac to indicate it is going to set the MAC - * address to the aggregation MAC address. - */ - port->lp_set_grpmac = B_TRUE; - rc = mac_unicst_set(port->lp_mh, macaddr); - port->lp_set_grpmac = B_FALSE; - return (rc); }
--- a/usr/src/uts/common/sys/aggr_impl.h Tue May 23 15:29:12 2006 -0700 +++ b/usr/src/uts/common/sys/aggr_impl.h Wed May 24 09:39:06 2006 -0700 @@ -62,12 +62,7 @@ lp_tx_enabled : 1, lp_collector_enabled : 1, lp_promisc_on : 1, - /* - * Indicates whether it is in the process of setting - * MAC address to the aggregation group MAC - */ - lp_set_grpmac : 1, - lp_pad_bits : 27; + lp_pad_bits : 28; uint32_t lp_closing; uint_t lp_port; mac_handle_t lp_mh; @@ -108,11 +103,11 @@ uint16_t lg_nports; /* number of MAC ports */ uint8_t lg_addr[ETHERADDRL]; /* group MAC address */ uint16_t + lg_closing : 1, lg_addr_fixed : 1, /* fixed MAC address? */ lg_started : 1, /* group started? */ lg_promisc : 1, /* in promiscuous mode? */ - lg_pad_bits : 13; - uint32_t lg_closing; + lg_pad_bits : 12; aggr_port_t *lg_ports; /* list of configured ports */ aggr_port_t *lg_mac_addr_port; mac_t lg_mac; @@ -178,10 +173,11 @@ extern void aggr_grp_notify(aggr_grp_t *, uint32_t); extern boolean_t aggr_grp_attach_port(aggr_grp_t *, aggr_port_t *); extern boolean_t aggr_grp_detach_port(aggr_grp_t *, aggr_port_t *); -extern boolean_t aggr_grp_port_mac_changed(aggr_grp_t *, aggr_port_t *); +extern void aggr_grp_port_mac_changed(aggr_grp_t *, aggr_port_t *, + boolean_t *, boolean_t *); extern int aggr_grp_add_ports(uint32_t, uint_t, laioc_port_t *); extern int aggr_grp_rem_ports(uint32_t, uint_t, laioc_port_t *); -extern void aggr_grp_update_ports_mac(aggr_grp_t *); +extern boolean_t aggr_grp_update_ports_mac(aggr_grp_t *); extern int aggr_grp_modify(uint32_t, aggr_grp_t *, uint8_t, uint32_t, boolean_t, const uchar_t *, aggr_lacp_mode_t, aggr_lacp_timer_t); extern void aggr_grp_multicst_port(aggr_port_t *, boolean_t);