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
aggr_mac_rx(mac_handle_t lg_mh,mac_resource_handle_t mrh,mblk_t * mp)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
aggr_recv_lacp(aggr_port_t * port,mac_resource_handle_t mrh,mblk_t * mp)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
aggr_recv_path_cb(void * arg,mac_resource_handle_t mrh,mblk_t * mp,boolean_t loopback)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
aggr_recv_cb(void * arg,mac_resource_handle_t mrh,mblk_t * mp,boolean_t loopback)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 }
173