xref: /illumos-gate/usr/src/uts/common/io/aggr/aggr_recv.c (revision 445f2479fe3d7435daab18bf2cdc310b86cd6738)
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_mac, 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_mac, 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_mac, mrh,
94 						    head);
95 					} else {
96 						freemsgchain(head);
97 					}
98 					head = cmp->b_next;
99 					cmp->b_next = NULL;
100 					freemsg(cmp);
101 					cmp = head;
102 					last = NULL;
103 				}
104 				continue;
105 			}
106 			ehp = (struct ether_header *)cmp->b_rptr;
107 
108 			sap = ntohs(ehp->ether_type);
109 			if (sap == ETHERTYPE_SLOW) {
110 				/*
111 				 * LACP or Marker packet. Send up pending
112 				 * chain, and send LACP/Marker packet
113 				 * to LACP subsystem.
114 				 */
115 				if (head == cmp) {
116 					/* first packet of chain */
117 					ASSERT(last == NULL);
118 					head = cmp->b_next;
119 					cmp->b_next = NULL;
120 					aggr_recv_lacp(port, cmp);
121 					cmp = head;
122 				} else {
123 					/* previously accumulated packets */
124 					ASSERT(last != NULL);
125 					/* send up non-LACP packets */
126 					last->b_next = NULL;
127 					if (port->lp_collector_enabled) {
128 						mac_rx(&grp->lg_mac, mrh,
129 						    head);
130 					} else {
131 						freemsgchain(head);
132 					}
133 					/* unlink and pass up LACP packets */
134 					head = cmp->b_next;
135 					cmp->b_next = NULL;
136 					aggr_recv_lacp(port, cmp);
137 					cmp = head;
138 					last = NULL;
139 				}
140 			} else {
141 				last = cmp;
142 				cmp = cmp->b_next;
143 			}
144 		}
145 		if (head != NULL) {
146 			if (port->lp_collector_enabled)
147 				mac_rx(&grp->lg_mac, mrh, head);
148 			else
149 				freemsgchain(head);
150 		}
151 	}
152 }
153