xref: /illumos-gate/usr/src/uts/common/io/aggr/aggr_recv.c (revision 8c067cfd3aea0c49a166f9fb38114b56a9160ac6)
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 /*
27  * IEEE 802.3ad Link Aggregation - Receive
28  *
29  * Implements the collector function.
30  * Manages the RX resources exposed by a link aggregation group.
31  */
32 
33 #include <sys/sysmacros.h>
34 #include <sys/ddi.h>
35 #include <sys/sunddi.h>
36 #include <sys/strsun.h>
37 #include <sys/strsubr.h>
38 #include <sys/byteorder.h>
39 #include <sys/aggr.h>
40 #include <sys/aggr_impl.h>
41 
42 static void
43 aggr_mac_rx(mac_handle_t lg_mh, mac_resource_handle_t mrh, mblk_t *mp)
44 {
45 	if (mrh == NULL) {
46 		mac_rx(lg_mh, mrh, mp);
47 	} else {
48 		aggr_pseudo_rx_ring_t	*ring = (aggr_pseudo_rx_ring_t *)mrh;
49 		mac_rx_ring(lg_mh, ring->arr_rh, mp, ring->arr_gen);
50 	}
51 }
52 
53 void
54 aggr_recv_lacp(aggr_port_t *port, mac_resource_handle_t mrh, mblk_t *mp)
55 {
56 	aggr_grp_t *grp = port->lp_grp;
57 
58 	/* in promiscuous mode, send copy of packet up */
59 	if (grp->lg_promisc) {
60 		mblk_t *nmp = copymsg(mp);
61 
62 		if (nmp != NULL)
63 			aggr_mac_rx(grp->lg_mh, mrh, nmp);
64 	}
65 
66 	aggr_lacp_rx_enqueue(port, mp);
67 }
68 
69 /*
70  * Callback function invoked by MAC service module when packets are
71  * made available by a MAC port.
72  */
73 /* ARGSUSED */
74 void
75 aggr_recv_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
76     boolean_t loopback)
77 {
78 	aggr_port_t *port = (aggr_port_t *)arg;
79 	aggr_grp_t *grp = port->lp_grp;
80 
81 	if (grp->lg_lacp_mode == AGGR_LACP_OFF) {
82 		aggr_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 						aggr_mac_rx(grp->lg_mh, mrh,
105 						    head);
106 					} else {
107 						freemsgchain(head);
108 					}
109 					head = cmp->b_next;
110 					cmp->b_next = NULL;
111 					freemsg(cmp);
112 					cmp = head;
113 					last = NULL;
114 				}
115 				continue;
116 			}
117 			ehp = (struct ether_header *)cmp->b_rptr;
118 
119 			sap = ntohs(ehp->ether_type);
120 			if (sap == ETHERTYPE_SLOW) {
121 				/*
122 				 * LACP or Marker packet. Send up pending
123 				 * chain, and send LACP/Marker packet
124 				 * to LACP subsystem.
125 				 */
126 				if (head == cmp) {
127 					/* first packet of chain */
128 					ASSERT(last == NULL);
129 					head = cmp->b_next;
130 					cmp->b_next = NULL;
131 					aggr_recv_lacp(port, mrh, cmp);
132 					cmp = head;
133 				} else {
134 					/* previously accumulated packets */
135 					ASSERT(last != NULL);
136 					/* send up non-LACP packets */
137 					last->b_next = NULL;
138 					if (port->lp_collector_enabled) {
139 						aggr_mac_rx(grp->lg_mh, mrh,
140 						    head);
141 					} else {
142 						freemsgchain(head);
143 					}
144 					/* unlink and pass up LACP packets */
145 					head = cmp->b_next;
146 					cmp->b_next = NULL;
147 					aggr_recv_lacp(port, mrh, cmp);
148 					cmp = head;
149 					last = NULL;
150 				}
151 			} else {
152 				last = cmp;
153 				cmp = cmp->b_next;
154 			}
155 		}
156 		if (head != NULL) {
157 			if (port->lp_collector_enabled)
158 				aggr_mac_rx(grp->lg_mh, mrh, head);
159 			else
160 				freemsgchain(head);
161 		}
162 	}
163 }
164