xref: /illumos-gate/usr/src/uts/common/io/aggr/aggr_recv.c (revision 45948e49)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5f12af565Snd  * Common Development and Distribution License (the "License").
6f12af565Snd  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22d62bc4baSyz  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
2484de666eSRyan Zezeski  * Copyright 2012 OmniTI Computer Consulting, Inc  All rights reserved.
25*45948e49SRyan Zezeski  * Copyright 2018 Joyent, Inc.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * IEEE 802.3ad Link Aggregation - Receive
307c478bd9Sstevel@tonic-gate  *
317c478bd9Sstevel@tonic-gate  * Implements the collector function.
327c478bd9Sstevel@tonic-gate  * Manages the RX resources exposed by a link aggregation group.
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
367c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
377c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
387c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
397c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
407c478bd9Sstevel@tonic-gate #include <sys/byteorder.h>
417c478bd9Sstevel@tonic-gate #include <sys/aggr.h>
427c478bd9Sstevel@tonic-gate #include <sys/aggr_impl.h>
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate static void
aggr_mac_rx(mac_handle_t lg_mh,mac_resource_handle_t mrh,mblk_t * mp)45da14cebeSEric Cheng aggr_mac_rx(mac_handle_t lg_mh, mac_resource_handle_t mrh, mblk_t *mp)
46da14cebeSEric Cheng {
47da14cebeSEric Cheng 	if (mrh == NULL) {
48da14cebeSEric Cheng 		mac_rx(lg_mh, mrh, mp);
49da14cebeSEric Cheng 	} else {
50da14cebeSEric Cheng 		aggr_pseudo_rx_ring_t	*ring = (aggr_pseudo_rx_ring_t *)mrh;
51da14cebeSEric Cheng 		mac_rx_ring(lg_mh, ring->arr_rh, mp, ring->arr_gen);
52da14cebeSEric Cheng 	}
53da14cebeSEric Cheng }
54da14cebeSEric Cheng 
55da14cebeSEric Cheng void
aggr_recv_lacp(aggr_port_t * port,mac_resource_handle_t mrh,mblk_t * mp)56da14cebeSEric Cheng aggr_recv_lacp(aggr_port_t *port, mac_resource_handle_t mrh, mblk_t *mp)
577c478bd9Sstevel@tonic-gate {
587c478bd9Sstevel@tonic-gate 	aggr_grp_t *grp = port->lp_grp;
597c478bd9Sstevel@tonic-gate 
60*45948e49SRyan Zezeski 	/* In promiscuous mode, pass copy of packet up. */
617c478bd9Sstevel@tonic-gate 	if (grp->lg_promisc) {
627c478bd9Sstevel@tonic-gate 		mblk_t *nmp = copymsg(mp);
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate 		if (nmp != NULL)
65da14cebeSEric Cheng 			aggr_mac_rx(grp->lg_mh, mrh, nmp);
667c478bd9Sstevel@tonic-gate 	}
677c478bd9Sstevel@tonic-gate 
68da14cebeSEric Cheng 	aggr_lacp_rx_enqueue(port, mp);
697c478bd9Sstevel@tonic-gate }
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate /*
727c478bd9Sstevel@tonic-gate  * Callback function invoked by MAC service module when packets are
7384de666eSRyan Zezeski  * made available by a MAC port, both in promisc_on mode and not.
747c478bd9Sstevel@tonic-gate  */
75da14cebeSEric Cheng /* ARGSUSED */
7684de666eSRyan Zezeski static void
aggr_recv_path_cb(void * arg,mac_resource_handle_t mrh,mblk_t * mp,boolean_t loopback)7784de666eSRyan Zezeski aggr_recv_path_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
78*45948e49SRyan Zezeski     boolean_t loopback)
797c478bd9Sstevel@tonic-gate {
807c478bd9Sstevel@tonic-gate 	aggr_port_t *port = (aggr_port_t *)arg;
817c478bd9Sstevel@tonic-gate 	aggr_grp_t *grp = port->lp_grp;
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 	if (grp->lg_lacp_mode == AGGR_LACP_OFF) {
84da14cebeSEric Cheng 		aggr_mac_rx(grp->lg_mh, mrh, mp);
857c478bd9Sstevel@tonic-gate 	} else {
867c478bd9Sstevel@tonic-gate 		mblk_t *cmp, *last, *head;
877c478bd9Sstevel@tonic-gate 		struct ether_header *ehp;
887c478bd9Sstevel@tonic-gate 		uint16_t sap;
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 		/* filter out slow protocol packets (LACP & Marker) */
917c478bd9Sstevel@tonic-gate 		last = NULL;
927c478bd9Sstevel@tonic-gate 		head = cmp = mp;
937c478bd9Sstevel@tonic-gate 		while (cmp != NULL) {
947c478bd9Sstevel@tonic-gate 			if (MBLKL(cmp) < sizeof (struct ether_header)) {
957c478bd9Sstevel@tonic-gate 				/* packet too short */
967c478bd9Sstevel@tonic-gate 				if (head == cmp) {
977c478bd9Sstevel@tonic-gate 					/* no packets accumulated */
987c478bd9Sstevel@tonic-gate 					head = cmp->b_next;
997c478bd9Sstevel@tonic-gate 					cmp->b_next = NULL;
1007c478bd9Sstevel@tonic-gate 					freemsg(cmp);
1017c478bd9Sstevel@tonic-gate 					cmp = head;
1027c478bd9Sstevel@tonic-gate 				} else {
1037c478bd9Sstevel@tonic-gate 					/* send up accumulated packets */
1047c478bd9Sstevel@tonic-gate 					last->b_next = NULL;
105da14cebeSEric Cheng 					if (port->lp_collector_enabled) {
106da14cebeSEric Cheng 						aggr_mac_rx(grp->lg_mh, mrh,
107da14cebeSEric Cheng 						    head);
108da14cebeSEric Cheng 					} else {
109f12af565Snd 						freemsgchain(head);
110da14cebeSEric Cheng 					}
1117c478bd9Sstevel@tonic-gate 					head = cmp->b_next;
1127c478bd9Sstevel@tonic-gate 					cmp->b_next = NULL;
1137c478bd9Sstevel@tonic-gate 					freemsg(cmp);
1147c478bd9Sstevel@tonic-gate 					cmp = head;
1157c478bd9Sstevel@tonic-gate 					last = NULL;
1167c478bd9Sstevel@tonic-gate 				}
1177c478bd9Sstevel@tonic-gate 				continue;
1187c478bd9Sstevel@tonic-gate 			}
1197c478bd9Sstevel@tonic-gate 			ehp = (struct ether_header *)cmp->b_rptr;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 			sap = ntohs(ehp->ether_type);
1227c478bd9Sstevel@tonic-gate 			if (sap == ETHERTYPE_SLOW) {
1237c478bd9Sstevel@tonic-gate 				/*
1247c478bd9Sstevel@tonic-gate 				 * LACP or Marker packet. Send up pending
1257c478bd9Sstevel@tonic-gate 				 * chain, and send LACP/Marker packet
1267c478bd9Sstevel@tonic-gate 				 * to LACP subsystem.
1277c478bd9Sstevel@tonic-gate 				 */
1287c478bd9Sstevel@tonic-gate 				if (head == cmp) {
1297c478bd9Sstevel@tonic-gate 					/* first packet of chain */
1307c478bd9Sstevel@tonic-gate 					ASSERT(last == NULL);
1317c478bd9Sstevel@tonic-gate 					head = cmp->b_next;
1327c478bd9Sstevel@tonic-gate 					cmp->b_next = NULL;
133da14cebeSEric Cheng 					aggr_recv_lacp(port, mrh, cmp);
1347c478bd9Sstevel@tonic-gate 					cmp = head;
1357c478bd9Sstevel@tonic-gate 				} else {
1367c478bd9Sstevel@tonic-gate 					/* previously accumulated packets */
1377c478bd9Sstevel@tonic-gate 					ASSERT(last != NULL);
1387c478bd9Sstevel@tonic-gate 					/* send up non-LACP packets */
1397c478bd9Sstevel@tonic-gate 					last->b_next = NULL;
140da14cebeSEric Cheng 					if (port->lp_collector_enabled) {
141da14cebeSEric Cheng 						aggr_mac_rx(grp->lg_mh, mrh,
142da14cebeSEric Cheng 						    head);
143da14cebeSEric Cheng 					} else {
144f12af565Snd 						freemsgchain(head);
145da14cebeSEric Cheng 					}
1467c478bd9Sstevel@tonic-gate 					/* unlink and pass up LACP packets */
1477c478bd9Sstevel@tonic-gate 					head = cmp->b_next;
1487c478bd9Sstevel@tonic-gate 					cmp->b_next = NULL;
149da14cebeSEric Cheng 					aggr_recv_lacp(port, mrh, cmp);
1507c478bd9Sstevel@tonic-gate 					cmp = head;
1517c478bd9Sstevel@tonic-gate 					last = NULL;
1527c478bd9Sstevel@tonic-gate 				}
1537c478bd9Sstevel@tonic-gate 			} else {
1547c478bd9Sstevel@tonic-gate 				last = cmp;
1557c478bd9Sstevel@tonic-gate 				cmp = cmp->b_next;
1567c478bd9Sstevel@tonic-gate 			}
1577c478bd9Sstevel@tonic-gate 		}
1587c478bd9Sstevel@tonic-gate 		if (head != NULL) {
1597c478bd9Sstevel@tonic-gate 			if (port->lp_collector_enabled)
160da14cebeSEric Cheng 				aggr_mac_rx(grp->lg_mh, mrh, head);
1617c478bd9Sstevel@tonic-gate 			else
162f12af565Snd 				freemsgchain(head);
1637c478bd9Sstevel@tonic-gate 		}
1647c478bd9Sstevel@tonic-gate 	}
1657c478bd9Sstevel@tonic-gate }
16684de666eSRyan Zezeski 
16784de666eSRyan Zezeski void
aggr_recv_cb(void * arg,mac_resource_handle_t mrh,mblk_t * mp,boolean_t loopback)16884de666eSRyan Zezeski aggr_recv_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
16984de666eSRyan Zezeski     boolean_t loopback)
17084de666eSRyan Zezeski {
171*45948e49SRyan Zezeski 	aggr_recv_path_cb(arg, mrh, mp, loopback);
17284de666eSRyan Zezeski }
173