1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright 2012 OmniTI Computer Consulting, Inc All rights reserved. 25 * Copyright 2018 Joyent, Inc. 26 */ 27 28 /* 29 * IEEE 802.3ad Link Aggregation - Receive 30 * 31 * Implements the collector function. 32 * Manages the RX resources exposed by a link aggregation group. 33 */ 34 35 #include <sys/sysmacros.h> 36 #include <sys/ddi.h> 37 #include <sys/sunddi.h> 38 #include <sys/strsun.h> 39 #include <sys/strsubr.h> 40 #include <sys/byteorder.h> 41 #include <sys/aggr.h> 42 #include <sys/aggr_impl.h> 43 44 static void 45 aggr_mac_rx(mac_handle_t lg_mh, mac_resource_handle_t mrh, mblk_t *mp) 46 { 47 if (mrh == NULL) { 48 mac_rx(lg_mh, mrh, mp); 49 } else { 50 aggr_pseudo_rx_ring_t *ring = (aggr_pseudo_rx_ring_t *)mrh; 51 mac_rx_ring(lg_mh, ring->arr_rh, mp, ring->arr_gen); 52 } 53 } 54 55 void 56 aggr_recv_lacp(aggr_port_t *port, mac_resource_handle_t mrh, mblk_t *mp) 57 { 58 aggr_grp_t *grp = port->lp_grp; 59 60 /* In promiscuous mode, pass copy of packet up. */ 61 if (grp->lg_promisc) { 62 mblk_t *nmp = copymsg(mp); 63 64 if (nmp != NULL) 65 aggr_mac_rx(grp->lg_mh, mrh, nmp); 66 } 67 68 aggr_lacp_rx_enqueue(port, mp); 69 } 70 71 /* 72 * Callback function invoked by MAC service module when packets are 73 * made available by a MAC port, both in promisc_on mode and not. 74 */ 75 /* ARGSUSED */ 76 static void 77 aggr_recv_path_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp, 78 boolean_t loopback) 79 { 80 aggr_port_t *port = (aggr_port_t *)arg; 81 aggr_grp_t *grp = port->lp_grp; 82 83 if (grp->lg_lacp_mode == AGGR_LACP_OFF) { 84 aggr_mac_rx(grp->lg_mh, mrh, mp); 85 } else { 86 mblk_t *cmp, *last, *head; 87 struct ether_header *ehp; 88 uint16_t sap; 89 90 /* filter out slow protocol packets (LACP & Marker) */ 91 last = NULL; 92 head = cmp = mp; 93 while (cmp != NULL) { 94 if (MBLKL(cmp) < sizeof (struct ether_header)) { 95 /* packet too short */ 96 if (head == cmp) { 97 /* no packets accumulated */ 98 head = cmp->b_next; 99 cmp->b_next = NULL; 100 freemsg(cmp); 101 cmp = head; 102 } else { 103 /* send up accumulated packets */ 104 last->b_next = NULL; 105 if (port->lp_collector_enabled) { 106 aggr_mac_rx(grp->lg_mh, mrh, 107 head); 108 } else { 109 freemsgchain(head); 110 } 111 head = cmp->b_next; 112 cmp->b_next = NULL; 113 freemsg(cmp); 114 cmp = head; 115 last = NULL; 116 } 117 continue; 118 } 119 ehp = (struct ether_header *)cmp->b_rptr; 120 121 sap = ntohs(ehp->ether_type); 122 if (sap == ETHERTYPE_SLOW) { 123 /* 124 * LACP or Marker packet. Send up pending 125 * chain, and send LACP/Marker packet 126 * to LACP subsystem. 127 */ 128 if (head == cmp) { 129 /* first packet of chain */ 130 ASSERT(last == NULL); 131 head = cmp->b_next; 132 cmp->b_next = NULL; 133 aggr_recv_lacp(port, mrh, cmp); 134 cmp = head; 135 } else { 136 /* previously accumulated packets */ 137 ASSERT(last != NULL); 138 /* send up non-LACP packets */ 139 last->b_next = NULL; 140 if (port->lp_collector_enabled) { 141 aggr_mac_rx(grp->lg_mh, mrh, 142 head); 143 } else { 144 freemsgchain(head); 145 } 146 /* unlink and pass up LACP packets */ 147 head = cmp->b_next; 148 cmp->b_next = NULL; 149 aggr_recv_lacp(port, mrh, cmp); 150 cmp = head; 151 last = NULL; 152 } 153 } else { 154 last = cmp; 155 cmp = cmp->b_next; 156 } 157 } 158 if (head != NULL) { 159 if (port->lp_collector_enabled) 160 aggr_mac_rx(grp->lg_mh, mrh, head); 161 else 162 freemsgchain(head); 163 } 164 } 165 } 166 167 void 168 aggr_recv_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp, 169 boolean_t loopback) 170 { 171 aggr_recv_path_cb(arg, mrh, mp, loopback); 172 }