xref: /illumos-gate/usr/src/uts/common/io/aggr/aggr_recv.c (revision 0173c38a73f34277e0c97a19fedfd25d81ba8380)
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 2006 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 promiscous 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 	if (grp->lg_lacp_mode == AGGR_LACP_OFF) {
71 		mac_rx(grp->lg_mh, mrh, mp);
72 	} else {
73 		mblk_t *cmp, *last, *head;
74 		struct ether_header *ehp;
75 		uint16_t sap;
76 
77 		/* filter out slow protocol packets (LACP & Marker) */
78 		last = NULL;
79 		head = cmp = mp;
80 		while (cmp != NULL) {
81 			if (MBLKL(cmp) < sizeof (struct ether_header)) {
82 				/* packet too short */
83 				if (head == cmp) {
84 					/* no packets accumulated */
85 					head = cmp->b_next;
86 					cmp->b_next = NULL;
87 					freemsg(cmp);
88 					cmp = head;
89 				} else {
90 					/* send up accumulated packets */
91 					last->b_next = NULL;
92 					if (port->lp_collector_enabled)
93 						mac_rx(grp->lg_mh, mrh, head);
94 					else
95 						freemsgchain(head);
96 					head = cmp->b_next;
97 					cmp->b_next = NULL;
98 					freemsg(cmp);
99 					cmp = head;
100 					last = NULL;
101 				}
102 				continue;
103 			}
104 			ehp = (struct ether_header *)cmp->b_rptr;
105 
106 			sap = ntohs(ehp->ether_type);
107 			if (sap == ETHERTYPE_SLOW) {
108 				/*
109 				 * LACP or Marker packet. Send up pending
110 				 * chain, and send LACP/Marker packet
111 				 * to LACP subsystem.
112 				 */
113 				if (head == cmp) {
114 					/* first packet of chain */
115 					ASSERT(last == NULL);
116 					head = cmp->b_next;
117 					cmp->b_next = NULL;
118 					aggr_recv_lacp(port, cmp);
119 					cmp = head;
120 				} else {
121 					/* previously accumulated packets */
122 					ASSERT(last != NULL);
123 					/* send up non-LACP packets */
124 					last->b_next = NULL;
125 					if (port->lp_collector_enabled)
126 						mac_rx(grp->lg_mh, mrh, head);
127 					else
128 						freemsgchain(head);
129 					/* unlink and pass up LACP packets */
130 					head = cmp->b_next;
131 					cmp->b_next = NULL;
132 					aggr_recv_lacp(port, cmp);
133 					cmp = head;
134 					last = NULL;
135 				}
136 			} else {
137 				last = cmp;
138 				cmp = cmp->b_next;
139 			}
140 		}
141 		if (head != NULL) {
142 			if (port->lp_collector_enabled)
143 				mac_rx(grp->lg_mh, mrh, head);
144 			else
145 				freemsgchain(head);
146 		}
147 	}
148 }
149