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>

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/io/aggr/aggr_port.c
          +++ new/usr/src/uts/common/io/aggr/aggr_port.c
↓ open down ↓ 63 lines elided ↑ open up ↑
  64   64          bzero(buf, sizeof (aggr_port_t));
  65   65          return (0);
  66   66  }
  67   67  
  68   68  /*ARGSUSED*/
  69   69  static void
  70   70  aggr_port_destructor(void *buf, void *arg)
  71   71  {
  72   72          aggr_port_t *port = buf;
  73   73  
  74      -        ASSERT(port->lp_mnh == NULL);
  75      -        ASSERT(port->lp_mphp == NULL);
  76      -        ASSERT(!port->lp_rx_grp_added && !port->lp_tx_grp_added);
  77      -        ASSERT(port->lp_hwgh == NULL);
       74 +        ASSERT3P(port->lp_mnh, ==, NULL);
       75 +        ASSERT(!port->lp_tx_grp_added);
       76 +        for (uint_t i = 0; i < MAX_GROUPS_PER_PORT; i++)
       77 +                ASSERT3P(port->lp_hwghs[i], ==, NULL);
  78   78  }
  79   79  
  80   80  void
  81   81  aggr_port_init(void)
  82   82  {
  83   83          aggr_port_cache = kmem_cache_create("aggr_port_cache",
  84   84              sizeof (aggr_port_t), 0, aggr_port_constructor,
  85   85              aggr_port_destructor, NULL, NULL, NULL, 0);
  86   86  
  87   87          /*
↓ open down ↓ 33 lines elided ↑ open up ↑
 121  121           * to exit before calling mac_unregister().
 122  122           *
 123  123           * Note that these references will be released either in
 124  124           * aggr_port_delete() when mac_notify_remove() succeeds, or in
 125  125           * the aggr_port_notify_cb() callback when the port is deleted
 126  126           * (lp_closing is set).
 127  127           */
 128  128          aggr_grp_port_hold(port);
 129  129  }
 130  130  
 131      -/* ARGSUSED */
 132  131  int
 133  132  aggr_port_create(aggr_grp_t *grp, const datalink_id_t linkid, boolean_t force,
 134  133      aggr_port_t **pp)
 135  134  {
 136  135          int err;
 137  136          mac_handle_t mh;
 138  137          mac_client_handle_t mch = NULL;
 139  138          aggr_port_t *port;
 140  139          uint16_t portid;
 141  140          uint_t i;
↓ open down ↓ 48 lines elided ↑ open up ↑
 190  189              MAC_OPEN_FLAGS_IS_AGGR_PORT | MAC_OPEN_FLAGS_EXCLUSIVE)) != 0) {
 191  190                  goto fail;
 192  191          }
 193  192  
 194  193          if ((portid = (uint16_t)id_alloc(aggr_portids)) == 0) {
 195  194                  err = ENOMEM;
 196  195                  goto fail;
 197  196          }
 198  197  
 199  198          /*
 200      -         * As the underlying mac's current margin size is used to determine
      199 +         * As the underlying MAC's current margin size is used to determine
 201  200           * the margin size of the aggregation itself, request the underlying
 202      -         * mac not to change to a smaller size.
      201 +         * MAC not to change to a smaller size.
 203  202           */
 204  203          if ((err = mac_margin_add(mh, &margin, B_TRUE)) != 0) {
 205  204                  id_free(aggr_portids, portid);
 206  205                  goto fail;
 207  206          }
 208  207  
 209  208          if ((err = mac_unicast_add(mch, NULL, MAC_UNICAST_PRIMARY |
 210  209              MAC_UNICAST_DISABLE_TX_VID_CHECK, &mah, 0, &diag)) != 0) {
 211      -                VERIFY(mac_margin_remove(mh, margin) == 0);
      210 +                VERIFY3S(mac_margin_remove(mh, margin), ==, 0);
 212  211                  id_free(aggr_portids, portid);
 213  212                  goto fail;
 214  213          }
 215  214  
 216  215          port = kmem_cache_alloc(aggr_port_cache, KM_SLEEP);
 217  216  
 218  217          port->lp_refs = 1;
 219  218          port->lp_next = NULL;
 220  219          port->lp_mh = mh;
 221  220          port->lp_mch = mch;
↓ open down ↓ 34 lines elided ↑ open up ↑
 256  255  
 257  256          /* LACP related state */
 258  257          port->lp_collector_enabled = B_FALSE;
 259  258  
 260  259          *pp = port;
 261  260          return (0);
 262  261  
 263  262  fail:
 264  263          if (mch != NULL)
 265  264                  mac_client_close(mch, MAC_CLOSE_FLAGS_EXCLUSIVE);
      265 +
 266  266          mac_close(mh);
 267  267          return (err);
 268  268  }
 269  269  
 270  270  void
 271  271  aggr_port_delete(aggr_port_t *port)
 272  272  {
 273  273          aggr_lacp_port_t *pl = &port->lp_lacp;
 274  274  
 275      -        ASSERT(port->lp_mphp == NULL);
 276  275          ASSERT(!port->lp_promisc_on);
 277      -
 278  276          port->lp_closing = B_TRUE;
      277 +        VERIFY0(mac_margin_remove(port->lp_mh, port->lp_margin));
      278 +        mac_client_clear_flow_cb(port->lp_mch);
 279  279  
 280      -        VERIFY(mac_margin_remove(port->lp_mh, port->lp_margin) == 0);
 281      -        mac_rx_clear(port->lp_mch);
 282  280          /*
 283  281           * If the notification callback is already in process and waiting for
 284  282           * the aggr grp's mac perimeter, don't wait (otherwise there would be
 285  283           * deadlock). Otherwise, if mac_notify_remove() succeeds, we can
 286  284           * release the reference held when mac_notify_add() is called.
 287  285           */
 288  286          if ((port->lp_mnh != NULL) &&
 289  287              (mac_notify_remove(port->lp_mnh, B_FALSE) == 0)) {
 290  288                  aggr_grp_port_rele(port);
 291  289          }
↓ open down ↓ 10 lines elided ↑ open up ↑
 302  300          pl->lacp_timer_bits |= LACP_THREAD_EXIT;
 303  301          cv_broadcast(&pl->lacp_timer_cv);
 304  302          mutex_exit(&pl->lacp_timer_lock);
 305  303  
 306  304          /*
 307  305           * Restore the port MAC address. Note it is called after the
 308  306           * port's notification callback being removed. This prevent
 309  307           * port's MAC_NOTE_UNICST notify callback function being called.
 310  308           */
 311  309          (void) mac_unicast_primary_set(port->lp_mh, port->lp_addr);
      310 +
 312  311          if (port->lp_mah != NULL)
 313  312                  (void) mac_unicast_remove(port->lp_mch, port->lp_mah);
      313 +
 314  314          mac_client_close(port->lp_mch, MAC_CLOSE_FLAGS_EXCLUSIVE);
 315  315          mac_close(port->lp_mh);
 316  316          AGGR_PORT_REFRELE(port);
 317  317  }
 318  318  
 319  319  void
 320  320  aggr_port_free(aggr_port_t *port)
 321  321  {
 322  322          ASSERT(port->lp_refs == 0);
 323  323          if (port->lp_grp != NULL)
↓ open down ↓ 190 lines elided ↑ open up ↑
 514  514  
 515  515          if (!port->lp_started)
 516  516                  return;
 517  517  
 518  518          aggr_grp_multicst_port(port, B_FALSE);
 519  519  
 520  520          /* update the port state */
 521  521          port->lp_started = B_FALSE;
 522  522  }
 523  523  
      524 +/*
      525 + * Set the promisc mode of the port. If the port is already in the
      526 + * requested mode then do nothing.
      527 + */
 524  528  int
 525  529  aggr_port_promisc(aggr_port_t *port, boolean_t on)
 526  530  {
 527  531          int rc;
 528  532  
 529  533          ASSERT(MAC_PERIM_HELD(port->lp_mh));
 530  534  
 531  535          if (on == port->lp_promisc_on)
 532      -                /* already in desired promiscous mode */
 533  536                  return (0);
 534  537  
 535      -        if (on) {
 536      -                mac_rx_clear(port->lp_mch);
      538 +        rc = mac_set_promisc(port->lp_mh, on);
 537  539  
 538      -                /*
 539      -                 * We use the promisc callback because without hardware
 540      -                 * rings, we deliver through flows that will cause duplicate
 541      -                 * delivery of packets when we've flipped into this mode
 542      -                 * to compensate for the lack of hardware MAC matching
 543      -                 */
 544      -                rc = mac_promisc_add(port->lp_mch, MAC_CLIENT_PROMISC_ALL,
 545      -                    aggr_recv_promisc_cb, port, &port->lp_mphp,
 546      -                    MAC_PROMISC_FLAGS_NO_TX_LOOP);
 547      -                if (rc != 0) {
 548      -                        mac_rx_set(port->lp_mch, aggr_recv_cb, port);
 549      -                        return (rc);
 550      -                }
 551      -        } else {
 552      -                mac_promisc_remove(port->lp_mphp);
 553      -                port->lp_mphp = NULL;
 554      -                mac_rx_set(port->lp_mch, aggr_recv_cb, port);
 555      -        }
      540 +        if (rc == 0)
      541 +                port->lp_promisc_on = on;
 556  542  
 557      -        port->lp_promisc_on = on;
 558      -
 559      -        return (0);
      543 +        return (rc);
 560  544  }
 561  545  
 562  546  /*
 563  547   * Set the MAC address of a port.
 564  548   */
 565  549  int
 566  550  aggr_port_unicst(aggr_port_t *port)
 567  551  {
 568  552          aggr_grp_t              *grp = port->lp_grp;
 569  553  
↓ open down ↓ 19 lines elided ↑ open up ↑
 589  573          }
 590  574  }
 591  575  
 592  576  uint64_t
 593  577  aggr_port_stat(aggr_port_t *port, uint_t stat)
 594  578  {
 595  579          return (mac_stat_get(port->lp_mh, stat));
 596  580  }
 597  581  
 598  582  /*
 599      - * Add a non-primary unicast address to the underlying port. If the port
 600      - * supports HW Rx group, try to add the address into the HW Rx group of
 601      - * the port first. If that fails, or if the port does not support HW Rx
 602      - * group, enable the port's promiscous mode.
      583 + * Add a non-primary unicast address to the underlying port. If the
      584 + * port supports HW Rx groups, then try to add the address filter to
      585 + * the HW group first. If that fails, or if the port does not support
      586 + * RINGS capab, then enable the port's promiscous mode.
 603  587   */
 604  588  int
 605      -aggr_port_addmac(aggr_port_t *port, const uint8_t *mac_addr)
      589 +aggr_port_addmac(aggr_port_t *port, uint_t idx, const uint8_t *mac_addr)
 606  590  {
 607  591          aggr_unicst_addr_t      *addr, **pprev;
 608  592          mac_perim_handle_t      pmph;
 609  593          int                     err;
 610  594  
 611  595          ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh));
      596 +        ASSERT3U(idx, <, MAX_GROUPS_PER_PORT);
 612  597          mac_perim_enter_by_mh(port->lp_mh, &pmph);
 613  598  
 614  599          /*
 615      -         * If the underlying port support HW Rx group, add the mac to its
 616      -         * RX group directly.
      600 +         * If the port doesn't have a HW group to back the aggr's
      601 +         * pseudo group, then try using the port's default group and
      602 +         * let the aggr SW classify its traffic. This scenario happens
      603 +         * when mixing ports with a different number of HW groups.
 617  604           */
 618      -        if ((port->lp_hwgh != NULL) &&
 619      -            ((mac_hwgroup_addmac(port->lp_hwgh, mac_addr)) == 0)) {
      605 +        if (port->lp_hwghs[idx] == NULL)
      606 +                idx = 0;
      607 +
      608 +        /*
      609 +         * If there is an underlying HW Rx group, then try adding this
      610 +         * unicast address to it.
      611 +         */
      612 +        if ((port->lp_hwghs[idx] != NULL) &&
      613 +            ((mac_hwgroup_addmac(port->lp_hwghs[idx], mac_addr)) == 0)) {
 620  614                  mac_perim_exit(pmph);
 621  615                  return (0);
 622  616          }
 623  617  
 624  618          /*
 625      -         * If that fails, or if the port does not support HW Rx group, enable
 626      -         * the port's promiscous mode. (Note that we turn on the promiscous
 627      -         * mode only if the port is already started.
      619 +         * If the port doesn't have HW groups, or we failed to add the
      620 +         * HW filter, then enable the port's promiscuous mode. We
      621 +         * enable promiscuous mode only if the port is already started.
 628  622           */
 629  623          if (port->lp_started &&
 630  624              ((err = aggr_port_promisc(port, B_TRUE)) != 0)) {
 631  625                  mac_perim_exit(pmph);
 632  626                  return (err);
 633  627          }
 634  628  
 635  629          /*
 636  630           * Walk through the unicast addresses that requires promiscous mode
 637  631           * enabled on this port, and add this address to the end of the list.
↓ open down ↓ 11 lines elided ↑ open up ↑
 649  643          return (0);
 650  644  }
 651  645  
 652  646  /*
 653  647   * Remove a non-primary unicast address from the underlying port. This address
 654  648   * must has been added by aggr_port_addmac(). As a result, we probably need to
 655  649   * remove the address from the port's HW Rx group, or to disable the port's
 656  650   * promiscous mode.
 657  651   */
 658  652  void
 659      -aggr_port_remmac(aggr_port_t *port, const uint8_t *mac_addr)
      653 +aggr_port_remmac(aggr_port_t *port, uint_t idx, const uint8_t *mac_addr)
 660  654  {
 661  655          aggr_grp_t              *grp = port->lp_grp;
 662  656          aggr_unicst_addr_t      *addr, **pprev;
 663  657          mac_perim_handle_t      pmph;
 664  658  
 665  659          ASSERT(MAC_PERIM_HELD(grp->lg_mh));
      660 +        ASSERT3U(idx, <, MAX_GROUPS_PER_PORT);
 666  661          mac_perim_enter_by_mh(port->lp_mh, &pmph);
 667  662  
 668  663          /*
 669  664           * See whether this address is in the list of addresses that requires
 670  665           * the port being promiscous mode.
 671  666           */
 672  667          pprev = &port->lp_prom_addr;
 673  668          while ((addr = *pprev) != NULL) {
 674  669                  if (bcmp(mac_addr, addr->aua_addr, ETHERADDRL) == 0)
 675  670                          break;
 676  671                  pprev = &addr->aua_next;
 677  672          }
      673 +
 678  674          if (addr != NULL) {
 679  675                  /*
 680  676                   * This unicast address put the port into the promiscous mode,
 681  677                   * delete this address from the lp_prom_addr list. If this is
 682  678                   * the last address in that list, disable the promiscous mode
 683  679                   * if the aggregation is not in promiscous mode.
 684  680                   */
 685  681                  *pprev = addr->aua_next;
 686  682                  kmem_free(addr, sizeof (aggr_unicst_addr_t));
 687  683                  if (port->lp_prom_addr == NULL && !grp->lg_promisc)
 688  684                          (void) aggr_port_promisc(port, B_FALSE);
 689  685          } else {
 690      -                ASSERT(port->lp_hwgh != NULL);
 691      -                (void) mac_hwgroup_remmac(port->lp_hwgh, mac_addr);
      686 +                /* See comment in aggr_port_addmac(). */
      687 +                if (port->lp_hwghs[idx] == NULL)
      688 +                        idx = 0;
      689 +
      690 +                ASSERT3P(port->lp_hwghs[idx], !=, NULL);
      691 +                (void) mac_hwgroup_remmac(port->lp_hwghs[idx], mac_addr);
 692  692          }
      693 +
 693  694          mac_perim_exit(pmph);
 694  695  }
 695  696  
 696  697  int
 697      -aggr_port_addvlan(aggr_port_t *port, uint16_t vid)
      698 +aggr_port_addvlan(aggr_port_t *port, uint_t idx, uint16_t vid)
 698  699  {
 699  700          mac_perim_handle_t      pmph;
 700  701          int                     err;
 701  702  
 702  703          ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh));
      704 +        ASSERT3U(idx, <, MAX_GROUPS_PER_PORT);
 703  705          mac_perim_enter_by_mh(port->lp_mh, &pmph);
 704  706  
      707 +        /* See comment in aggr_port_addmac(). */
      708 +        if (port->lp_hwghs[idx] == NULL)
      709 +                idx = 0;
      710 +
 705  711          /*
 706  712           * Add the VLAN filter to the HW group if the port has a HW
 707  713           * group. If the port doesn't have a HW group, then it will
 708  714           * implicitly allow tagged traffic to pass and there is
 709  715           * nothing to do.
 710  716           */
 711      -        if (port->lp_hwgh == NULL)
 712      -                return (0);
      717 +        if (port->lp_hwghs[idx] == NULL)
      718 +                err = 0;
      719 +        else
      720 +                err = mac_hwgroup_addvlan(port->lp_hwghs[idx], vid);
 713  721  
 714      -        err = mac_hwgroup_addvlan(port->lp_hwgh, vid);
 715  722          mac_perim_exit(pmph);
 716  723          return (err);
 717  724  }
 718  725  
 719  726  int
 720      -aggr_port_remvlan(aggr_port_t *port, uint16_t vid)
      727 +aggr_port_remvlan(aggr_port_t *port, uint_t idx, uint16_t vid)
 721  728  {
 722  729          mac_perim_handle_t      pmph;
 723  730          int                     err;
 724  731  
 725  732          ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh));
      733 +        ASSERT3U(idx, <, MAX_GROUPS_PER_PORT);
 726  734          mac_perim_enter_by_mh(port->lp_mh, &pmph);
 727  735  
 728      -        if (port->lp_hwgh == NULL)
 729      -                return (0);
      736 +        /* See comment in aggr_port_addmac(). */
      737 +        if (port->lp_hwghs[idx] == NULL)
      738 +                idx = 0;
 730  739  
 731      -        err = mac_hwgroup_remvlan(port->lp_hwgh, vid);
      740 +        if (port->lp_hwghs[idx] == NULL)
      741 +                err = 0;
      742 +        else
      743 +                err = mac_hwgroup_remvlan(port->lp_hwghs[idx], vid);
      744 +
 732  745          mac_perim_exit(pmph);
 733  746          return (err);
 734  747  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX