xref: /illumos-gate/usr/src/uts/common/io/aggr/aggr_recv.c (revision bdfc6d18da790deeec2e0eb09c625902defe2498)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * IEEE 802.3ad Link Aggregation - Receive
31  *
32  * Implements the collector function.
33  * Manages the RX resources exposed by a link aggregation group.
34  */
35 
36 #include <sys/sysmacros.h>
37 #include <sys/ddi.h>
38 #include <sys/sunddi.h>
39 #include <sys/strsun.h>
40 #include <sys/strsubr.h>
41 #include <sys/byteorder.h>
42 #include <sys/aggr.h>
43 #include <sys/aggr_impl.h>
44 
45 static void
46 aggr_recv_lacp(aggr_port_t *port, mblk_t *mp)
47 {
48 	aggr_grp_t *grp = port->lp_grp;
49 
50 	/* in promiscous mode, send copy of packet up */
51 	if (grp->lg_promisc) {
52 		mblk_t *nmp = copymsg(mp);
53 
54 		if (nmp != NULL)
55 			mac_rx(&grp->lg_mac, NULL, nmp);
56 	}
57 
58 	aggr_lacp_rx(port, mp);
59 }
60 
61 /*
62  * Callback function invoked by MAC service module when packets are
63  * made available by a MAC port.
64  */
65 void
66 aggr_recv_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp)
67 {
68 	aggr_port_t *port = (aggr_port_t *)arg;
69 	aggr_grp_t *grp = port->lp_grp;
70 
71 	if (grp->lg_lacp_mode == AGGR_LACP_OFF) {
72 		mac_rx(&grp->lg_mac, mrh, mp);
73 	} else {
74 		mblk_t *cmp, *last, *head;
75 		struct ether_header *ehp;
76 		uint16_t sap;
77 
78 		/* filter out slow protocol packets (LACP & Marker) */
79 		last = NULL;
80 		head = cmp = mp;
81 		while (cmp != NULL) {
82 			if (MBLKL(cmp) < sizeof (struct ether_header)) {
83 				/* packet too short */
84 				if (head == cmp) {
85 					/* no packets accumulated */
86 					head = cmp->b_next;
87 					cmp->b_next = NULL;
88 					freemsg(cmp);
89 					cmp = head;
90 				} else {
91 					/* send up accumulated packets */
92 					last->b_next = NULL;
93 					if (port->lp_collector_enabled) {
94 						mac_rx(&grp->lg_mac, mrh,
95 						    head);
96 					} else {
97 						freemsg(head);
98 					}
99 					head = cmp->b_next;
100 					cmp->b_next = NULL;
101 					freemsg(cmp);
102 					cmp = head;
103 					last = NULL;
104 				}
105 				continue;
106 			}
107 			ehp = (struct ether_header *)cmp->b_rptr;
108 
109 			sap = ntohs(ehp->ether_type);
110 			if (sap == ETHERTYPE_SLOW) {
111 				/*
112 				 * LACP or Marker packet. Send up pending
113 				 * chain, and send LACP/Marker packet
114 				 * to LACP subsystem.
115 				 */
116 				if (head == cmp) {
117 					/* first packet of chain */
118 					ASSERT(last == NULL);
119 					head = cmp->b_next;
120 					cmp->b_next = NULL;
121 					aggr_recv_lacp(port, cmp);
122 					cmp = head;
123 				} else {
124 					/* previously accumulated packets */
125 					ASSERT(last != NULL);
126 					/* send up non-LACP packets */
127 					last->b_next = NULL;
128 					if (port->lp_collector_enabled) {
129 						mac_rx(&grp->lg_mac, mrh,
130 						    head);
131 					} else {
132 						freemsg(head);
133 					}
134 					/* unlink and pass up LACP packets */
135 					head = cmp->b_next;
136 					cmp->b_next = NULL;
137 					aggr_recv_lacp(port, cmp);
138 					cmp = head;
139 					last = NULL;
140 				}
141 			} else {
142 				last = cmp;
143 				cmp = cmp->b_next;
144 			}
145 		}
146 		if (head != NULL) {
147 			if (port->lp_collector_enabled)
148 				mac_rx(&grp->lg_mac, mrh, head);
149 			else
150 				freemsg(head);
151 		}
152 	}
153 }
154