xref: /illumos-gate/usr/src/uts/common/io/aggr/aggr_recv.c (revision 09fbbb7d1b5a956a9b81304070dcff318a4a158e)
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 }
173