Print this page
11493 aggr needs support for multiple pseudo rx groups
Portions contributed by: Dan McDonald <danmcd@joyent.com>
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>

*** 69,82 **** static void aggr_port_destructor(void *buf, void *arg) { aggr_port_t *port = buf; ! ASSERT(port->lp_mnh == NULL); ! ASSERT(port->lp_mphp == NULL); ! ASSERT(!port->lp_rx_grp_added && !port->lp_tx_grp_added); ! ASSERT(port->lp_hwgh == NULL); } void aggr_port_init(void) { --- 69,82 ---- static void aggr_port_destructor(void *buf, void *arg) { aggr_port_t *port = buf; ! ASSERT3P(port->lp_mnh, ==, NULL); ! ASSERT(!port->lp_tx_grp_added); ! for (uint_t i = 0; i < MAX_GROUPS_PER_PORT; i++) ! ASSERT3P(port->lp_hwghs[i], ==, NULL); } void aggr_port_init(void) {
*** 126,136 **** * (lp_closing is set). */ aggr_grp_port_hold(port); } - /* ARGSUSED */ int aggr_port_create(aggr_grp_t *grp, const datalink_id_t linkid, boolean_t force, aggr_port_t **pp) { int err; --- 126,135 ----
*** 195,216 **** err = ENOMEM; goto fail; } /* ! * As the underlying mac's current margin size is used to determine * the margin size of the aggregation itself, request the underlying ! * mac not to change to a smaller size. */ if ((err = mac_margin_add(mh, &margin, B_TRUE)) != 0) { id_free(aggr_portids, portid); goto fail; } if ((err = mac_unicast_add(mch, NULL, MAC_UNICAST_PRIMARY | MAC_UNICAST_DISABLE_TX_VID_CHECK, &mah, 0, &diag)) != 0) { ! VERIFY(mac_margin_remove(mh, margin) == 0); id_free(aggr_portids, portid); goto fail; } port = kmem_cache_alloc(aggr_port_cache, KM_SLEEP); --- 194,215 ---- err = ENOMEM; goto fail; } /* ! * As the underlying MAC's current margin size is used to determine * the margin size of the aggregation itself, request the underlying ! * MAC not to change to a smaller size. */ if ((err = mac_margin_add(mh, &margin, B_TRUE)) != 0) { id_free(aggr_portids, portid); goto fail; } if ((err = mac_unicast_add(mch, NULL, MAC_UNICAST_PRIMARY | MAC_UNICAST_DISABLE_TX_VID_CHECK, &mah, 0, &diag)) != 0) { ! VERIFY3S(mac_margin_remove(mh, margin), ==, 0); id_free(aggr_portids, portid); goto fail; } port = kmem_cache_alloc(aggr_port_cache, KM_SLEEP);
*** 261,286 **** return (0); fail: if (mch != NULL) mac_client_close(mch, MAC_CLOSE_FLAGS_EXCLUSIVE); mac_close(mh); return (err); } void aggr_port_delete(aggr_port_t *port) { aggr_lacp_port_t *pl = &port->lp_lacp; - ASSERT(port->lp_mphp == NULL); ASSERT(!port->lp_promisc_on); - port->lp_closing = B_TRUE; - VERIFY(mac_margin_remove(port->lp_mh, port->lp_margin) == 0); - mac_rx_clear(port->lp_mch); /* * If the notification callback is already in process and waiting for * the aggr grp's mac perimeter, don't wait (otherwise there would be * deadlock). Otherwise, if mac_notify_remove() succeeds, we can * release the reference held when mac_notify_add() is called. --- 260,284 ---- return (0); fail: if (mch != NULL) mac_client_close(mch, MAC_CLOSE_FLAGS_EXCLUSIVE); + mac_close(mh); return (err); } void aggr_port_delete(aggr_port_t *port) { aggr_lacp_port_t *pl = &port->lp_lacp; ASSERT(!port->lp_promisc_on); port->lp_closing = B_TRUE; + VERIFY0(mac_margin_remove(port->lp_mh, port->lp_margin)); + mac_client_clear_flow_cb(port->lp_mch); /* * If the notification callback is already in process and waiting for * the aggr grp's mac perimeter, don't wait (otherwise there would be * deadlock). Otherwise, if mac_notify_remove() succeeds, we can * release the reference held when mac_notify_add() is called.
*** 307,318 **** --- 305,318 ---- * Restore the port MAC address. Note it is called after the * port's notification callback being removed. This prevent * port's MAC_NOTE_UNICST notify callback function being called. */ (void) mac_unicast_primary_set(port->lp_mh, port->lp_addr); + if (port->lp_mah != NULL) (void) mac_unicast_remove(port->lp_mch, port->lp_mah); + mac_client_close(port->lp_mch, MAC_CLOSE_FLAGS_EXCLUSIVE); mac_close(port->lp_mh); AGGR_PORT_REFRELE(port); }
*** 519,564 **** /* update the port state */ port->lp_started = B_FALSE; } int aggr_port_promisc(aggr_port_t *port, boolean_t on) { int rc; ASSERT(MAC_PERIM_HELD(port->lp_mh)); if (on == port->lp_promisc_on) - /* already in desired promiscous mode */ return (0); ! if (on) { ! mac_rx_clear(port->lp_mch); ! /* ! * We use the promisc callback because without hardware ! * rings, we deliver through flows that will cause duplicate ! * delivery of packets when we've flipped into this mode ! * to compensate for the lack of hardware MAC matching ! */ ! rc = mac_promisc_add(port->lp_mch, MAC_CLIENT_PROMISC_ALL, ! aggr_recv_promisc_cb, port, &port->lp_mphp, ! MAC_PROMISC_FLAGS_NO_TX_LOOP); ! if (rc != 0) { ! mac_rx_set(port->lp_mch, aggr_recv_cb, port); ! return (rc); ! } ! } else { ! mac_promisc_remove(port->lp_mphp); ! port->lp_mphp = NULL; ! mac_rx_set(port->lp_mch, aggr_recv_cb, port); ! } ! port->lp_promisc_on = on; ! return (0); } /* * Set the MAC address of a port. */ --- 519,548 ---- /* update the port state */ port->lp_started = B_FALSE; } + /* + * Set the promisc mode of the port. If the port is already in the + * requested mode then do nothing. + */ int aggr_port_promisc(aggr_port_t *port, boolean_t on) { int rc; ASSERT(MAC_PERIM_HELD(port->lp_mh)); if (on == port->lp_promisc_on) return (0); ! rc = mac_set_promisc(port->lp_mh, on); ! if (rc == 0) port->lp_promisc_on = on; ! return (rc); } /* * Set the MAC address of a port. */
*** 594,632 **** { return (mac_stat_get(port->lp_mh, stat)); } /* ! * Add a non-primary unicast address to the underlying port. If the port ! * supports HW Rx group, try to add the address into the HW Rx group of ! * the port first. If that fails, or if the port does not support HW Rx ! * group, enable the port's promiscous mode. */ int ! aggr_port_addmac(aggr_port_t *port, const uint8_t *mac_addr) { aggr_unicst_addr_t *addr, **pprev; mac_perim_handle_t pmph; int err; ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh)); mac_perim_enter_by_mh(port->lp_mh, &pmph); /* ! * If the underlying port support HW Rx group, add the mac to its ! * RX group directly. */ ! if ((port->lp_hwgh != NULL) && ! ((mac_hwgroup_addmac(port->lp_hwgh, mac_addr)) == 0)) { mac_perim_exit(pmph); return (0); } /* ! * If that fails, or if the port does not support HW Rx group, enable ! * the port's promiscous mode. (Note that we turn on the promiscous ! * mode only if the port is already started. */ if (port->lp_started && ((err = aggr_port_promisc(port, B_TRUE)) != 0)) { mac_perim_exit(pmph); return (err); --- 578,626 ---- { return (mac_stat_get(port->lp_mh, stat)); } /* ! * Add a non-primary unicast address to the underlying port. If the ! * port supports HW Rx groups, then try to add the address filter to ! * the HW group first. If that fails, or if the port does not support ! * RINGS capab, then enable the port's promiscous mode. */ int ! aggr_port_addmac(aggr_port_t *port, uint_t idx, const uint8_t *mac_addr) { aggr_unicst_addr_t *addr, **pprev; mac_perim_handle_t pmph; int err; ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh)); + ASSERT3U(idx, <, MAX_GROUPS_PER_PORT); mac_perim_enter_by_mh(port->lp_mh, &pmph); /* ! * If the port doesn't have a HW group to back the aggr's ! * pseudo group, then try using the port's default group and ! * let the aggr SW classify its traffic. This scenario happens ! * when mixing ports with a different number of HW groups. */ ! if (port->lp_hwghs[idx] == NULL) ! idx = 0; ! ! /* ! * If there is an underlying HW Rx group, then try adding this ! * unicast address to it. ! */ ! if ((port->lp_hwghs[idx] != NULL) && ! ((mac_hwgroup_addmac(port->lp_hwghs[idx], mac_addr)) == 0)) { mac_perim_exit(pmph); return (0); } /* ! * If the port doesn't have HW groups, or we failed to add the ! * HW filter, then enable the port's promiscuous mode. We ! * enable promiscuous mode only if the port is already started. */ if (port->lp_started && ((err = aggr_port_promisc(port, B_TRUE)) != 0)) { mac_perim_exit(pmph); return (err);
*** 654,670 **** * must has been added by aggr_port_addmac(). As a result, we probably need to * remove the address from the port's HW Rx group, or to disable the port's * promiscous mode. */ void ! aggr_port_remmac(aggr_port_t *port, const uint8_t *mac_addr) { aggr_grp_t *grp = port->lp_grp; aggr_unicst_addr_t *addr, **pprev; mac_perim_handle_t pmph; ASSERT(MAC_PERIM_HELD(grp->lg_mh)); mac_perim_enter_by_mh(port->lp_mh, &pmph); /* * See whether this address is in the list of addresses that requires * the port being promiscous mode. --- 648,665 ---- * must has been added by aggr_port_addmac(). As a result, we probably need to * remove the address from the port's HW Rx group, or to disable the port's * promiscous mode. */ void ! aggr_port_remmac(aggr_port_t *port, uint_t idx, const uint8_t *mac_addr) { aggr_grp_t *grp = port->lp_grp; aggr_unicst_addr_t *addr, **pprev; mac_perim_handle_t pmph; ASSERT(MAC_PERIM_HELD(grp->lg_mh)); + ASSERT3U(idx, <, MAX_GROUPS_PER_PORT); mac_perim_enter_by_mh(port->lp_mh, &pmph); /* * See whether this address is in the list of addresses that requires * the port being promiscous mode.
*** 673,682 **** --- 668,678 ---- while ((addr = *pprev) != NULL) { if (bcmp(mac_addr, addr->aua_addr, ETHERADDRL) == 0) break; pprev = &addr->aua_next; } + if (addr != NULL) { /* * This unicast address put the port into the promiscous mode, * delete this address from the lp_prom_addr list. If this is * the last address in that list, disable the promiscous mode
*** 685,734 **** *pprev = addr->aua_next; kmem_free(addr, sizeof (aggr_unicst_addr_t)); if (port->lp_prom_addr == NULL && !grp->lg_promisc) (void) aggr_port_promisc(port, B_FALSE); } else { ! ASSERT(port->lp_hwgh != NULL); ! (void) mac_hwgroup_remmac(port->lp_hwgh, mac_addr); } mac_perim_exit(pmph); } int ! aggr_port_addvlan(aggr_port_t *port, uint16_t vid) { mac_perim_handle_t pmph; int err; ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh)); mac_perim_enter_by_mh(port->lp_mh, &pmph); /* * Add the VLAN filter to the HW group if the port has a HW * group. If the port doesn't have a HW group, then it will * implicitly allow tagged traffic to pass and there is * nothing to do. */ ! if (port->lp_hwgh == NULL) ! return (0); - err = mac_hwgroup_addvlan(port->lp_hwgh, vid); mac_perim_exit(pmph); return (err); } int ! aggr_port_remvlan(aggr_port_t *port, uint16_t vid) { mac_perim_handle_t pmph; int err; ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh)); mac_perim_enter_by_mh(port->lp_mh, &pmph); ! if (port->lp_hwgh == NULL) ! return (0); ! err = mac_hwgroup_remvlan(port->lp_hwgh, vid); mac_perim_exit(pmph); return (err); } --- 681,747 ---- *pprev = addr->aua_next; kmem_free(addr, sizeof (aggr_unicst_addr_t)); if (port->lp_prom_addr == NULL && !grp->lg_promisc) (void) aggr_port_promisc(port, B_FALSE); } else { ! /* See comment in aggr_port_addmac(). */ ! if (port->lp_hwghs[idx] == NULL) ! idx = 0; ! ! ASSERT3P(port->lp_hwghs[idx], !=, NULL); ! (void) mac_hwgroup_remmac(port->lp_hwghs[idx], mac_addr); } + mac_perim_exit(pmph); } int ! aggr_port_addvlan(aggr_port_t *port, uint_t idx, uint16_t vid) { mac_perim_handle_t pmph; int err; ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh)); + ASSERT3U(idx, <, MAX_GROUPS_PER_PORT); mac_perim_enter_by_mh(port->lp_mh, &pmph); + /* See comment in aggr_port_addmac(). */ + if (port->lp_hwghs[idx] == NULL) + idx = 0; + /* * Add the VLAN filter to the HW group if the port has a HW * group. If the port doesn't have a HW group, then it will * implicitly allow tagged traffic to pass and there is * nothing to do. */ ! if (port->lp_hwghs[idx] == NULL) ! err = 0; ! else ! err = mac_hwgroup_addvlan(port->lp_hwghs[idx], vid); mac_perim_exit(pmph); return (err); } int ! aggr_port_remvlan(aggr_port_t *port, uint_t idx, uint16_t vid) { mac_perim_handle_t pmph; int err; ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh)); + ASSERT3U(idx, <, MAX_GROUPS_PER_PORT); mac_perim_enter_by_mh(port->lp_mh, &pmph); ! /* See comment in aggr_port_addmac(). */ ! if (port->lp_hwghs[idx] == NULL) ! idx = 0; ! if (port->lp_hwghs[idx] == NULL) ! err = 0; ! else ! err = mac_hwgroup_remvlan(port->lp_hwghs[idx], vid); ! mac_perim_exit(pmph); return (err); }