xref: /illumos-gate/usr/src/uts/common/io/aggr/aggr_recv.c (revision 7257d1b4)
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  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
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_recv_lacp(aggr_port_t *port, mblk_t *mp)
46 {
47 	aggr_grp_t *grp = port->lp_grp;
48 
49 	/* in promiscuous mode, send copy of packet up */
50 	if (grp->lg_promisc) {
51 		mblk_t *nmp = copymsg(mp);
52 
53 		if (nmp != NULL)
54 			mac_rx(grp->lg_mh, NULL, nmp);
55 	}
56 
57 	aggr_lacp_rx(port, mp);
58 }
59 
60 /*
61  * Callback function invoked by MAC service module when packets are
62  * made available by a MAC port.
63  */
64 void
65 aggr_recv_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp)
66 {
67 	aggr_port_t *port = (aggr_port_t *)arg;
68 	aggr_grp_t *grp = port->lp_grp;
69 
70 	/*
71 	 * If this message is looped back from the legacy devices, drop
72 	 * it as the Nemo framework will be responsible for looping it
73 	 * back by the mac_txloop() function.
74 	 */
75 	if (mp->b_flag & MSGNOLOOP) {
76 		ASSERT(mp->b_next == NULL);
77 		freemsg(mp);
78 		return;
79 	}
80 
81 	if (grp->lg_lacp_mode == AGGR_LACP_OFF) {
82 		mac_rx(grp->lg_mh, mrh, mp);
83 	} else {
84 		mblk_t *cmp, *last, *head;
85 		struct ether_header *ehp;
86 		uint16_t sap;
87 
88 		/* filter out slow protocol packets (LACP & Marker) */
89 		last = NULL;
90 		head = cmp = mp;
91 		while (cmp != NULL) {
92 			if (MBLKL(cmp) < sizeof (struct ether_header)) {
93 				/* packet too short */
94 				if (head == cmp) {
95 					/* no packets accumulated */
96 					head = cmp->b_next;
97 					cmp->b_next = NULL;
98 					freemsg(cmp);
99 					cmp = head;
100 				} else {
101 					/* send up accumulated packets */
102 					last->b_next = NULL;
103 					if (port->lp_collector_enabled)
104 						mac_rx(grp->lg_mh, mrh, head);
105 					else
106 						freemsgchain(head);
107 					head = cmp->b_next;
108 					cmp->b_next = NULL;
109 					freemsg(cmp);
110 					cmp = head;
111 					last = NULL;
112 				}
113 				continue;
114 			}
115 			ehp = (struct ether_header *)cmp->b_rptr;
116 
117 			sap = ntohs(ehp->ether_type);
118 			if (sap == ETHERTYPE_SLOW) {
119 				/*
120 				 * LACP or Marker packet. Send up pending
121 				 * chain, and send LACP/Marker packet
122 				 * to LACP subsystem.
123 				 */
124 				if (head == cmp) {
125 					/* first packet of chain */
126 					ASSERT(last == NULL);
127 					head = cmp->b_next;
128 					cmp->b_next = NULL;
129 					aggr_recv_lacp(port, cmp);
130 					cmp = head;
131 				} else {
132 					/* previously accumulated packets */
133 					ASSERT(last != NULL);
134 					/* send up non-LACP packets */
135 					last->b_next = NULL;
136 					if (port->lp_collector_enabled)
137 						mac_rx(grp->lg_mh, mrh, head);
138 					else
139 						freemsgchain(head);
140 					/* unlink and pass up LACP packets */
141 					head = cmp->b_next;
142 					cmp->b_next = NULL;
143 					aggr_recv_lacp(port, cmp);
144 					cmp = head;
145 					last = NULL;
146 				}
147 			} else {
148 				last = cmp;
149 				cmp = cmp->b_next;
150 			}
151 		}
152 		if (head != NULL) {
153 			if (port->lp_collector_enabled)
154 				mac_rx(grp->lg_mh, mrh, head);
155 			else
156 				freemsgchain(head);
157 		}
158 	}
159 }
160