diff options
author | dg199075 <none@none> | 2006-09-19 11:16:27 -0700 |
---|---|---|
committer | dg199075 <none@none> | 2006-09-19 11:16:27 -0700 |
commit | 605445d5657096e69d948ccb554c9ff024fa34df (patch) | |
tree | c0acbb1d49d8259bf1a104d24f427270905e955c /usr/src | |
parent | 8bc68872f6b178bf5e1d324c663e29fb6ccb1eab (diff) | |
download | illumos-gate-605445d5657096e69d948ccb554c9ff024fa34df.tar.gz |
PSARC/2006/358 VLAN Observability Enhancement
4095699 snoop: add support for 802.1Q VLAN tagging
6292043 DL_PROMISC_SAP should see *all* traffic, not just untagged traffic on GLDv2 links
6306794 GLDv2 drivers incorrectly strip the VLAN tag in raw mode
6309233 GLDv3 drivers incorrectly process VLAN packets in raw mode
6375633 GLDv2 processes DL_PROMISC{ON,OFF}_REQ incorrectly
6425678 DL_PROMISC_SAP should make all VLAN traffic visible on physical GLDv3 links
6434082 Enhance snoop's VLAN filtering capability
6434130 i_dls_ether_header() doesn't generate VLAN header when priority is non-zero
6436003 QoS should be supported on non VLAN streams as well
6438679 GLDv3 doesn't respect QoS priorities in some cases
6442753 GLDv2/GLDv3 has several VLAN packet processing issues
6453746 Change definition of enprintf in pfmod.c
6457476 GLDv2 kstats are not MT-protected, could cause missing increment in some cases
6464397 mac_header_{cook,uncook}() failure can cause a message to be freed twice
Diffstat (limited to 'usr/src')
38 files changed, 2248 insertions, 1073 deletions
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c index 386fcbce85..ff43c225a7 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c @@ -88,6 +88,8 @@ boolean_t zflg = B_FALSE; /* debugging packet corrupt flag */ #endif struct Pf_ext_packetfilt pf; +static int vlanid = 0; + static void usage(void); void show_count(); static void snoop_sigrecover(int sig, siginfo_t *info, void *p); @@ -584,6 +586,11 @@ show_pktinfo(flags, num, src, dst, ptvp, tvp, drops, len) } } + if ((flags & F_SUM) && !(flags & F_ALLSUM) && (vlanid != 0)) { + (void) snprintf(lp, MAXLINE, "VLAN#%i: ", vlanid); + lp += strlen(lp); + } + if (flags & F_WHO) { (void) sprintf(lp, "%12s -> %-12s ", src, dst); lp += strlen(lp); @@ -622,7 +629,7 @@ show_pktinfo(flags, num, src, dst, ptvp, tvp, drops, len) } /* - * The following two routines are called back + * The following three routines are called back * from the interpreters to display their stuff. * The theory is that when snoop becomes a window * based tool we can just supply a new version of @@ -658,6 +665,27 @@ get_detail_line(off, len) } /* + * This function exists to make sure that VLAN information is + * prepended to summary lines displayed. The problem this function + * solves is how to display VLAN information while in summary mode. + * Each interpretor uses the get_sum_line and get_detail_line functions + * to get a character buffer to display information to the user. + * get_sum_line is the important one here. Each call to get_sum_line + * gets a buffer which stores one line of information. In summary mode, + * the last line generated is the line printed. Instead of changing each + * interpreter to add VLAN information to the summary line, the ethernet + * interpreter changes to call this function and set an ID. If the ID is not + * zero and snoop is in default summary mode, snoop displays the + * VLAN information at the beginning of the output line. Otherwise, + * no VLAN information is displayed. + */ +void +set_vlan_id(int id) +{ + vlanid = id; +} + +/* * Print an error. * Works like printf (fmt string and variable args) * except that it will substitute an error message diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h index fe9bf31253..017317e765 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h @@ -126,6 +126,7 @@ extern char *prot_nest_prefix; extern char *get_sum_line(void); extern char *get_detail_line(int, int); +extern void set_vlan_id(int); extern struct timeval prev_time; extern void process_pkt(struct sb_hdr *, char *, int, int); extern char *getflag(int, int, char *, char *); @@ -263,23 +264,29 @@ extern char *print_ethertype(int); * The mac_type is one of the supported DLPI media * types (see <sys/dlpi.h>). * The mtu_size is the size of the largest frame. + * network_type_offset is where the network type + * is located in the link layer header. * The header length is returned by a function to * allow for variable header size - for ethernet it's * just a constant 14 octets. * The interpreter is the function that "knows" how * to interpret the frame. + * try_kernel_filter tells snoop to first try a kernel + * filter (because the header size is fixed, or if it could + * be of variable size where the variable size is easy for a kernel + * filter to handle, for example, Ethernet and VLAN tags) + * and only use a user space filter if the filter expression + * cannot be expressed in kernel space. */ typedef struct interface { uint_t mac_type; uint_t mtu_size; + uint_t network_type_offset; uint_t (*header_len)(char *); uint_t (*interpreter)(int, char *, int, int); - uint_t mac_hdr_fixed_size; + uint_t try_kernel_filter; } interface_t; -#define IF_HDR_FIXED 0 -#define IF_HDR_VAR 1 - extern interface_t INTERFACES[], *interface; extern char *device; diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c index e3e7bd75fd..5d24744e66 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c @@ -240,10 +240,7 @@ check_device(char **devicep, int *ppap) if (interface->mtu_size > (uint_t)netdl.info_ack.dl_max_sdu) netdl.info_ack.dl_max_sdu = (t_scalar_t)interface->mtu_size; - if (interface->mac_hdr_fixed_size == IF_HDR_FIXED) - return (B_TRUE); - - return (B_FALSE); + return (interface->try_kernel_filter); } /* diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ether.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ether.c index f3214def05..8db0a37930 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ether.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ether.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,6 +29,7 @@ #include <stdlib.h> #include <ctype.h> #include <string.h> +#include <stddef.h> #include <fcntl.h> #include <string.h> #include <sys/types.h> @@ -44,11 +44,13 @@ #include <netinet/ip.h> #include <netinet/if_ether.h> #include <sys/ib/clients/ibd/ibd.h> +#include <sys/ethernet.h> +#include <sys/vlan.h> #include "at.h" #include "snoop.h" -static uint_t ether_header_len(char *), fddi_header_len(char *), +static uint_t ether_header_len(char *), fddi_header_len(char *), tr_header_len(char *), ib_header_len(char *); static uint_t interpret_ether(), interpret_fddi(), interpret_tr(); static uint_t interpret_ib(int, char *, int, int); @@ -58,25 +60,24 @@ interface_t *interface; interface_t INTERFACES[] = { /* IEEE 802.3 CSMA/CD network */ - { DL_CSMACD, 1550, ether_header_len, interpret_ether, IF_HDR_FIXED }, + { DL_CSMACD, 1550, 12, ether_header_len, interpret_ether, B_TRUE }, /* Ethernet Bus */ - { DL_ETHER, 1550, ether_header_len, interpret_ether, IF_HDR_FIXED }, + { DL_ETHER, 1550, 12, ether_header_len, interpret_ether, B_TRUE }, /* Fiber Distributed data interface */ - { DL_FDDI, 4500, fddi_header_len, interpret_fddi, IF_HDR_VAR }, + { DL_FDDI, 4500, 19, fddi_header_len, interpret_fddi, B_FALSE }, /* Token Ring interface */ - { DL_TPR, 17800, tr_header_len, interpret_tr, IF_HDR_VAR }, + { DL_TPR, 17800, 0, tr_header_len, interpret_tr, B_FALSE }, /* Infiniband */ - { DL_IB, 4096, ib_header_len, interpret_ib, IF_HDR_FIXED }, + { DL_IB, 4096, 0, ib_header_len, interpret_ib, B_TRUE }, - { (uint_t)-1, 0, 0, 0, 0 } + { (uint_t)-1, 0, 0, 0, 0, 0 } }; - /* externals */ extern char *dlc_header; extern int pi_frame; @@ -109,6 +110,7 @@ interpret_ether(flags, e, elen, origlen) extern char *dst_name; int ethertype; boolean_t data_copied = B_FALSE; + struct ether_vlan_extinfo *evx = NULL; int blen = MAX(origlen, ETHERMTU); if (data != NULL && datalen != 0 && datalen < blen) { @@ -153,7 +155,7 @@ interpret_ether(flags, e, elen, origlen) if (ethertype <= 1514) { /* * Fake out the IEEE 802.3 packets. - * Should be DSAP=170, SSAP=170, control=3 + * Should be DSAP=0xAA, SSAP=0xAA, control=0x03 * then three padding bytes of zero, * followed by a normal ethernet-type packet. */ @@ -163,6 +165,29 @@ interpret_ether(flags, e, elen, origlen) len -= 8; } + if (ethertype == ETHERTYPE_VLAN) { + if (origlen < sizeof (struct ether_vlan_header)) { + if (flags & F_SUM) { + (void) sprintf(get_sum_line(), + "RUNT (short VLAN packet - %d bytes)", + origlen); + } + if (flags & F_DTAIL) { + show_header("RUNT: ", "Short VLAN packet", + origlen); + } + return (elen); + } + if (len < sizeof (struct ether_vlan_extinfo)) + return (elen); + + evx = (struct ether_vlan_extinfo *)off; + off += sizeof (struct ether_vlan_extinfo); + len -= sizeof (struct ether_vlan_extinfo); + + ethertype = ntohs(evx->ether_type); + } + /* * We cannot trust the length field in the header to be correct. * But we should continue to process the packet. Then user can @@ -174,11 +199,27 @@ interpret_ether(flags, e, elen, origlen) } if (flags & F_SUM) { - (void) sprintf(get_sum_line(), - "ETHER Type=%04X (%s), size = %d bytes", - ethertype, - print_ethertype(ethertype), - origlen); + /* + * Set the flag that says don't display VLAN information. + * If it needs to change, that will be done later if the + * packet is VLAN tagged and if snoop is in its default + * summary mode. + */ + set_vlan_id(0); + if (evx == NULL) { + (void) sprintf(get_sum_line(), + "ETHER Type=%04X (%s), size=%d bytes", + ethertype, print_ethertype(ethertype), + origlen); + } else { + (void) sprintf(get_sum_line(), + "ETHER Type=%04X (%s), VLAN ID=%hu, size=%d " + "bytes", ethertype, print_ethertype(ethertype), + VLAN_ID(ntohs(evx->ether_tci)), origlen); + + if (!(flags & F_ALLSUM)) + set_vlan_id(VLAN_ID(ntohs(evx->ether_tci))); + } } if (flags & F_DTAIL) { @@ -200,10 +241,16 @@ interpret_ether(flags, e, elen, origlen) "Source = %s, %s", printether(&e->ether_shost), print_etherinfo(&e->ether_shost)); - if (ieee8023 > 0) + if (ieee8023 > 0) { (void) sprintf(get_line(12, 2), - "IEEE 802.3 length = %d bytes", - ieee8023); + "IEEE 802.3 length = %d bytes", ieee8023); + } + if (evx != NULL) { + (void) sprintf(get_line(0, 0), + "VLAN ID = %hu", VLAN_ID(ntohs(evx->ether_tci))); + (void) sprintf(get_line(0, 0), + "VLAN Priority = %hu", VLAN_PRI(ntohs(evx->ether_tci))); + } (void) sprintf(get_line(12, 2), "Ethertype = %04X (%s)", ethertype, print_ethertype(ethertype)); @@ -242,12 +289,32 @@ interpret_ether(flags, e, elen, origlen) return (elen); } -/* ARGSUSED */ +/* + * Return the length of the ethernet header. In the case + * where we have a VLAN tagged packet, return the length of + * the ethernet header plus the length of the VLAN tag. + * + * INPUTS: e - A buffer pointer. Passing a NULL pointer + * is not allowed, e must be non-NULL. + * OUTPUTS: Return the size of an untagged ethernet header + * if the packet is not VLAN tagged, and the size + * of an untagged ethernet header plus the size of + * a VLAN header otherwise. + */ uint_t ether_header_len(e) char *e; { - return (14); + uint16_t ether_type = 0; + e += (offsetof(struct ether_header, ether_type)); + + GETINT16(ether_type, e); + + if (ether_type == (uint16_t)ETHERTYPE_VLAN) { + return (sizeof (struct ether_vlan_header)); + } else { + return (sizeof (struct ether_header)); + } } diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_filter.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_filter.c index f025214510..a0793502a7 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_filter.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_filter.c @@ -37,6 +37,7 @@ #include <sys/socket.h> #include <sys/sockio.h> +#include <sys/vlan.h> #include <net/if.h> #include <netinet/in_systm.h> #include <netinet/in.h> @@ -54,6 +55,7 @@ #include <sys/dlpi.h> #include <snoop.h> +#include "snoop_vlan.h" #define IPV4_ONLY 0 #define IPV6_ONLY 1 @@ -73,6 +75,7 @@ #define MASKED_IPV6_VERS 0x60 #define IP_HDR_LEN(p) (((*(uchar_t *)p) & 0xf) * 4) #define TCP_HDR_LEN(p) ((((*((uchar_t *)p+12)) >> 4) & 0xf) * 4) + /* * Coding the constant below is tacky, but the compiler won't let us * be more clever. E.g., &((struct ip *)0)->ip_xxx @@ -128,6 +131,11 @@ int opstack; /* operand stack depth */ * It points the base at the cached RPC header. For the * purposes of selection, RPC reply headers look like call * headers except for the direction value. + * OP_OFFSET_ETHERTYPE sets base according to the following + * algorithm: + * if the packet is not VLAN tagged, then set base to + * the ethertype field in the ethernet header + * else set base to the ethertype field of the VLAN header * OP_OFFSET_POP restores the offset base to the value prior * to the most recent OP_OFFSET call. */ @@ -163,6 +171,7 @@ enum optype { OP_OFFSET_UDP, OP_OFFSET_RPC, OP_OFFSET_SLP, + OP_OFFSET_ETHERTYPE, OP_LAST }; @@ -198,6 +207,7 @@ static char *opnames[] = { "OFFSET_UDP", "OFFSET_RPC", "OP_OFFSET_SLP", + "OFFSET_ETHERTYPE", "" }; @@ -219,6 +229,27 @@ static struct xid_entry *find_rpc(); static void optimize(); static void ethertype_match(); +/* + * Get a ushort from a possibly unaligned character buffer. + * + * INPUTS: buffer - where the data is. Must be at least + * sizeof(uint16_t) bytes long. + * OUPUTS: An unsigned short that contains the data at buffer. + * No calls to ntohs or htons are done on the data. + */ +static uint16_t +get_u16(uchar_t *buffer) +{ + uint8_t *bufraw = buffer; + + /* + * ntohs is used only as a cheap way to flip the bits + * around on a little endian platform. The value will + * still be in host order or network order, depending on + * the order it was in when it was passed in. + */ + return (ntohs(bufraw[0] << 8 | bufraw[1])); +} /* * Returns the ULP for an IPv4 or IPv6 packet @@ -524,6 +555,7 @@ want_packet(uchar_t *pkt, int len, int origlen) uchar_t **offp; /* current offset */ uchar_t *opkt = NULL; uint_t olen; + uint_t ethertype = 0; sp = stack; *sp = 1; @@ -546,21 +578,7 @@ want_packet(uchar_t *pkt, int len, int origlen) if ((base + off + sizeof (uint16_t) - 1) > (pkt + len)) return (0); /* packet too short */ - /* - * Handle 2 possible alignments - */ - switch ((((unsigned)base)+off) % sizeof (ushort_t)) { - case 0: - *sp = ntohs(*((ushort_t *)(base + *sp))); - break; - case 1: - *((uchar_t *)(sp)) = - *((uchar_t *)(base + off)); - *(((uchar_t *)sp) + 1) = - *((uchar_t *)(base + off) + 1); - *sp = ntohs(*(ushort_t *)sp); - break; - } + *sp = ntohs(get_u16((uchar_t *)(base + off))); break; case OP_LOAD_LONG: off = *sp; @@ -900,6 +918,45 @@ want_packet(uchar_t *pkt, int len, int origlen) return (0); *(++sp) = 0; break; + case OP_OFFSET_ETHERTYPE: + /* + * Set base to the location of the ethertype. + * If the packet is VLAN tagged, move base + * to the ethertype field in the VLAN header. + * Otherwise, set it to the appropriate field + * for this link type. + */ + if (offp >= &offstack[MAXSS]) + return (0); + *++offp = base; + base = pkt + interface->network_type_offset; + if (base > pkt + len) { + /* Went too far, drop the packet */ + return (0); + } + + /* + * VLAN links are only supported on Ethernet-like + * links. + */ + if (interface->mac_type == DL_ETHER || + interface->mac_type == DL_CSMACD) { + if (ntohs(get_u16(base)) == ETHERTYPE_VLAN) { + /* + * We need to point to the + * ethertype field in the VLAN + * tag, so also move past the + * ethertype field in the + * ethernet header. + */ + base += (ENCAP_ETHERTYPE_OFF); + } + if (base > pkt + len) { + /* Went too far, drop the packet */ + return (0); + } + } + break; } } @@ -1250,36 +1307,36 @@ static struct match_type { } match_types[] = { /* * Table initialized assuming Ethernet data link headers. + * m_offset is an offset beyond the offset op, which is why + * the offset is zero for when snoop needs to check an ethertype. */ - "ip", 12, 2, ETHERTYPE_IP, -1, OP_OFFSET_ZERO, - "ip6", 12, 2, ETHERTYPE_IPV6, -1, OP_OFFSET_ZERO, - "arp", 12, 2, ETHERTYPE_ARP, -1, OP_OFFSET_ZERO, - "rarp", 12, 2, ETHERTYPE_REVARP, -1, OP_OFFSET_ZERO, - "pppoed", 12, 2, ETHERTYPE_PPPOED, -1, OP_OFFSET_ZERO, - "pppoes", 12, 2, ETHERTYPE_PPPOES, -1, OP_OFFSET_ZERO, - "tcp", 9, 1, IPPROTO_TCP, 0, OP_OFFSET_LINK, - "tcp", 6, 1, IPPROTO_TCP, 1, OP_OFFSET_LINK, - "udp", 9, 1, IPPROTO_UDP, 0, OP_OFFSET_LINK, - "udp", 6, 1, IPPROTO_UDP, 1, OP_OFFSET_LINK, - "icmp", 9, 1, IPPROTO_ICMP, 0, OP_OFFSET_LINK, - "icmp6", 6, 1, IPPROTO_ICMPV6, 1, OP_OFFSET_LINK, - "ospf", 9, 1, IPPROTO_OSPF, 0, OP_OFFSET_LINK, - "ospf", 6, 1, IPPROTO_OSPF, 1, OP_OFFSET_LINK, - "ip-in-ip", 9, 1, IPPROTO_ENCAP, 0, OP_OFFSET_LINK, - "esp", 9, 1, IPPROTO_ESP, 0, OP_OFFSET_LINK, - "esp", 6, 1, IPPROTO_ESP, 1, OP_OFFSET_LINK, - "ah", 9, 1, IPPROTO_AH, 0, OP_OFFSET_LINK, - "ah", 6, 1, IPPROTO_AH, 1, OP_OFFSET_LINK, - "sctp", 9, 1, IPPROTO_SCTP, 0, OP_OFFSET_LINK, - "sctp", 6, 1, IPPROTO_SCTP, 1, OP_OFFSET_LINK, - 0, 0, 0, 0, 0, 0 + "ip", 0, 2, ETHERTYPE_IP, -1, OP_OFFSET_ETHERTYPE, + "ip6", 0, 2, ETHERTYPE_IPV6, -1, OP_OFFSET_ETHERTYPE, + "arp", 0, 2, ETHERTYPE_ARP, -1, OP_OFFSET_ETHERTYPE, + "rarp", 0, 2, ETHERTYPE_REVARP, -1, OP_OFFSET_ETHERTYPE, + "pppoed", 0, 2, ETHERTYPE_PPPOED, -1, OP_OFFSET_ETHERTYPE, + "pppoes", 0, 2, ETHERTYPE_PPPOES, -1, OP_OFFSET_ETHERTYPE, + "tcp", 9, 1, IPPROTO_TCP, 0, OP_OFFSET_LINK, + "tcp", 6, 1, IPPROTO_TCP, 1, OP_OFFSET_LINK, + "udp", 9, 1, IPPROTO_UDP, 0, OP_OFFSET_LINK, + "udp", 6, 1, IPPROTO_UDP, 1, OP_OFFSET_LINK, + "icmp", 9, 1, IPPROTO_ICMP, 0, OP_OFFSET_LINK, + "icmp6", 6, 1, IPPROTO_ICMPV6, 1, OP_OFFSET_LINK, + "ospf", 9, 1, IPPROTO_OSPF, 0, OP_OFFSET_LINK, + "ospf", 6, 1, IPPROTO_OSPF, 1, OP_OFFSET_LINK, + "ip-in-ip", 9, 1, IPPROTO_ENCAP, 0, OP_OFFSET_LINK, + "esp", 9, 1, IPPROTO_ESP, 0, OP_OFFSET_LINK, + "esp", 6, 1, IPPROTO_ESP, 1, OP_OFFSET_LINK, + "ah", 9, 1, IPPROTO_AH, 0, OP_OFFSET_LINK, + "ah", 6, 1, IPPROTO_AH, 1, OP_OFFSET_LINK, + "sctp", 9, 1, IPPROTO_SCTP, 0, OP_OFFSET_LINK, + "sctp", 6, 1, IPPROTO_SCTP, 1, OP_OFFSET_LINK, + 0, 0, 0, 0, 0, 0 }; static void generate_check(struct match_type *mtp) { - int offset; - /* * Note: this code assumes the above dependencies are * not cyclic. This *should* always be true. @@ -1287,45 +1344,10 @@ generate_check(struct match_type *mtp) if (mtp->m_depend != -1) generate_check(&match_types[mtp->m_depend]); - offset = mtp->m_offset; - if (mtp->m_optype == OP_OFFSET_ZERO) { - - /* - * The table is filled with ethernet offsets. Here we - * fudge the value based on what know about the - * interface. It is okay to do this because we are - * checking what we believe to be an IP/ARP/RARP - * packet, and we know those are carried in LLC-SNAP - * headers on FDDI. We assume that it's unlikely - * another kind of packet, with a shorter FDDI header - * will happen to match the filter. - * - * Ether FDDI IPoIB - * edst addr 0 1 none - * esrc addr 6 7 none - * ethertype 12 19 0 - * - * XXX token ring? - */ - if (interface->mac_type == DL_FDDI) { - if (offset < 12) - offset++; - else if (offset == 12) - offset = 19; - } else if (interface->mac_type == DL_IB) { - offset = 0; - } - } - - if (mtp->m_optype != OP_OFFSET_ZERO) { - emitop(mtp->m_optype); - load_value(offset, mtp->m_size); - load_const(mtp->m_value); - emitop(OP_OFFSET_POP); - } else { - load_value(offset, mtp->m_size); - load_const(mtp->m_value); - } + emitop(mtp->m_optype); + load_value(mtp->m_offset, mtp->m_size); + load_const(mtp->m_value); + emitop(OP_OFFSET_POP); emitop(OP_EQ); @@ -1732,6 +1754,7 @@ etheraddr_match(enum direction which, char *hostname) memcpy(&addr, (ushort_t *)ep, 4); addrp = (ushort_t *)ep + 2; + emitop(OP_OFFSET_ZERO); switch (which) { case TO: compare_value(to_offset, 4, ntohl(addr)); @@ -1760,33 +1783,40 @@ etheraddr_match(enum direction which, char *hostname) resolve_chain(m); break; } + emitop(OP_OFFSET_POP); } static void ethertype_match(int val) { - int m; - int ether_offset; - - switch (interface->mac_type) { - case DL_ETHER: - ether_offset = 12; - break; - - case DL_IB: - ether_offset = 0; - break; + int ether_offset = interface->network_type_offset; - case DL_FDDI: - /* XXX Okay to assume LLC SNAP? */ - ether_offset = 19; - break; - - default: - load_const(1); /* Assume a match */ - return; + /* + * If the user is interested in ethertype VLAN, + * then we need to set the offset to the beginning of the packet. + * But if the user is interested in another ethertype, + * such as IPv4, then we need to take into consideration + * the fact that the packet might be VLAN tagged. + */ + if (interface->mac_type == DL_ETHER || + interface->mac_type == DL_CSMACD) { + if (val != ETHERTYPE_VLAN) { + /* + * OP_OFFSET_ETHERTYPE puts us at the ethertype + * field whether or not there is a VLAN tag, + * so ether_offset goes to zero if we get here. + */ + emitop(OP_OFFSET_ETHERTYPE); + ether_offset = 0; + } else { + emitop(OP_OFFSET_ZERO); + } + } + compare_value(ether_offset, 2, val); + if (interface->mac_type == DL_ETHER || + interface->mac_type == DL_CSMACD) { + emitop(OP_OFFSET_POP); } - compare_value(ether_offset, 2, val); /* XXX.sparker */ } /* @@ -2076,9 +2106,11 @@ primary() * bytes long, this works for FDDI & ethernet. * XXX - Token ring? */ + emitop(OP_OFFSET_ZERO); if (interface->mac_type == DL_IB) pr_err("filter option unsupported on media"); compare_value(1, 4, 0xffffffff); + emitop(OP_OFFSET_POP); opstack++; next(); break; @@ -2086,6 +2118,7 @@ primary() if (EQ("multicast")) { /* XXX Token ring? */ + emitop(OP_OFFSET_ZERO); if (interface->mac_type == DL_FDDI) { compare_value_mask(1, 1, 0x01, 0x01); } else if (interface->mac_type == DL_IB) { @@ -2093,6 +2126,7 @@ primary() } else { compare_value_mask(0, 1, 0x01, 0x01); } + emitop(OP_OFFSET_POP); opstack++; next(); break; @@ -2111,21 +2145,40 @@ primary() emitop(OP_LE); resolve_chain(m); } else { - load_value(12, 2); /* ether type */ + emitop(OP_OFFSET_ETHERTYPE); + load_value(0, 2); /* ether type */ load_const(0x6000); emitop(OP_GE); emitop(OP_BRFL); m = chain(0); - load_value(12, 2); /* ether type */ + load_value(0, 2); /* ether type */ load_const(0x6009); emitop(OP_LE); resolve_chain(m); + emitop(OP_OFFSET_POP); } opstack++; next(); break; } + if (EQ("vlan-id")) { + next(); + if (tokentype != NUMBER) + pr_err("vlan id expected"); + emitop(OP_OFFSET_ZERO); + ethertype_match(ETHERTYPE_VLAN); + emitop(OP_BRFL); + m = chain(0); + compare_value_mask(VLAN_ID_OFFSET, 2, tokenval, + VLAN_ID_MASK); + resolve_chain(m); + emitop(OP_OFFSET_POP); + opstack++; + next(); + break; + } + if (EQ("apple")) { /* * Appletalk also appears in 802.2 @@ -2148,6 +2201,16 @@ primary() break; } + if (EQ("vlan")) { + ethertype_match(ETHERTYPE_VLAN); + compare_value_mask(VLAN_ID_OFFSET, 2, 0, VLAN_ID_MASK); + emitop(OP_NOT); + emitop(OP_AND); + opstack++; + next(); + break; + } + if (EQ("bootp") || EQ("dhcp")) { emitop(OP_OFFSET_LINK); emitop(OP_LOAD_CONST); @@ -2163,6 +2226,8 @@ primary() compare_value(0, 4, (IPPORT_BOOTPC << 16 | IPPORT_BOOTPS)); resolve_chain(m); + emitop(OP_OFFSET_POP); + emitop(OP_OFFSET_POP); opstack++; dir = ANY; next(); diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_pf.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_pf.c index 8ef09a2fc9..072d05f833 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_pf.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_pf.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,13 +19,14 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* SunOS */ #include <stdio.h> +#include <stddef.h> #include <ctype.h> #include <string.h> #include <fcntl.h> @@ -38,6 +38,7 @@ #include <sys/socket.h> #include <sys/sockio.h> #include <sys/dlpi.h> +#include <sys/vlan.h> #include <net/if.h> #include <netinet/in_systm.h> #include <netinet/in.h> @@ -51,6 +52,7 @@ #include <sys/pfmod.h> #include "snoop.h" +#include "snoop_vlan.h" /* * This module generates code for the kernel packet filter. @@ -97,8 +99,8 @@ static int link_addr_len = 6; #define IPV4_DSTADDR_OFFSET (link_header_len + 16) #define IPV6_SRCADDR_OFFSET (link_header_len + 8) #define IPV6_DSTADDR_OFFSET (link_header_len + 24) -#define IPV4_TYPE_OFFSET (link_header_len + 9) -#define IPV6_TYPE_OFFSET (link_header_len + 6) +#define IPV4_TYPE_HEADER_OFFSET (9) +#define IPV6_TYPE_HEADER_OFFSET (6) static int inBrace = 0, inBraceOR = 0; static int foundOR = 0; @@ -114,6 +116,26 @@ enum direction dir; extern void next(); static void pf_expression(); +static void pf_check_vlan_tag(uint_t offset); +static void pf_clear_offset_register(); +static void pf_emit_load_offset(uint_t offset); +static void pf_match_ethertype(uint_t ethertype); +static void pf_check_transport_protocol(uint_t transport_protocol); +static void pf_compare_value_mask_generic(int offset, uint_t len, + uint_t val, int mask, uint_t op); + +/* + * This pointer points to the function that last generated + * instructions to change the offset register. It's used + * for comparisons to see if we need to issue more instructions + * to change the register. + * + * It's initialized to pf_clear_offset_register because the offset + * register in pfmod is initialized to zero, similar to the state + * it would be in after executing the instructions issued by + * pf_clear_offset_register. + */ +static void *last_offset_operation = (void*)pf_clear_offset_register; static void pf_emit(x) @@ -170,6 +192,18 @@ pf_codeprint(code, len) printf("PUSH00FF "); break; #endif + case ENF_LOAD_OFFSET: + printf("LOAD_OFFSET "); + break; + case ENF_BRTR: + printf("BRTR "); + break; + case ENF_BRFL: + printf("BRFL "); + break; + case ENF_POP: + printf("POP "); + break; } if (action >= ENF_PUSHWORD) @@ -217,7 +251,10 @@ pf_codeprint(code, len) break; } - if (action == ENF_PUSHLIT) { + if (action == ENF_PUSHLIT || + action == ENF_LOAD_OFFSET || + action == ENF_BRTR || + action == ENF_BRFL) { pc++; printf("\n\t%3d: %d (0x%04x)", pc - code, *pc, *pc); } @@ -323,11 +360,36 @@ pf_compare_value_v6(int offset, uint_t len, struct in6_addr val) /* * Same as above except mask the field value - * before doing the comparison. + * before doing the comparison. The comparison checks + * to make sure the values are equal. */ static void pf_compare_value_mask(int offset, uint_t len, uint_t val, int mask) { + pf_compare_value_mask_generic(offset, len, val, mask, ENF_EQ); +} + +/* + * Same as above except the values are compared to see if they are not + * equal. + */ +static void +pf_compare_value_mask_neq(int offset, uint_t len, uint_t val, int mask) +{ + pf_compare_value_mask_generic(offset, len, val, mask, ENF_NEQ); +} + +/* + * Similar to pf_compare_value. + * + * This is the utility function that does the actual work to compare + * two values using a mask. The comparison operation is passed into + * the function. + */ +static void +pf_compare_value_mask_generic(int offset, uint_t len, uint_t val, int mask, + uint_t op) +{ /* * If the property being filtered on is absent in the media * packet, error out. @@ -346,12 +408,12 @@ pf_compare_value_mask(int offset, uint_t len, uint_t val, int mask) { pf_emit(ENF_PUSHLIT | ENF_AND); pf_emit(mask & 0x00ff); - pf_emit(ENF_PUSHLIT | ENF_EQ); + pf_emit(ENF_PUSHLIT | op); pf_emit(val); } else { pf_emit(ENF_PUSHLIT | ENF_AND); pf_emit((mask << 8) & 0xff00); - pf_emit(ENF_PUSHLIT | ENF_EQ); + pf_emit(ENF_PUSHLIT | op); pf_emit(val << 8); } break; @@ -360,7 +422,7 @@ pf_compare_value_mask(int offset, uint_t len, uint_t val, int mask) pf_emit(ENF_PUSHWORD + offset / 2); pf_emit(ENF_PUSHLIT | ENF_AND); pf_emit(htons((ushort_t)mask)); - pf_emit(ENF_PUSHLIT | ENF_EQ); + pf_emit(ENF_PUSHLIT | op); pf_emit(htons((ushort_t)val)); break; @@ -368,13 +430,13 @@ pf_compare_value_mask(int offset, uint_t len, uint_t val, int mask) pf_emit(ENF_PUSHWORD + offset / 2); pf_emit(ENF_PUSHLIT | ENF_AND); pf_emit(htons((ushort_t)((mask >> 16) & 0xffff))); - pf_emit(ENF_PUSHLIT | ENF_EQ); + pf_emit(ENF_PUSHLIT | op); pf_emit(htons((ushort_t)((val >> 16) & 0xffff))); pf_emit(ENF_PUSHWORD + (offset / 2) + 1); pf_emit(ENF_PUSHLIT | ENF_AND); pf_emit(htons((ushort_t)(mask & 0xffff))); - pf_emit(ENF_PUSHLIT | ENF_EQ); + pf_emit(ENF_PUSHLIT | op); pf_emit(htons((ushort_t)(val & 0xffff))); pf_emit(ENF_AND); @@ -491,7 +553,8 @@ pf_ipaddr_match(which, hostname, inet_type) } if (hp != NULL && hp->h_addrtype == AF_INET) { - pf_compare_value(link_type_offset, 2, htons(ETHERTYPE_IP)); + pf_match_ethertype(ETHERTYPE_IP); + pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2); h_addr_index = 0; addr4ptr = (uint_t *)hp->h_addr_list[h_addr_index]; while (addr4ptr != NULL) { @@ -520,8 +583,9 @@ pf_ipaddr_match(which, hostname, inet_type) while (addr6ptr != NULL) { if (IN6_IS_ADDR_V4MAPPED(addr6ptr)) { if (first) { - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_IP)); + pf_match_ethertype(ETHERTYPE_IP); + pf_check_vlan_tag( + ENCAP_ETHERTYPE_OFF/2); pass++; } IN6_V4MAPPED_TO_INADDR(addr6ptr, @@ -556,8 +620,9 @@ pf_ipaddr_match(which, hostname, inet_type) while (addr6ptr != NULL) { if (!IN6_IS_ADDR_V4MAPPED(addr6ptr)) { if (first) { - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_IPV6)); + pf_match_ethertype(ETHERTYPE_IPV6); + pf_check_vlan_tag( + ENCAP_ETHERTYPE_OFF/2); pass++; } if (addr6offset == -1) { @@ -651,6 +716,8 @@ pf_etheraddr_match(which, hostname) ep = &e; } + pf_clear_offset_register(); + switch (which) { case TO: pf_compare_address(link_dest_offset, link_addr_len, @@ -705,6 +772,8 @@ pf_netaddr_match(which, netname) } } + pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2); + switch (which) { case TO: pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask); @@ -720,6 +789,223 @@ pf_netaddr_match(which, netname) } } +/* + * A helper function to keep the code to emit instructions + * to change the offset register in one place. + * + * INPUTS: offset - An value representing an offset in 16-bit + * words. + * OUTPUTS: If there is enough room in the storage for the + * packet filtering program, instructions to load + * a constant to the offset register. Otherwise, + * nothing. + */ +static void +pf_emit_load_offset(uint_t offset) +{ + pf_emit(ENF_LOAD_OFFSET | ENF_NOP); + pf_emit(offset); +} + +/* + * Clear pfmod's offset register. + * + * INPUTS: none + * OUTPUTS: Instructions to clear the offset register if + * there is enough space remaining in the packet + * filtering program structure's storage, and + * the last thing done to the offset register was + * not clearing the offset register. Otherwise, + * nothing. + */ +static void +pf_clear_offset_register() +{ + if (last_offset_operation != (void*)pf_clear_offset_register) { + pf_emit_load_offset(0); + last_offset_operation = (void*)pf_clear_offset_register; + } +} + +/* + * This function will issue opcodes to check if a packet + * is VLAN tagged, and if so, update the offset register + * with the appropriate offset. + * + * Note that if the packet is not VLAN tagged, then the offset + * register will be cleared. + * + * If the interface type is not an ethernet type, then this + * function returns without doing anything. + * + * If the last attempt to change the offset register occured because + * of a call to this function that was called with the same offset, + * then we don't issue packet filtering instructions. + * + * INPUTS: offset - an offset in 16 bit words. The function + * will set the offset register to this + * value if the packet is VLAN tagged. + * OUTPUTS: If the conditions are met, packet filtering instructions. + */ +static void +pf_check_vlan_tag(uint_t offset) +{ + static uint_t last_offset = 0; + + if ((interface->mac_type == DL_ETHER || + interface->mac_type == DL_CSMACD) && + (last_offset_operation != (void*)pf_check_vlan_tag || + last_offset != offset)) { + /* + * First thing is to clear the offset register. + * We don't know what state it is in, and if it + * is not zero, then we have no idea what we load + * when we execute ENF_PUSHWORD. + */ + pf_clear_offset_register(); + + /* + * Check the ethertype. + */ + pf_compare_value(link_type_offset, 2, htons(ETHERTYPE_VLAN)); + + /* + * And if it's not VLAN, don't load offset to the offset + * register. + */ + pf_emit(ENF_BRFL | ENF_NOP); + pf_emit(3); + + /* + * Otherwise, load offset to the offset register. + */ + pf_emit_load_offset(offset); + + /* + * Now get rid of the results of the comparison, + * we don't want the results of the comparison to affect + * other logic in the packet filtering program. + */ + pf_emit(ENF_POP | ENF_NOP); + + /* + * Set the last operation at the end, or any time + * after the call to pf_clear_offset because + * pf_clear_offset uses it. + */ + last_offset_operation = (void*)pf_check_vlan_tag; + last_offset = offset; + } +} + +/* + * Utility function used to emit packet filtering code + * to match an ethertype. + * + * INPUTS: ethertype - The ethertype we want to check for. + * Don't call htons on the ethertype before + * calling this function. + * OUTPUTS: If there is sufficient storage available, packet + * filtering code to check an ethertype. Otherwise, + * nothing. + */ +static void +pf_match_ethertype(uint_t ethertype) +{ + /* + * If the user wants to filter on ethertype VLAN, + * then clear the offset register so that the offset + * for ENF_PUSHWORD points to the right place in the + * packet. + * + * Otherwise, call pf_check_vlan_tag to set the offset + * register such that the contents of the offset register + * plus the argument for ENF_PUSHWORD point to the right + * part of the packet, whether or not the packet is VLAN + * tagged. We call pf_check_vlan_tag with an offset of + * two words because if the packet is VLAN tagged, we have + * to move past the ethertype in the ethernet header, and + * past the lower two octets of the VLAN header to get to + * the ethertype in the VLAN header. + */ + if (ethertype == ETHERTYPE_VLAN) + pf_clear_offset_register(); + else + pf_check_vlan_tag(2); + + pf_compare_value(link_type_offset, 2, htons(ethertype)); +} + +typedef struct { + int transport_protocol; + int network_protocol; + /* + * offset is the offset in bytes from the beginning + * of the network protocol header to where the transport + * protocol type is. + */ + int offset; +} transport_protocol_table_t; + +static transport_protocol_table_t mapping_table[] = { + {IPPROTO_TCP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, + {IPPROTO_TCP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, + {IPPROTO_UDP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, + {IPPROTO_UDP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, + {IPPROTO_OSPF, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, + {IPPROTO_OSPF, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, + {IPPROTO_SCTP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, + {IPPROTO_SCTP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, + {IPPROTO_ICMP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, + {IPPROTO_ICMPV6, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, + {IPPROTO_ENCAP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, + {IPPROTO_ESP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, + {IPPROTO_ESP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, + {IPPROTO_AH, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET}, + {IPPROTO_AH, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET}, + {-1, 0, 0} /* must be the final entry */ +}; + +/* + * This function uses the table above to generate a + * piece of a packet filtering program to check a transport + * protocol type. + * + * INPUTS: tranport_protocol - the transport protocol we're + * interested in. + * OUTPUTS: If there is sufficient storage, then packet filtering + * code to check a transport protocol type. Otherwise, + * nothing. + */ +static void +pf_check_transport_protocol(uint_t transport_protocol) +{ + int i = 0; + uint_t number_of_matches = 0; + + for (i = 0; mapping_table[i].transport_protocol != -1; i++) { + if (transport_protocol == + (uint_t)mapping_table[i].transport_protocol) { + number_of_matches++; + pf_match_ethertype(mapping_table[i].network_protocol); + pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2); + pf_compare_value( + mapping_table[i].offset + link_header_len, 1, + transport_protocol); + pf_emit(ENF_AND); + if (number_of_matches > 1) { + /* + * Since we have two or more matches, in + * order to have a correct and complete + * program we need to OR the result of + * each block of comparisons together. + */ + pf_emit(ENF_OR); + } + } + } +} + static void pf_primary() { @@ -728,26 +1014,22 @@ pf_primary() break; if (EQ("ip")) { - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_IP)); + pf_match_ethertype(ETHERTYPE_IP); opstack++; next(); break; } if (EQ("ip6")) { - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_IPV6)); + pf_match_ethertype(ETHERTYPE_IPV6); opstack++; next(); break; } if (EQ("pppoe")) { - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_PPPOED)); - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_PPPOES)); + pf_match_ethertype(ETHERTYPE_PPPOED); + pf_match_ethertype(ETHERTYPE_PPPOES); pf_emit(ENF_OR); opstack++; next(); @@ -755,77 +1037,72 @@ pf_primary() } if (EQ("pppoed")) { - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_PPPOED)); + pf_match_ethertype(ETHERTYPE_PPPOED); opstack++; next(); break; } if (EQ("pppoes")) { - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_PPPOES)); + pf_match_ethertype(ETHERTYPE_PPPOES); opstack++; next(); break; } if (EQ("arp")) { - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_ARP)); + pf_match_ethertype(ETHERTYPE_ARP); + opstack++; + next(); + break; + } + + if (EQ("vlan")) { + pf_match_ethertype(ETHERTYPE_VLAN); + pf_compare_value_mask_neq(VLAN_ID_OFFSET, 2, + 0, VLAN_ID_MASK); + pf_emit(ENF_AND); + opstack++; + next(); + break; + } + + if (EQ("vlan-id")) { + next(); + if (tokentype != NUMBER) + pr_err("VLAN ID expected"); + pf_match_ethertype(ETHERTYPE_VLAN); + pf_compare_value_mask(VLAN_ID_OFFSET, 2, tokenval, + VLAN_ID_MASK); + pf_emit(ENF_AND); opstack++; next(); break; } if (EQ("rarp")) { - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_REVARP)); + pf_match_ethertype(ETHERTYPE_REVARP); opstack++; next(); break; } if (EQ("tcp")) { - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_IP)); - pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_TCP); - pf_emit(ENF_AND); - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_IPV6)); - pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_TCP); - pf_emit(ENF_AND); - pf_emit(ENF_OR); + pf_check_transport_protocol(IPPROTO_TCP); opstack++; next(); break; } if (EQ("udp")) { - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_IP)); - pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_UDP); - pf_emit(ENF_AND); - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_IPV6)); - pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_UDP); - pf_emit(ENF_AND); - pf_emit(ENF_OR); + pf_check_transport_protocol(IPPROTO_UDP); opstack++; next(); break; } if (EQ("ospf")) { - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_IP)); - pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_OSPF); - pf_emit(ENF_AND); - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_IPV6)); - pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_OSPF); - pf_emit(ENF_AND); - pf_emit(ENF_OR); + pf_check_transport_protocol(IPPROTO_OSPF); opstack++; next(); break; @@ -833,75 +1110,42 @@ pf_primary() if (EQ("sctp")) { - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_IP)); - pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_SCTP); - pf_emit(ENF_AND); - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_IPV6)); - pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_SCTP); - pf_emit(ENF_AND); - pf_emit(ENF_OR); + pf_check_transport_protocol(IPPROTO_SCTP); opstack++; next(); break; } if (EQ("icmp")) { - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_IP)); - pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_ICMP); - pf_emit(ENF_AND); + pf_check_transport_protocol(IPPROTO_ICMP); opstack++; next(); break; } if (EQ("icmp6")) { - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_IPV6)); - pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_ICMPV6); - pf_emit(ENF_AND); + pf_check_transport_protocol(IPPROTO_ICMPV6); opstack++; next(); break; } if (EQ("ip-in-ip")) { - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_IP)); - pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_ENCAP); - pf_emit(ENF_AND); + pf_check_transport_protocol(IPPROTO_ENCAP); opstack++; next(); break; } if (EQ("esp")) { - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_IP)); - pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_ESP); - pf_emit(ENF_AND); - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_IPV6)); - pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_ESP); - pf_emit(ENF_AND); - pf_emit(ENF_OR); + pf_check_transport_protocol(IPPROTO_ESP); opstack++; next(); break; } if (EQ("ah")) { - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_IP)); - pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_AH); - pf_emit(ENF_AND); - pf_compare_value(link_type_offset, 2, - htons(ETHERTYPE_IPV6)); - pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_AH); - pf_emit(ENF_AND); - pf_emit(ENF_OR); + pf_check_transport_protocol(IPPROTO_AH); opstack++; next(); break; @@ -966,13 +1210,15 @@ pf_primary() next(); if (tokentype != NUMBER) pr_err("IP proto type expected"); - pf_compare_value(IPV4_TYPE_OFFSET, 1, tokenval); + pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2); + pf_compare_value(IPV4_TYPE_HEADER_OFFSET, 1, tokenval); opstack++; next(); break; } if (EQ("broadcast")) { + pf_clear_offset_register(); pf_compare_value(link_dest_offset, 4, 0xffffffff); opstack++; next(); @@ -980,6 +1226,7 @@ pf_primary() } if (EQ("multicast")) { + pf_clear_offset_register(); pf_compare_value_mask(link_dest_offset, 1, 0x01, 0x01); opstack++; next(); @@ -990,7 +1237,7 @@ pf_primary() next(); if (tokentype != NUMBER) pr_err("ether type expected"); - pf_compare_value(link_type_offset, 2, htons(tokenval)); + pf_match_ethertype(tokenval); opstack++; next(); break; diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_vlan.h b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_vlan.h new file mode 100644 index 0000000000..068bcb577b --- /dev/null +++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_vlan.h @@ -0,0 +1,57 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SNOOP_VLAN_H +#define _SNOOP_VLAN_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/ethernet.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The offset in bytes, in a VLAN tagged packet, from the + * ethernet header ethertype (which is ETHERTYPE_VLAN) to + * the encapsulated ethertype. + */ +#define ENCAP_ETHERTYPE_OFF (offsetof(struct ether_vlan_header, ether_type) -\ + offsetof(struct ether_vlan_header, ether_tpid)) + +/* + * The offset in bytes, from the beginning of an ethernet header, + * to the VLAN ID. + */ +#define VLAN_ID_OFFSET (offsetof(struct ether_vlan_header, ether_tci) -\ + offsetof(struct ether_vlan_header, ether_dhost)) + +#ifdef __cplusplus +} +#endif + +#endif /* _SNOOP_VLAN_H */ diff --git a/usr/src/pkgdefs/etc/exception_list_i386 b/usr/src/pkgdefs/etc/exception_list_i386 index c208110ff3..245922942f 100644 --- a/usr/src/pkgdefs/etc/exception_list_i386 +++ b/usr/src/pkgdefs/etc/exception_list_i386 @@ -501,6 +501,7 @@ usr/include/sys/dumpadm.h i386 usr/include/sys/ontrap.h i386 usr/include/sys/sysmsg_impl.h i386 usr/include/sys/cryptmod.h i386 +usr/include/sys/vlan.h i386 # # These files are installed in the proto area so lvm can use # them during the build process. diff --git a/usr/src/pkgdefs/etc/exception_list_sparc b/usr/src/pkgdefs/etc/exception_list_sparc index 2eeae9517a..565291281e 100644 --- a/usr/src/pkgdefs/etc/exception_list_sparc +++ b/usr/src/pkgdefs/etc/exception_list_sparc @@ -508,6 +508,7 @@ usr/include/sys/dumpadm.h sparc usr/include/sys/ontrap.h sparc usr/include/sys/sysmsg_impl.h sparc usr/include/sys/cryptmod.h sparc +usr/include/sys/vlan.h sparc # # These files are installed in the proto area so lvm can use # them during the build process. diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h index 7ff59d9b84..079b88d8e5 100644 --- a/usr/src/uts/common/inet/ip.h +++ b/usr/src/uts/common/inet/ip.h @@ -2968,6 +2968,8 @@ extern uint32_t ipsechw_debug; struct ipsec_out_s; +struct mac_header_info_s; + extern const char *dlpi_prim_str(int); extern const char *dlpi_err_str(int); extern void ill_frag_timer(void *); @@ -3002,7 +3004,8 @@ extern int ip_reassemble(mblk_t *, ipf_t *, uint_t, boolean_t, ill_t *, extern int ip_opt_set_ill(conn_t *, int, boolean_t, boolean_t, int, int, mblk_t *); extern void ip_rput(queue_t *, mblk_t *); -extern void ip_input(ill_t *, ill_rx_ring_t *, mblk_t *, size_t); +extern void ip_input(ill_t *, ill_rx_ring_t *, mblk_t *, + struct mac_header_info_s *); extern void ip_rput_dlpi(queue_t *, mblk_t *); extern void ip_rput_forward(ire_t *, ipha_t *, mblk_t *, ill_t *); extern void ip_rput_forward_multicast(ipaddr_t, mblk_t *, ipif_t *); @@ -3308,7 +3311,7 @@ extern int ip_squeue_bind_get(queue_t *, mblk_t *, caddr_t, cred_t *); extern void ip_squeue_clean(void *, mblk_t *, void *); extern void ip_resume_tcp_bind(void *, mblk_t *, void *); extern void ip_soft_ring_assignment(ill_t *, ill_rx_ring_t *, - mblk_t *, size_t); + mblk_t *, struct mac_header_info_s *); extern void tcp_wput(queue_t *, mblk_t *); diff --git a/usr/src/uts/common/inet/ip/ip.c b/usr/src/uts/common/inet/ip/ip.c index aa0d4f3ead..00a1e4275f 100644 --- a/usr/src/uts/common/inet/ip/ip.c +++ b/usr/src/uts/common/inet/ip/ip.c @@ -836,8 +836,6 @@ static int ip_conn_report(queue_t *, mblk_t *, caddr_t, cred_t *); static mblk_t *ip_tcp_input(mblk_t *, ipha_t *, ill_t *, boolean_t, ire_t *, mblk_t *, uint_t, queue_t *, ill_rx_ring_t *); -void ip_input(ill_t *, ill_rx_ring_t *, mblk_t *, size_t); - static void ip_rput_process_forward(queue_t *, mblk_t *, ire_t *, ipha_t *, ill_t *, boolean_t); @@ -14358,7 +14356,7 @@ ip_rput(queue_t *q, mblk_t *mp) TRACE_2(TR_FAC_IP, TR_IP_RPUT_END, "ip_rput_end: q %p (%S)", q, "end"); - ip_input(ill, NULL, mp, 0); + ip_input(ill, NULL, mp, NULL); } /* @@ -14369,10 +14367,19 @@ ip_rput(queue_t *q, mblk_t *mp) * * The ill will always be valid if this function is called directly from * the driver. + * + * If ip_input() is called from GLDv3: + * + * - This must be a non-VLAN IP stream. + * - 'mp' is either an untagged or a special priority-tagged packet. + * - Any VLAN tag that was in the MAC header has been stripped. + * + * Thus, there is no need to adjust b_rptr in this function. */ /* ARGSUSED */ void -ip_input(ill_t *ill, ill_rx_ring_t *ip_ring, mblk_t *mp_chain, size_t hdrlen) +ip_input(ill_t *ill, ill_rx_ring_t *ip_ring, mblk_t *mp_chain, + struct mac_header_info_s *mhip) { ipaddr_t dst = NULL; ipaddr_t prev_dst; diff --git a/usr/src/uts/common/inet/ip/ip_squeue.c b/usr/src/uts/common/inet/ip/ip_squeue.c index 417b1580eb..5c1da7c964 100644 --- a/usr/src/uts/common/inet/ip/ip_squeue.c +++ b/usr/src/uts/common/inet/ip/ip_squeue.c @@ -596,7 +596,7 @@ ip_squeue_soft_ring_affinity(void *arg) /* ARGSUSED */ void ip_soft_ring_assignment(ill_t *ill, ill_rx_ring_t *ip_ring, -mblk_t *mp_chain, size_t hdrlen) + mblk_t *mp_chain, struct mac_header_info_s *mhip) { ip_taskq_arg_t *taskq_arg; boolean_t refheld; @@ -645,7 +645,7 @@ mblk_t *mp_chain, size_t hdrlen) kmem_free(taskq_arg, sizeof (ip_taskq_arg_t)); out: - ip_input(ill, NULL, mp_chain, hdrlen); + ip_input(ill, NULL, mp_chain, mhip); } static squeue_t * diff --git a/usr/src/uts/common/io/aggr/aggr_send.c b/usr/src/uts/common/io/aggr/aggr_send.c index 9c13d1b50d..6c5787a297 100644 --- a/usr/src/uts/common/io/aggr/aggr_send.c +++ b/usr/src/uts/common/io/aggr/aggr_send.c @@ -84,7 +84,7 @@ aggr_send_port(aggr_grp_t *grp, mblk_t *mp) /* skip ethernet header */ - if (ntohs(ehp->ether_type) == VLAN_TPID) { + if (ntohs(ehp->ether_type) == ETHERTYPE_VLAN) { struct ether_vlan_header *evhp; ASSERT(MBLKL(mp) >= sizeof (struct ether_vlan_header)); diff --git a/usr/src/uts/common/io/bge/bge_recv2.c b/usr/src/uts/common/io/bge/bge_recv2.c index 8126e05b9a..8eea27b476 100644 --- a/usr/src/uts/common/io/bge/bge_recv2.c +++ b/usr/src/uts/common/io/bge/bge_recv2.c @@ -208,7 +208,7 @@ bge_receive_packet(bge_t *bgep, bge_rbd_t *hw_rbd_p) mp->b_rptr = dp = mp->b_rptr + BGE_HEADROOM - VLAN_TAGSZ; bcopy(DMA_VPTR(srbdp->pbuf), dp, 2 * ETHERADDRL); ehp = (struct ether_vlan_header *)dp; - ehp->ether_tpid = ntohs(VLAN_TPID); + ehp->ether_tpid = ntohs(ETHERTYPE_VLAN); ehp->ether_tci = ntohs(hw_rbd.vlan_tci); bcopy(((uchar_t *)(DMA_VPTR(srbdp->pbuf))) + 2 * ETHERADDRL, dp + 2 * ETHERADDRL + VLAN_TAGSZ, diff --git a/usr/src/uts/common/io/bge/bge_send.c b/usr/src/uts/common/io/bge/bge_send.c index d872b813c4..d886d19636 100644 --- a/usr/src/uts/common/io/bge/bge_send.c +++ b/usr/src/uts/common/io/bge/bge_send.c @@ -407,7 +407,7 @@ bge_send(bge_t *bgep, mblk_t *mp) ASSERT(MBLKL(mp) >= sizeof (struct ether_header)); ehp = (struct ether_vlan_header *)mp->b_rptr; - if (ehp->ether_tpid == htons(VLAN_TPID)) { + if (ehp->ether_tpid == htons(ETHERTYPE_VLAN)) { if (MBLKL(mp) < sizeof (struct ether_vlan_header)) { uint32_t pflags; diff --git a/usr/src/uts/common/io/dld/dld_proto.c b/usr/src/uts/common/io/dld/dld_proto.c index 467d55c2d1..3d5db8d82e 100644 --- a/usr/src/uts/common/io/dld/dld_proto.c +++ b/usr/src/uts/common/io/dld/dld_proto.c @@ -301,46 +301,35 @@ proto_info_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) dlp->dl_brdcst_addr_length = addr_length; } - /* - * We only support QoS information for VLAN interfaces. - */ - if (dsp->ds_vid != VLAN_ID_NONE) { - dlp->dl_qos_range_offset = (uintptr_t)rangep - (uintptr_t)dlp; - dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t); + dlp->dl_qos_range_offset = (uintptr_t)rangep - (uintptr_t)dlp; + dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t); - rangep->dl_qos_type = DL_QOS_CL_RANGE1; - rangep->dl_trans_delay.dl_target_value = DL_UNKNOWN; - rangep->dl_trans_delay.dl_accept_value = DL_UNKNOWN; - rangep->dl_protection.dl_min = DL_UNKNOWN; - rangep->dl_protection.dl_max = DL_UNKNOWN; - rangep->dl_residual_error = DL_UNKNOWN; + rangep->dl_qos_type = DL_QOS_CL_RANGE1; + rangep->dl_trans_delay.dl_target_value = DL_UNKNOWN; + rangep->dl_trans_delay.dl_accept_value = DL_UNKNOWN; + rangep->dl_protection.dl_min = DL_UNKNOWN; + rangep->dl_protection.dl_max = DL_UNKNOWN; + rangep->dl_residual_error = DL_UNKNOWN; - /* - * Specify the supported range of priorities. - */ - rangep->dl_priority.dl_min = 0; - rangep->dl_priority.dl_max = (1 << VLAN_PRI_SIZE) - 1; + /* + * Specify the supported range of priorities. + */ + rangep->dl_priority.dl_min = 0; + rangep->dl_priority.dl_max = (1 << VLAN_PRI_SIZE) - 1; - dlp->dl_qos_offset = (uintptr_t)selp - (uintptr_t)dlp; - dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t); + dlp->dl_qos_offset = (uintptr_t)selp - (uintptr_t)dlp; + dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t); - selp->dl_qos_type = DL_QOS_CL_SEL1; - selp->dl_trans_delay = DL_UNKNOWN; - selp->dl_protection = DL_UNKNOWN; - selp->dl_residual_error = DL_UNKNOWN; + selp->dl_qos_type = DL_QOS_CL_SEL1; + selp->dl_trans_delay = DL_UNKNOWN; + selp->dl_protection = DL_UNKNOWN; + selp->dl_residual_error = DL_UNKNOWN; - /* - * Specify the current priority (which can be changed by - * the DL_UDQOS_REQ primitive). - */ - selp->dl_priority = dsp->ds_pri; - } else { - /* - * Shorten the buffer to lose the unused QoS information - * structures. - */ - mp->b_wptr = (uint8_t *)rangep; - } + /* + * Specify the current priority (which can be changed by + * the DL_UDQOS_REQ primitive). + */ + selp->dl_priority = dsp->ds_pri; dlp->dl_addr_length = addr_length + sizeof (uint16_t); if (dsp->ds_dlstate == DL_IDLE) { @@ -1100,8 +1089,7 @@ proto_udqos_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) goto failed; } - if (dsp->ds_vid == VLAN_ID_NONE || - selp->dl_priority > (1 << VLAN_PRI_SIZE) - 1 || + if (selp->dl_priority > (1 << VLAN_PRI_SIZE) - 1 || selp->dl_priority < 0) { dl_err = DL_BADQOSPARAM; goto failed; @@ -1476,8 +1464,8 @@ proto_unitdata_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) /* * Build a packet header. */ - bp = dls_header(dsp->ds_dc, addr, sap, dsp->ds_pri, payload); - if (bp == NULL) { + if ((bp = dls_header(dsp->ds_dc, addr, sap, dlp->dl_priority.dl_max, + &payload)) == NULL) { dl_err = DL_BADADDR; goto failed; } @@ -1500,7 +1488,7 @@ proto_unitdata_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) ASSERT(bp->b_cont == NULL); bp->b_cont = payload; - str_mdata_fastpath_put(dsp, bp); + dld_tx_single(dsp, bp); rw_exit(&dsp->ds_lock); return (B_TRUE); failed: diff --git a/usr/src/uts/common/io/dld/dld_str.c b/usr/src/uts/common/io/dld/dld_str.c index 29ea09c260..d8335c4fe5 100644 --- a/usr/src/uts/common/io/dld/dld_str.c +++ b/usr/src/uts/common/io/dld/dld_str.c @@ -42,7 +42,7 @@ static int str_constructor(void *, void *, int); static void str_destructor(void *, void *); -static mblk_t *str_unitdata_ind(dld_str_t *, mblk_t *); +static mblk_t *str_unitdata_ind(dld_str_t *, mblk_t *, boolean_t); static void str_notify_promisc_on_phys(dld_str_t *); static void str_notify_promisc_off_phys(dld_str_t *); static void str_notify_phys_addr(dld_str_t *, const uint8_t *); @@ -58,6 +58,9 @@ static void ioc(dld_str_t *, mblk_t *); static void dld_ioc(dld_str_t *, mblk_t *); static minor_t dld_minor_hold(boolean_t); static void dld_minor_rele(minor_t); +static void str_mdata_raw_put(dld_str_t *, mblk_t *); +static mblk_t *i_dld_ether_header_update_tag(mblk_t *, uint_t, uint16_t); +static mblk_t *i_dld_ether_header_strip_tag(mblk_t *); static uint32_t str_count; static kmem_cache_t *str_cachep; @@ -79,8 +82,8 @@ static mod_hash_t *str_hashp; * the DL_CAPAB_POLL negotiation. The put procedure handles all control * and data operations, while the fast-path routine deals only with M_DATA * fast-path packets. Regardless of the entry point, all outbound packets - * will end up in str_mdata_fastpath_put(), where they will be delivered to - * the MAC driver. + * will end up in dld_tx_single(), where they will be delivered to the MAC + * driver. * * The transmit logic operates in two modes: a "not busy" mode where the * packets will be delivered to the MAC for a send attempt, or "busy" mode @@ -452,7 +455,7 @@ dld_wsrv(queue_t *wq) * Discard packets unless we are attached and bound; note that * the driver mode (fastpath/raw/unitdata) is irrelevant here, * because regardless of the mode all transmit will end up in - * str_mdata_fastpath_put() where the packets may be queued. + * dld_tx_single() where the packets may be queued. */ ASSERT(DB_TYPE(mp) == M_DATA); if (dsp->ds_dlstate != DL_IDLE) { @@ -786,10 +789,10 @@ str_destructor(void *buf, void *cdrarg) } /* - * M_DATA put (IP fast-path mode) + * M_DATA put. Note that mp is a single message, not a chained message. */ void -str_mdata_fastpath_put(dld_str_t *dsp, mblk_t *mp) +dld_tx_single(dld_str_t *dsp, mblk_t *mp) { /* * This function can be called from within dld or from an upper @@ -811,14 +814,133 @@ str_mdata_fastpath_put(dld_str_t *dsp, mblk_t *mp) } /* - * M_DATA put (raw mode) + * Update the priority bits and VID (may need to insert tag if mp points + * to an untagged packet. + * If vid is VLAN_ID_NONE, use the VID encoded in the packet. + */ +static mblk_t * +i_dld_ether_header_update_tag(mblk_t *mp, uint_t pri, uint16_t vid) +{ + mblk_t *hmp; + struct ether_vlan_header *evhp; + struct ether_header *ehp; + uint16_t old_tci = 0; + size_t len; + + ASSERT(pri != 0 || vid != VLAN_ID_NONE); + + evhp = (struct ether_vlan_header *)mp->b_rptr; + if (ntohs(evhp->ether_tpid) == ETHERTYPE_VLAN) { + /* + * Tagged packet, update the priority bits. + */ + old_tci = ntohs(evhp->ether_tci); + len = sizeof (struct ether_vlan_header); + + if ((DB_REF(mp) > 1) || (MBLKL(mp) < len)) { + /* + * In case some drivers only check the db_ref + * count of the first mblk, we pullup the + * message into a single mblk. + */ + hmp = msgpullup(mp, -1); + if ((hmp == NULL) || (MBLKL(hmp) < len)) { + freemsg(hmp); + return (NULL); + } else { + freemsg(mp); + mp = hmp; + } + } + + evhp = (struct ether_vlan_header *)mp->b_rptr; + } else { + /* + * Untagged packet. Insert the special priority tag. + * First allocate a header mblk. + */ + hmp = allocb(sizeof (struct ether_vlan_header), BPRI_MED); + if (hmp == NULL) + return (NULL); + + evhp = (struct ether_vlan_header *)hmp->b_rptr; + ehp = (struct ether_header *)mp->b_rptr; + + /* + * Copy the MAC addresses and typelen + */ + bcopy(ehp, evhp, (ETHERADDRL * 2)); + evhp->ether_type = ehp->ether_type; + evhp->ether_tpid = htons(ETHERTYPE_VLAN); + + hmp->b_wptr += sizeof (struct ether_vlan_header); + mp->b_rptr += sizeof (struct ether_header); + + /* + * Free the original message if it's now empty. Link the + * rest of messages to the header message. + */ + if (MBLKL(mp) == 0) { + hmp->b_cont = mp->b_cont; + freeb(mp); + } else { + hmp->b_cont = mp; + } + mp = hmp; + } + + if (pri == 0) + pri = VLAN_PRI(old_tci); + if (vid == VLAN_ID_NONE) + vid = VLAN_ID(old_tci); + evhp->ether_tci = htons(VLAN_TCI(pri, VLAN_CFI(old_tci), vid)); + return (mp); +} + +/* + * M_DATA put (IP fast-path mode) */ void +str_mdata_fastpath_put(dld_str_t *dsp, mblk_t *mp) +{ + boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER); + mblk_t *newmp; + uint_t pri; + + if (is_ethernet) { + /* + * Update the priority bits to the assigned priority. + */ + pri = (VLAN_MBLKPRI(mp) == 0) ? dsp->ds_pri : VLAN_MBLKPRI(mp); + + if (pri != 0) { + newmp = i_dld_ether_header_update_tag(mp, pri, + VLAN_ID_NONE); + if (newmp == NULL) + goto discard; + mp = newmp; + } + } + + dld_tx_single(dsp, mp); + return; + +discard: + /* TODO: bump kstat? */ + freemsg(mp); +} + +/* + * M_DATA put (DLIOCRAW mode) + */ +static void str_mdata_raw_put(dld_str_t *dsp, mblk_t *mp) { - mblk_t *bp, *newmp; - size_t size; - mac_header_info_t mhi; + boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER); + mblk_t *bp, *newmp; + size_t size; + mac_header_info_t mhi; + uint_t pri, vid; /* * Certain MAC type plugins provide an illusion for raw DLPI @@ -854,23 +976,43 @@ str_mdata_raw_put(dld_str_t *dsp, mblk_t *mp) if (size > dsp->ds_mip->mi_sdu_max + mhi.mhi_hdrsize) goto discard; - if (dsp->ds_mip->mi_media == DL_ETHER && mhi.mhi_origsap == VLAN_TPID) { - struct ether_vlan_header *evhp; + if (is_ethernet) { + /* + * Discard the packet if this is a VLAN stream but the VID in + * the packet is not correct. + */ + vid = VLAN_ID(mhi.mhi_tci); + if ((dsp->ds_vid != VLAN_ID_NONE) && (vid != VLAN_ID_NONE)) + goto discard; - if (size < sizeof (struct ether_vlan_header)) + /* + * Discard the packet if this packet is a tagged packet + * but both pri and VID are 0. + */ + pri = VLAN_PRI(mhi.mhi_tci); + if (mhi.mhi_istagged && (pri == 0) && (vid == VLAN_ID_NONE)) goto discard; + /* - * Replace vtag with our own + * Update the priority bits to the per-stream priority if + * priority is not set in the packet. Update the VID for + * packets on a VLAN stream. */ - evhp = (struct ether_vlan_header *)mp->b_rptr; - evhp->ether_tci = htons(VLAN_TCI(dsp->ds_pri, - ETHER_CFI, dsp->ds_vid)); + pri = (pri == 0) ? dsp->ds_pri : 0; + if ((pri != 0) || (dsp->ds_vid != VLAN_ID_NONE)) { + if ((newmp = i_dld_ether_header_update_tag(mp, + pri, dsp->ds_vid)) == NULL) { + goto discard; + } + mp = newmp; + } } - str_mdata_fastpath_put(dsp, mp); + dld_tx_single(dsp, mp); return; discard: + /* TODO: bump kstat? */ freemsg(mp); } @@ -979,15 +1121,56 @@ dld_str_detach(dld_str_t *dsp) } /* + * This function is only called for VLAN streams. In raw mode, we strip VLAN + * tags before sending packets up to the DLS clients, with the exception of + * special priority tagged packets, in that case, we set the VID to 0. + * mp must be a VLAN tagged packet. + */ +static mblk_t * +i_dld_ether_header_strip_tag(mblk_t *mp) +{ + mblk_t *newmp; + struct ether_vlan_header *evhp; + uint16_t tci, new_tci; + + ASSERT(MBLKL(mp) >= sizeof (struct ether_vlan_header)); + if (DB_REF(mp) > 1) { + newmp = copymsg(mp); + if (newmp == NULL) + return (NULL); + freemsg(mp); + mp = newmp; + } + evhp = (struct ether_vlan_header *)mp->b_rptr; + + tci = ntohs(evhp->ether_tci); + if (VLAN_PRI(tci) == 0) { + /* + * Priority is 0, strip the tag. + */ + ovbcopy(mp->b_rptr, mp->b_rptr + VLAN_TAGSZ, 2 * ETHERADDRL); + mp->b_rptr += VLAN_TAGSZ; + } else { + /* + * Priority is not 0, update the VID to 0. + */ + new_tci = VLAN_TCI(VLAN_PRI(tci), VLAN_CFI(tci), VLAN_ID_NONE); + evhp->ether_tci = htons(new_tci); + } + return (mp); +} + +/* * Raw mode receive function. */ /*ARGSUSED*/ void dld_str_rx_raw(void *arg, mac_resource_handle_t mrh, mblk_t *mp, - size_t header_length) + mac_header_info_t *mhip) { - dld_str_t *dsp = (dld_str_t *)arg; - mblk_t *next, *newmp; + dld_str_t *dsp = (dld_str_t *)arg; + boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER); + mblk_t *next, *newmp; ASSERT(mp != NULL); do { @@ -1001,8 +1184,8 @@ dld_str_rx_raw(void *arg, mac_resource_handle_t mrh, mblk_t *mp, /* * Wind back b_rptr to point at the MAC header. */ - ASSERT(mp->b_rptr >= DB_BASE(mp) + header_length); - mp->b_rptr -= header_length; + ASSERT(mp->b_rptr >= DB_BASE(mp) + mhip->mhi_hdrsize); + mp->b_rptr -= mhip->mhi_hdrsize; /* * Certain MAC type plugins provide an illusion for raw @@ -1017,24 +1200,22 @@ dld_str_rx_raw(void *arg, mac_resource_handle_t mrh, mblk_t *mp, */ if ((newmp = mac_header_uncook(dsp->ds_mh, mp)) == NULL) { freemsg(mp); - mp = next; - continue; + goto next; } mp = newmp; - if (dsp->ds_mip->mi_media == DL_ETHER) { - struct ether_header *ehp = - (struct ether_header *)mp->b_rptr; - - if (ntohs(ehp->ether_type) == VLAN_TPID) { - /* - * Strip off the vtag - */ - ovbcopy(mp->b_rptr, mp->b_rptr + VLAN_TAGSZ, - 2 * ETHERADDRL); - mp->b_rptr += VLAN_TAGSZ; + /* + * Strip the VLAN tag for VLAN streams. + */ + if (is_ethernet && dsp->ds_vid != VLAN_ID_NONE) { + newmp = i_dld_ether_header_strip_tag(mp); + if (newmp == NULL) { + freemsg(mp); + goto next; } + mp = newmp; } + /* * Pass the packet on. */ @@ -1043,6 +1224,7 @@ dld_str_rx_raw(void *arg, mac_resource_handle_t mrh, mblk_t *mp, else freemsg(mp); +next: /* * Move on to the next packet in the chain. */ @@ -1056,10 +1238,32 @@ dld_str_rx_raw(void *arg, mac_resource_handle_t mrh, mblk_t *mp, /*ARGSUSED*/ void dld_str_rx_fastpath(void *arg, mac_resource_handle_t mrh, mblk_t *mp, - size_t header_length) + mac_header_info_t *mhip) { - dld_str_t *dsp = (dld_str_t *)arg; - mblk_t *next; + dld_str_t *dsp = (dld_str_t *)arg; + mblk_t *next; + size_t offset = 0; + + /* + * MAC header stripping rules: + * - Tagged packets: + * a. VLAN streams. Strip the whole VLAN header including the tag. + * b. Physical streams + * - VLAN packets (non-zero VID). The stream must be either a + * DL_PROMISC_SAP listener or a ETHERTYPE_VLAN listener. + * Strip the Ethernet header but keep the VLAN header. + * - Special tagged packets (zero VID) + * * The stream is either a DL_PROMISC_SAP listener or a + * ETHERTYPE_VLAN listener, strip the Ethernet header but + * keep the VLAN header. + * * Otherwise, strip the whole VLAN header. + * - Untagged packets. Strip the whole MAC header. + */ + if (mhip->mhi_istagged && (dsp->ds_vid == VLAN_ID_NONE) && + ((dsp->ds_sap == ETHERTYPE_VLAN) || + (dsp->ds_promisc & DLS_PROMISC_SAP))) { + offset = VLAN_TAGSZ; + } ASSERT(mp != NULL); do { @@ -1071,6 +1275,12 @@ dld_str_rx_fastpath(void *arg, mac_resource_handle_t mrh, mblk_t *mp, mp->b_next = NULL; /* + * Wind back b_rptr to point at the VLAN header. + */ + ASSERT(mp->b_rptr >= DB_BASE(mp) + offset); + mp->b_rptr -= offset; + + /* * Pass the packet on. */ if (canputnext(dsp->ds_rq)) @@ -1090,11 +1300,23 @@ dld_str_rx_fastpath(void *arg, mac_resource_handle_t mrh, mblk_t *mp, /*ARGSUSED*/ void dld_str_rx_unitdata(void *arg, mac_resource_handle_t mrh, mblk_t *mp, - size_t header_length) + mac_header_info_t *mhip) { dld_str_t *dsp = (dld_str_t *)arg; mblk_t *ud_mp; mblk_t *next; + size_t offset = 0; + boolean_t strip_vlan = B_TRUE; + + /* + * See MAC header stripping rules in the dld_str_rx_fastpath() function. + */ + if (mhip->mhi_istagged && (dsp->ds_vid == VLAN_ID_NONE) && + ((dsp->ds_sap == ETHERTYPE_VLAN) || + (dsp->ds_promisc & DLS_PROMISC_SAP))) { + offset = VLAN_TAGSZ; + strip_vlan = B_FALSE; + } ASSERT(mp != NULL); do { @@ -1108,21 +1330,21 @@ dld_str_rx_unitdata(void *arg, mac_resource_handle_t mrh, mblk_t *mp, /* * Wind back b_rptr to point at the MAC header. */ - ASSERT(mp->b_rptr >= DB_BASE(mp) + header_length); - mp->b_rptr -= header_length; + ASSERT(mp->b_rptr >= DB_BASE(mp) + mhip->mhi_hdrsize); + mp->b_rptr -= mhip->mhi_hdrsize; /* * Create the DL_UNITDATA_IND M_PROTO. */ - if ((ud_mp = str_unitdata_ind(dsp, mp)) == NULL) { + if ((ud_mp = str_unitdata_ind(dsp, mp, strip_vlan)) == NULL) { freemsgchain(mp); return; } /* - * Advance b_rptr to point at the payload again. + * Advance b_rptr to point at the payload (or the VLAN header). */ - mp->b_rptr += header_length; + mp->b_rptr += (mhip->mhi_hdrsize - offset); /* * Prepend the DL_UNITDATA_IND. @@ -1167,7 +1389,7 @@ typedef struct dl_unitdata_ind_wrapper { * Create a DL_UNITDATA_IND M_PROTO message. */ static mblk_t * -str_unitdata_ind(dld_str_t *dsp, mblk_t *mp) +str_unitdata_ind(dld_str_t *dsp, mblk_t *mp, boolean_t strip_vlan) { mblk_t *nmp; dl_unitdata_ind_wrapper_t *dlwp; @@ -1207,9 +1429,12 @@ str_unitdata_ind(dld_str_t *dsp, mblk_t *mp) bcopy(mhi.mhi_daddr, daddr, addr_length); /* - * Set the destination DLSAP to our bound DLSAP value. + * Set the destination DLSAP to the SAP value encoded in the packet. */ - *(uint16_t *)(daddr + addr_length) = dsp->ds_sap; + if (mhi.mhi_istagged && !strip_vlan) + *(uint16_t *)(daddr + addr_length) = ETHERTYPE_VLAN; + else + *(uint16_t *)(daddr + addr_length) = mhi.mhi_bindsap; dlp->dl_dest_addr_length = addr_length + sizeof (uint16_t); /* @@ -1703,6 +1928,15 @@ ioc_fast(dld_str_t *dsp, mblk_t *mp) goto failed; } + /* + * DLIOCHDRINFO should only come from IP. The one initiated from + * user-land should not be allowed. + */ + if (((struct iocblk *)mp->b_rptr)->ioc_cr != kcred) { + err = EINVAL; + goto failed; + } + nmp = mp->b_cont; if (nmp == NULL || MBLKL(nmp) < sizeof (dl_unitdata_req_t) || (dlp = (dl_unitdata_req_t *)nmp->b_rptr, @@ -1737,7 +1971,7 @@ ioc_fast(dld_str_t *dsp, mblk_t *mp) sap = *(uint16_t *)(nmp->b_rptr + off + addr_length); dc = dsp->ds_dc; - if ((hmp = dls_header(dc, addr, sap, dsp->ds_pri, NULL)) == NULL) { + if ((hmp = dls_header(dc, addr, sap, 0, NULL)) == NULL) { rw_exit(&dsp->ds_lock); err = ENOMEM; goto failed; diff --git a/usr/src/uts/common/io/dls/dls.c b/usr/src/uts/common/io/dls/dls.c index 51456292d5..a8e1089776 100644 --- a/usr/src/uts/common/io/dls/dls.c +++ b/usr/src/uts/common/io/dls/dls.c @@ -602,42 +602,90 @@ done: mblk_t * dls_header(dls_channel_t dc, const uint8_t *addr, uint16_t sap, uint_t pri, - mblk_t *payload) + mblk_t **payloadp) { - dls_impl_t *dip = (dls_impl_t *)dc; - uint16_t vid; - size_t extra_len; - uint16_t mac_sap; - mblk_t *mp; + dls_impl_t *dip = (dls_impl_t *)dc; + uint16_t vid; + size_t extra_len; + uint16_t mac_sap; + mblk_t *mp, *payload; + boolean_t is_ethernet = (dip->di_mip->mi_media == DL_ETHER); struct ether_vlan_header *evhp; vid = dip->di_dvp->dv_id; - if (vid != VLAN_ID_NONE) { - /* - * We know ahead of time that we'll need to fill in - * additional VLAN information in the link-layer header. - * We will tell the MAC layer to pre-allocate some space at - * the end of the Ethernet header for us. - */ - ASSERT(dip->di_mip->mi_media == DL_ETHER); + payload = (payloadp == NULL) ? NULL : (*payloadp); + + /* + * If the following conditions are satisfied: + * - This is not a ETHERTYPE_VLAN listener; and + * - This is either a VLAN stream or this is a physical stream + * but the priority is not 0. + * + * then we know ahead of time that we'll need to fill in additional + * VLAN information in the link-layer header. We will tell the MAC + * layer to pre-allocate some space at the end of the Ethernet + * header for us. + */ + if (is_ethernet && sap != ETHERTYPE_VLAN && + (vid != VLAN_ID_NONE || pri != 0)) { extra_len = sizeof (struct ether_vlan_header) - sizeof (struct ether_header); - mac_sap = VLAN_TPID; + mac_sap = ETHERTYPE_VLAN; } else { extra_len = 0; mac_sap = sap; } mp = mac_header(dip->di_mh, addr, mac_sap, payload, extra_len); - if (vid == VLAN_ID_NONE || mp == NULL) + if (mp == NULL) + return (NULL); + + if ((vid == VLAN_ID_NONE && pri == 0) || !is_ethernet) return (mp); - /* This is an Ethernet VLAN link. Fill in the VLAN information */ + /* + * Fill in the tag information. + */ ASSERT(MBLKL(mp) == sizeof (struct ether_header)); - mp->b_wptr += extra_len; - evhp = (struct ether_vlan_header *)mp->b_rptr; - evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid)); - evhp->ether_type = htons(sap); + if (extra_len != 0) { + mp->b_wptr += extra_len; + evhp = (struct ether_vlan_header *)mp->b_rptr; + evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid)); + evhp->ether_type = htons(sap); + } else { + /* + * The stream is ETHERTYPE_VLAN listener, so its VLAN tag is + * in the payload. Update the priority. + */ + struct ether_vlan_extinfo *extinfo; + size_t len = sizeof (struct ether_vlan_extinfo); + + ASSERT(sap == ETHERTYPE_VLAN); + ASSERT(payload != NULL); + + if ((DB_REF(payload) > 1) || (MBLKL(payload) < len)) { + mblk_t *newmp; + + /* + * Because some DLS consumers only check the db_ref + * count of the first mblk, we pullup 'payload' into + * a single mblk. + */ + newmp = msgpullup(payload, -1); + if ((newmp == NULL) || (MBLKL(newmp) < len)) { + freemsg(newmp); + freemsg(mp); + return (NULL); + } else { + freemsg(payload); + *payloadp = payload = newmp; + } + } + + extinfo = (struct ether_vlan_extinfo *)payload->b_rptr; + extinfo->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, + VLAN_ID(ntohs(extinfo->ether_tci)))); + } return (mp); } @@ -645,7 +693,7 @@ int dls_header_info(dls_channel_t dc, mblk_t *mp, mac_header_info_t *mhip) { return (dls_link_header_info(((dls_impl_t *)dc)->di_dvp->dv_dlp, - mp, mhip, NULL)); + mp, mhip)); } void @@ -738,8 +786,10 @@ accept: return (B_TRUE); } +/* ARGSUSED */ boolean_t -dls_accept_loopback(dls_impl_t *dip, dls_rx_t *di_rx, void **di_rx_arg) +dls_accept_loopback(dls_impl_t *dip, mac_header_info_t *mhip, dls_rx_t *di_rx, + void **di_rx_arg) { /* * We must not accept packets if the dls_impl_t is not marked as bound diff --git a/usr/src/uts/common/io/dls/dls_link.c b/usr/src/uts/common/io/dls/dls_link.c index 47b0d99169..19e2f12976 100644 --- a/usr/src/uts/common/io/dls/dls_link.c +++ b/usr/src/uts/common/io/dls/dls_link.c @@ -119,51 +119,70 @@ i_dls_link_destructor(void *buf, void *arg) } /* + * - Parse the mac header information of the given packet. + * - Strip the padding and skip over the header. Note that because some + * DLS consumers only check the db_ref count of the first mblk, we + * pullup the message into a single mblk. The dls_link_header_info() + * function ensures that the size of the pulled message is greater + * than the MAC header size. + * + * We choose to use a macro for performance reasons. + */ +#define DLS_PREPARE_PKT(dlp, mp, mhip, err) { \ + mblk_t *nextp = (mp)->b_next; \ + if (((err) = dls_link_header_info((dlp), (mp), (mhip))) == 0) { \ + DLS_STRIP_PADDING((mhip)->mhi_pktsize, (mp)); \ + if (MBLKL((mp)) < (mhip)->mhi_hdrsize) { \ + mblk_t *newmp; \ + if ((newmp = msgpullup((mp), -1)) == NULL) { \ + (err) = EINVAL; \ + } else { \ + freemsg((mp)); \ + (mp) = newmp; \ + (mp)->b_next = nextp; \ + (mp)->b_rptr += (mhip)->mhi_hdrsize; \ + } \ + } else { \ + (mp)->b_rptr += (mhip)->mhi_hdrsize; \ + } \ + } \ +} + +/* * Truncate the chain starting at mp such that all packets in the chain - * have identical source and destination addresses, saps, and VLAN tags (if - * any). It returns a pointer to the mblk following the chain, NULL if - * there is no further packet following the processed chain. The countp - * argument is set to the number of valid packets in the chain. It is set - * to 0 if the function encountered a problem with the first packet. + * have identical source and destination addresses, saps, and tag types + * (see below). It returns a pointer to the mblk following the chain, + * NULL if there is no further packet following the processed chain. + * The countp argument is set to the number of valid packets in the chain. + * Note that the whole MAC header (including the VLAN tag if any) in each + * packet will be stripped. */ static mblk_t * -i_dls_link_subchain(dls_link_t *dlp, mblk_t *mp, mac_header_info_t *mhip, - uint16_t *vidp, uint_t *countp) +i_dls_link_subchain(dls_link_t *dlp, mblk_t *mp, const mac_header_info_t *mhip, + uint_t *countp) { - mblk_t **pp; - mblk_t *p; - uint_t npacket; + mblk_t *prevp; + uint_t npacket = 1; size_t addr_size = dlp->dl_mip->mi_addr_length; - - /* - * Packets should always be at least 16 bit aligned. - */ - ASSERT(IS_P2ALIGNED(mp->b_rptr, sizeof (uint16_t))); - - if (dls_link_header_info(dlp, mp, mhip, vidp) != 0) { - /* - * Something is wrong with the initial header. No chain is - * possible. - */ - p = mp->b_next; - mp->b_next = NULL; - *countp = 0; - return (p); - } + uint16_t vid = VLAN_ID(mhip->mhi_tci); + uint16_t pri = VLAN_PRI(mhip->mhi_tci); /* * Compare with subsequent headers until we find one that has * differing header information. After checking each packet * strip padding and skip over the header. */ - npacket = 1; - for (pp = &(mp->b_next); (p = *pp) != NULL; pp = &(p->b_next)) { + for (prevp = mp; (mp = mp->b_next) != NULL; prevp = mp) { mac_header_info_t cmhi; - uint16_t cvid; + uint16_t cvid, cpri; + int err; - if (dls_link_header_info(dlp, p, &cmhi, &cvid) != 0) + DLS_PREPARE_PKT(dlp, mp, &cmhi, err); + if (err != 0) break; + prevp->b_next = mp; + /* * The source, destination, sap, and vlan id must all match * in a given subchain. @@ -171,30 +190,46 @@ i_dls_link_subchain(dls_link_t *dlp, mblk_t *mp, mac_header_info_t *mhip, if (memcmp(mhip->mhi_daddr, cmhi.mhi_daddr, addr_size) != 0 || memcmp(mhip->mhi_saddr, cmhi.mhi_saddr, addr_size) != 0 || mhip->mhi_bindsap != cmhi.mhi_bindsap) { + /* + * Note that we don't need to restore the padding. + */ + mp->b_rptr -= cmhi.mhi_hdrsize; break; } - if (cvid != *vidp) + cvid = VLAN_ID(cmhi.mhi_tci); + cpri = VLAN_PRI(cmhi.mhi_tci); + + /* + * There are several types of packets. Packets don't match + * if they are classified to different type or if they are + * VLAN packets but belong to different VLANs: + * + * packet type tagged vid pri + * --------------------------------------------------------- + * untagged No zero zero + * VLAN packets Yes non-zero - + * priority tagged Yes zero non-zero + * 0 tagged Yes zero zero + */ + if ((mhip->mhi_istagged != cmhi.mhi_istagged) || + (vid != cvid) || ((vid == VLAN_ID_NONE) && + (((pri == 0) && (cpri != 0)) || + ((pri != 0) && (cpri == 0))))) { + mp->b_rptr -= cmhi.mhi_hdrsize; break; + } - DLS_STRIP_PADDING(cmhi.mhi_pktsize, p); - p->b_rptr += cmhi.mhi_hdrsize; npacket++; } /* - * Strip padding and skip over the initial packet's header. - */ - DLS_STRIP_PADDING(mhip->mhi_pktsize, mp); - mp->b_rptr += mhip->mhi_hdrsize; - - /* * Break the chain at this point and return a pointer to the next * sub-chain. */ - *pp = NULL; + prevp->b_next = NULL; *countp = npacket; - return (p); + return (mp); } static void @@ -226,156 +261,80 @@ i_dls_head_free(dls_head_t *dhp) kmem_free(dhp, sizeof (dls_head_t)); } -static void -i_dls_link_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp) +/* + * Try to send mp up to the streams of the given sap and vid. Return B_TRUE + * if this message is sent to any streams. + * Note that this function will copy the message chain and the original + * mp will remain valid after this function + */ +static uint_t +i_dls_link_rx_func(dls_link_t *dlp, mac_resource_handle_t mrh, + mac_header_info_t *mhip, mblk_t *mp, uint32_t sap, uint16_t vid, + boolean_t (*acceptfunc)()) { - dls_link_t *dlp = arg; - mod_hash_t *hash = dlp->dl_impl_hash; - mblk_t *nextp; - mac_header_info_t mhi; - uint16_t vid; - dls_head_t *dhp; - dls_impl_t *dip; - dls_impl_t *ndip; - mblk_t *nmp; - mod_hash_key_t key; - uint_t npacket; - boolean_t accepted; - dls_rx_t di_rx, ndi_rx; - void *di_rx_arg, *ndi_rx_arg; + mod_hash_t *hash = dlp->dl_impl_hash; + mod_hash_key_t key; + dls_head_t *dhp; + dls_impl_t *dip; + mblk_t *nmp; + dls_rx_t di_rx; + void *di_rx_arg; + uint_t naccepted = 0; /* - * Walk the packet chain. + * Construct a hash key from the VLAN identifier and the + * DLSAP that represents dls_impl_t in promiscuous mode. */ - while (mp != NULL) { - /* - * Wipe the accepted state. - */ - accepted = B_FALSE; - - /* - * Grab the longest sub-chain we can process as a single - * unit. - */ - nextp = i_dls_link_subchain(dlp, mp, &mhi, &vid, &npacket); - - if (npacket == 0) { - /* - * The first packet had an unrecognized header. - * Modify npacket so that this stray can be - * accounted for. - */ - npacket = 1; - freemsg(mp); - goto loop; - } - - /* - * Construct a hash key from the VLAN identifier and the - * DLSAP. - */ - key = MAKE_KEY(mhi.mhi_bindsap, vid); + key = MAKE_KEY(sap, vid); - /* - * Search the has table for dls_impl_t eligible to receive - * a packet chain for this DLSAP/VLAN combination. - */ - rw_enter(&dlp->dl_impl_lock, RW_READER); - if (mod_hash_find(hash, key, (mod_hash_val_t *)&dhp) != 0) { - rw_exit(&dlp->dl_impl_lock); - freemsgchain(mp); - goto loop; - } - i_dls_head_hold(dhp); + /* + * Search the hash table for dls_impl_t eligible to receive + * a packet chain for this DLSAP/VLAN combination. + */ + rw_enter(&dlp->dl_impl_lock, RW_READER); + if (mod_hash_find(hash, key, (mod_hash_val_t *)&dhp) != 0) { rw_exit(&dlp->dl_impl_lock); + return (B_FALSE); + } + i_dls_head_hold(dhp); + rw_exit(&dlp->dl_impl_lock); - /* - * Find the first dls_impl_t that will accept the sub-chain. - */ - for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp) - if (dls_accept(dip, &mhi, &di_rx, &di_rx_arg)) - break; - - /* - * If we did not find any dls_impl_t willing to accept the - * sub-chain then throw it away. - */ - if (dip == NULL) { - i_dls_head_rele(dhp); - freemsgchain(mp); - goto loop; - } + /* + * Find dls_impl_t that will accept the sub-chain. + */ + for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp) { + if (!acceptfunc(dip, mhip, &di_rx, &di_rx_arg)) + continue; /* * We have at least one acceptor. */ - accepted = B_TRUE; - for (;;) { - /* - * Find the next dls_impl_t that will accept the - * sub-chain. - */ - for (ndip = dip->di_nextp; ndip != NULL; - ndip = ndip->di_nextp) - if (dls_accept(ndip, &mhi, &ndi_rx, - &ndi_rx_arg)) - break; - - /* - * If there are no more dls_impl_t that are willing - * to accept the sub-chain then we don't need to dup - * it before handing it to the current one. - */ - if (ndip == NULL) { - di_rx(di_rx_arg, mrh, mp, mhi.mhi_hdrsize); - - /* - * Since there are no more dls_impl_t, we're - * done. - */ - break; - } - - /* - * There are more dls_impl_t so dup the sub-chain. - */ - if ((nmp = copymsgchain(mp)) != NULL) - di_rx(di_rx_arg, mrh, nmp, mhi.mhi_hdrsize); - - dip = ndip; - di_rx = ndi_rx; - di_rx_arg = ndi_rx_arg; - } - - /* - * Release the hold on the dls_impl_t chain now that we have - * finished walking it. - */ - i_dls_head_rele(dhp); - -loop: - /* - * If there were no acceptors then add the packet count to the - * 'unknown' count. - */ - if (!accepted) - atomic_add_32(&(dlp->dl_unknowns), npacket); + naccepted ++; /* - * Move onto the next sub-chain. + * There will normally be at least more dls_impl_t + * (since we've yet to check for non-promiscuous + * dls_impl_t) so dup the sub-chain. */ - mp = nextp; + if ((nmp = copymsgchain(mp)) != NULL) + di_rx(di_rx_arg, mrh, nmp, mhip); } + + /* + * Release the hold on the dls_impl_t chain now that we have + * finished walking it. + */ + i_dls_head_rele(dhp); + return (naccepted); } static void -i_dls_link_rx_promisc(void *arg, mac_resource_handle_t mrh, mblk_t *mp) +i_dls_link_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp) { dls_link_t *dlp = arg; mod_hash_t *hash = dlp->dl_impl_hash; mblk_t *nextp; mac_header_info_t mhi; - uint16_t vid; dls_head_t *dhp; dls_impl_t *dip; dls_impl_t *ndip; @@ -385,80 +344,64 @@ i_dls_link_rx_promisc(void *arg, mac_resource_handle_t mrh, mblk_t *mp) boolean_t accepted; dls_rx_t di_rx, ndi_rx; void *di_rx_arg, *ndi_rx_arg; + uint16_t vid; + int err; /* * Walk the packet chain. */ - while (mp != NULL) { + for (; mp != NULL; mp = nextp) { /* * Wipe the accepted state. */ accepted = B_FALSE; - /* - * Grab the longest sub-chain we can process as a single - * unit. - */ - nextp = i_dls_link_subchain(dlp, mp, &mhi, &vid, &npacket); - - if (npacket == 0) { - /* - * The first packet had an unrecognized header. - * Modify npacket so that this stray can be - * accounted for. - */ - npacket = 1; + DLS_PREPARE_PKT(dlp, mp, &mhi, err); + if (err != 0) { + atomic_add_32(&(dlp->dl_unknowns), 1); + nextp = mp->b_next; freemsg(mp); - goto loop; + continue; } /* - * Construct a hash key from the VLAN identifier and the - * DLSAP that represents dls_impl_t in promiscuous mode. + * Grab the longest sub-chain we can process as a single + * unit. */ - key = MAKE_KEY(DLS_SAP_PROMISC, vid); + nextp = i_dls_link_subchain(dlp, mp, &mhi, &npacket); + ASSERT(npacket != 0); - /* - * Search the has table for dls_impl_t eligible to receive - * a packet chain for this DLSAP/VLAN combination. - */ - rw_enter(&dlp->dl_impl_lock, RW_READER); - if (mod_hash_find(hash, key, (mod_hash_val_t *)&dhp) != 0) { - rw_exit(&dlp->dl_impl_lock); - goto non_promisc; - } - i_dls_head_hold(dhp); - rw_exit(&dlp->dl_impl_lock); - - /* - * Find dls_impl_t that will accept the sub-chain. - */ - for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp) { - if (!dls_accept(dip, &mhi, &di_rx, &di_rx_arg)) - continue; + vid = VLAN_ID(mhi.mhi_tci); + if (mhi.mhi_istagged) { /* - * We have at least one acceptor. + * If it is tagged traffic, send it upstream to + * all dls_impl_t which are attached to the physical + * link and bound to SAP 0x8100. */ - accepted = B_TRUE; + if (i_dls_link_rx_func(dlp, mrh, &mhi, mp, + ETHERTYPE_VLAN, VLAN_ID_NONE, dls_accept) > 0) { + accepted = B_TRUE; + } /* - * There will normally be at least more dls_impl_t - * (since we've yet to check for non-promiscuous - * dls_impl_t) so dup the sub-chain. + * Don't pass the packets up if they are tagged + * packets and: + * - their VID and priority are both zero (invalid + * packets). + * - their sap is ETHERTYPE_VLAN and their VID is + * zero as they have already been sent upstreams. */ - if ((nmp = copymsgchain(mp)) != NULL) - di_rx(di_rx_arg, mrh, nmp, mhi.mhi_hdrsize); + if ((vid == VLAN_ID_NONE && + VLAN_PRI(mhi.mhi_tci) == 0) || + (mhi.mhi_bindsap == ETHERTYPE_VLAN && + vid == VLAN_ID_NONE)) { + freemsgchain(mp); + goto loop; + } } /* - * Release the hold on the dls_impl_t chain now that we have - * finished walking it. - */ - i_dls_head_rele(dhp); - -non_promisc: - /* * Construct a hash key from the VLAN identifier and the * DLSAP. */ @@ -515,7 +458,7 @@ non_promisc: * it before handing it to the current one. */ if (ndip == NULL) { - di_rx(di_rx_arg, mrh, mp, mhi.mhi_hdrsize); + di_rx(di_rx_arg, mrh, mp, &mhi); /* * Since there are no more dls_impl_t, we're @@ -528,7 +471,7 @@ non_promisc: * There are more dls_impl_t so dup the sub-chain. */ if ((nmp = copymsgchain(mp)) != NULL) - di_rx(di_rx_arg, mrh, nmp, mhi.mhi_hdrsize); + di_rx(di_rx_arg, mrh, nmp, &mhi); dip = ndip; di_rx = ndi_rx; @@ -548,92 +491,112 @@ loop: */ if (!accepted) atomic_add_32(&(dlp->dl_unknowns), npacket); + } +} - /* - * Move onto the next sub-chain. - */ - mp = nextp; +/* + * Try to send mp up to the DLS_SAP_PROMISC listeners. Return B_TRUE if this + * message is sent to any streams. + */ +static uint_t +i_dls_link_rx_common_promisc(dls_link_t *dlp, mac_resource_handle_t mrh, + mac_header_info_t *mhip, mblk_t *mp, uint16_t vid, + boolean_t (*acceptfunc)()) +{ + uint_t naccepted; + + naccepted = i_dls_link_rx_func(dlp, mrh, mhip, mp, DLS_SAP_PROMISC, + vid, acceptfunc); + + if (vid != VLAN_ID_NONE) { + naccepted += i_dls_link_rx_func(dlp, mrh, mhip, mp, + DLS_SAP_PROMISC, VLAN_ID_NONE, acceptfunc); } + return (naccepted); } static void -i_dls_link_txloop(void *arg, mblk_t *mp) +i_dls_link_rx_common(void *arg, mac_resource_handle_t mrh, mblk_t *mp, + boolean_t (*acceptfunc)()) { dls_link_t *dlp = arg; mod_hash_t *hash = dlp->dl_impl_hash; mblk_t *nextp; mac_header_info_t mhi; - uint16_t vid; + uint16_t vid, vidkey, pri; dls_head_t *dhp; dls_impl_t *dip; - dls_impl_t *ndip; mblk_t *nmp; mod_hash_key_t key; uint_t npacket; - dls_rx_t di_rx, ndi_rx; - void *di_rx_arg, *ndi_rx_arg; + uint32_t sap; + boolean_t accepted; + dls_rx_t di_rx, fdi_rx; + void *di_rx_arg, *fdi_rx_arg; + boolean_t pass2; + int err; /* * Walk the packet chain. */ - while (mp != NULL) { + for (; mp != NULL; mp = nextp) { /* - * Grab the longest sub-chain we can process as a single - * unit. + * Wipe the accepted state and the receive information of + * the first eligible dls_impl_t. */ - nextp = i_dls_link_subchain(dlp, mp, &mhi, &vid, &npacket); - - if (npacket == 0) { + accepted = B_FALSE; + pass2 = B_FALSE; + fdi_rx = NULL; + fdi_rx_arg = NULL; + + DLS_PREPARE_PKT(dlp, mp, &mhi, err); + if (err != 0) { + if (acceptfunc == dls_accept) + atomic_add_32(&(dlp->dl_unknowns), 1); + nextp = mp->b_next; freemsg(mp); - goto loop; + continue; } /* - * Construct a hash key from the VLAN identifier and the - * DLSAP. + * Grab the longest sub-chain we can process as a single + * unit. */ - key = MAKE_KEY(mhi.mhi_bindsap, vid); + nextp = i_dls_link_subchain(dlp, mp, &mhi, &npacket); + ASSERT(npacket != 0); - /* - * Search the has table for dls_impl_t eligible to receive - * a packet chain for this DLSAP/VLAN combination. - */ - rw_enter(&dlp->dl_impl_lock, RW_READER); - if (mod_hash_find(hash, key, (mod_hash_val_t *)&dhp) != 0) { - rw_exit(&dlp->dl_impl_lock); - goto promisc; - } - i_dls_head_hold(dhp); - rw_exit(&dlp->dl_impl_lock); + vid = VLAN_ID(mhi.mhi_tci); + pri = VLAN_PRI(mhi.mhi_tci); + + vidkey = vid; /* - * Find dls_impl_t that will accept the sub-chain. + * Note that we need to first send to the dls_impl_t + * in promiscuous mode in order to avoid the packet reordering + * when snooping. */ - for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp) { - if (!dls_accept_loopback(dip, &di_rx, &di_rx_arg)) - continue; - - /* - * There should be at least more dls_impl_t (since - * we've yet to check for dls_impl_t in promiscuous - * mode) so dup the sub-chain. - */ - if ((nmp = copymsgchain(mp)) != NULL) - di_rx(di_rx_arg, NULL, nmp, mhi.mhi_hdrsize); + if (i_dls_link_rx_common_promisc(dlp, mrh, &mhi, mp, vidkey, + acceptfunc) > 0) { + accepted = B_TRUE; } /* - * Release the hold on the dls_impl_t chain now that we have - * finished walking it. + * Non promisc case. Two passes: + * 1. send tagged packets to ETHERTYPE_VLAN listeners + * 2. send packets to listeners bound to the specific SAP. */ - i_dls_head_rele(dhp); - -promisc: + if (mhi.mhi_istagged) { + vidkey = VLAN_ID_NONE; + sap = ETHERTYPE_VLAN; + } else { + goto non_promisc_loop; + } +non_promisc: /* * Construct a hash key from the VLAN identifier and the - * DLSAP that represents dls_impl_t in promiscuous mode. + * DLSAP. */ - key = MAKE_KEY(DLS_SAP_PROMISC, vid); + key = MAKE_KEY(sap, vidkey); /* * Search the has table for dls_impl_t eligible to receive @@ -642,8 +605,7 @@ promisc: rw_enter(&dlp->dl_impl_lock, RW_READER); if (mod_hash_find(hash, key, (mod_hash_val_t *)&dhp) != 0) { rw_exit(&dlp->dl_impl_lock); - freemsgchain(mp); - goto loop; + goto non_promisc_loop; } i_dls_head_hold(dhp); rw_exit(&dlp->dl_impl_lock); @@ -651,56 +613,25 @@ promisc: /* * Find the first dls_impl_t that will accept the sub-chain. */ - for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp) - if (dls_accept_loopback(dip, &di_rx, &di_rx_arg)) - break; - - /* - * If we did not find any dls_impl_t willing to accept the - * sub-chain then throw it away. - */ - if (dip == NULL) { - i_dls_head_rele(dhp); - freemsgchain(mp); - goto loop; - } + for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp) { + if (!acceptfunc(dip, &mhi, &di_rx, &di_rx_arg)) + continue; - for (;;) { - /* - * Find the next dls_impl_t that will accept the - * sub-chain. - */ - for (ndip = dip->di_nextp; ndip != NULL; - ndip = ndip->di_nextp) - if (dls_accept_loopback(ndip, &ndi_rx, - &ndi_rx_arg)) { - break; - } + accepted = B_TRUE; /* - * If there are no more dls_impl_t that are willing - * to accept the sub-chain then we don't need to dup - * it before handing it to the current one. + * To avoid the extra copymsgchain(), if this + * is the first eligible dls_impl_t, remember required + * information and send up the message afterwards. */ - if (ndip == NULL) { - di_rx(di_rx_arg, NULL, mp, mhi.mhi_hdrsize); - - /* - * Since there are no more dls_impl_t, we're - * done. - */ - break; + if (fdi_rx == NULL) { + fdi_rx = di_rx; + fdi_rx_arg = di_rx_arg; + continue; } - /* - * There are more dls_impl_t so dup the sub-chain. - */ if ((nmp = copymsgchain(mp)) != NULL) - di_rx(di_rx_arg, NULL, nmp, mhi.mhi_hdrsize); - - dip = ndip; - di_rx = ndi_rx; - di_rx_arg = ndi_rx_arg; + di_rx(di_rx_arg, mrh, nmp, &mhi); } /* @@ -709,14 +640,54 @@ promisc: */ i_dls_head_rele(dhp); -loop: +non_promisc_loop: + /* + * Don't pass the packets up again if: + * - First pass is done and the packets are tagged and their: + * - VID and priority are both zero (invalid packets). + * - their sap is ETHERTYPE_VLAN and their VID is zero + * (they have already been sent upstreams). + * - Second pass is done: + */ + if (pass2 || (mhi.mhi_istagged && + ((vid == VLAN_ID_NONE && pri == 0) || + (mhi.mhi_bindsap == ETHERTYPE_VLAN && + vid == VLAN_ID_NONE)))) { + /* + * Send the message up to the first eligible dls_impl_t. + */ + if (fdi_rx != NULL) + fdi_rx(fdi_rx_arg, mrh, mp, &mhi); + else + freemsgchain(mp); + } else { + vidkey = vid; + sap = mhi.mhi_bindsap; + pass2 = B_TRUE; + goto non_promisc; + } + /* - * Move onto the next sub-chain. + * If there were no acceptors then add the packet count to the + * 'unknown' count. */ - mp = nextp; + if (!accepted && (acceptfunc == dls_accept)) + atomic_add_32(&(dlp->dl_unknowns), npacket); } } +static void +i_dls_link_rx_promisc(void *arg, mac_resource_handle_t mrh, mblk_t *mp) +{ + i_dls_link_rx_common(arg, mrh, mp, dls_accept); +} + +static void +i_dls_link_txloop(void *arg, mblk_t *mp) +{ + i_dls_link_rx_common(arg, NULL, mp, dls_accept_loopback); +} + /*ARGSUSED*/ static uint_t i_dls_link_walk(mod_hash_key_t key, mod_hash_val_t *val, void *arg) @@ -1125,32 +1096,55 @@ dls_link_remove(dls_link_t *dlp, dls_impl_t *dip) } int -dls_link_header_info(dls_link_t *dlp, mblk_t *mp, mac_header_info_t *mhip, - uint16_t *vidp) +dls_link_header_info(dls_link_t *dlp, mblk_t *mp, mac_header_info_t *mhip) { boolean_t is_ethernet = (dlp->dl_mip->mi_media == DL_ETHER); int err = 0; + /* + * Packets should always be at least 16 bit aligned. + */ + ASSERT(IS_P2ALIGNED(mp->b_rptr, sizeof (uint16_t))); + if ((err = mac_header_info(dlp->dl_mh, mp, mhip)) != 0) return (err); /* * If this is a VLAN-tagged Ethernet packet, then the SAP in the - * mac_header_info_t as returned by mac_header_info() is VLAN_TPID. - * We need to grab the ethertype from the VLAN header. + * mac_header_info_t as returned by mac_header_info() is + * ETHERTYPE_VLAN. We need to grab the ethertype from the VLAN header. */ - if (is_ethernet && (mhip->mhi_bindsap == VLAN_TPID)) { + if (is_ethernet && (mhip->mhi_bindsap == ETHERTYPE_VLAN)) { struct ether_vlan_header *evhp; uint16_t sap; + mblk_t *tmp = NULL; + size_t size; + + size = sizeof (struct ether_vlan_header); + if (MBLKL(mp) < size) { + /* + * Pullup the message in order to get the MAC header + * infomation. Note that this is a read-only function, + * we keep the input packet intact. + */ + if ((tmp = msgpullup(mp, size)) == NULL) + return (EINVAL); + mp = tmp; + } evhp = (struct ether_vlan_header *)mp->b_rptr; sap = ntohs(evhp->ether_type); (void) mac_sap_verify(dlp->dl_mh, sap, &mhip->mhi_bindsap); mhip->mhi_hdrsize = sizeof (struct ether_vlan_header); - if (vidp != NULL) - *vidp = VLAN_ID(ntohs(evhp->ether_tci)); - } else if (vidp != NULL) { - *vidp = VLAN_ID_NONE; + mhip->mhi_tci = ntohs(evhp->ether_tci); + mhip->mhi_istagged = B_TRUE; + freemsg(tmp); + + if (VLAN_CFI(mhip->mhi_tci) != ETHER_CFI) + return (EINVAL); + } else { + mhip->mhi_istagged = B_FALSE; + mhip->mhi_tci = 0; } return (0); } diff --git a/usr/src/uts/common/io/dls/dls_soft_ring.c b/usr/src/uts/common/io/dls/dls_soft_ring.c index cfd75e724a..56c79edb1c 100644 --- a/usr/src/uts/common/io/dls/dls_soft_ring.c +++ b/usr/src/uts/common/io/dls/dls_soft_ring.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -371,7 +370,7 @@ soft_ring_process(soft_ring_t *ringp, mblk_t *mp_chain, uint8_t tag) arg2 = ringp->s_ring_upcall_arg2; mutex_exit(&ringp->s_ring_lock); - (*proc)(arg1, arg2, mp_chain, -1); + (*proc)(arg1, arg2, mp_chain, NULL); ASSERT(MUTEX_NOT_HELD(&ringp->s_ring_lock)); mutex_enter(&ringp->s_ring_lock); @@ -481,7 +480,7 @@ soft_ring_drain(soft_ring_t *ringp, clock_t expire) tid = 0; } - (*proc)(arg1, arg2, mp, -1); + (*proc)(arg1, arg2, mp, NULL); mutex_enter(&ringp->s_ring_lock); } @@ -632,7 +631,7 @@ dls_soft_ring_enable(dls_channel_t dc, dl_capab_dls_t *soft_ringp) /* ARGSUSED */ void dls_ether_soft_ring_fanout(void *rx_handle, void *rx_cookie, mblk_t *mp_chain, - size_t hdrlen) + mac_header_info_t *mhip) { ipha_t *ipha = (ipha_t *)mp_chain->b_rptr; dls_impl_t *dip = (dls_impl_t *)rx_handle; diff --git a/usr/src/uts/common/io/gld.c b/usr/src/uts/common/io/gld.c index c70b2c53cd..240d81c25e 100644 --- a/usr/src/uts/common/io/gld.c +++ b/usr/src/uts/common/io/gld.c @@ -68,27 +68,52 @@ #include <sys/sunddi.h> /* - * Macro to atomically increment counters of type uint32_t, uint64_t - * and ulong_t. + * Macros to increment statistics. */ -#define BUMP(stat, delta) do { \ + +/* + * Increase kstats. Note this operation is not atomic. It can be used when + * GLDM_LOCK_HELD_WRITE(macinfo). + */ +#define BUMP(stats, vstats, stat, delta) do { \ + ((stats)->stat) += (delta); \ + _NOTE(CONSTANTCONDITION) \ + if ((vstats) != NULL) \ + ((struct gld_stats *)(vstats))->stat += (delta); \ + _NOTE(CONSTANTCONDITION) \ +} while (0) + +#define ATOMIC_BUMP_STAT(stat, delta) do { \ _NOTE(CONSTANTCONDITION) \ - if (sizeof (stat) == sizeof (uint32_t)) { \ - atomic_add_32((uint32_t *)&stat, delta); \ + if (sizeof ((stat)) == sizeof (uint32_t)) { \ + atomic_add_32((uint32_t *)&(stat), (delta)); \ _NOTE(CONSTANTCONDITION) \ - } else if (sizeof (stat) == sizeof (uint64_t)) { \ - atomic_add_64((uint64_t *)&stat, delta); \ + } else if (sizeof ((stat)) == sizeof (uint64_t)) { \ + atomic_add_64((uint64_t *)&(stat), (delta)); \ } \ _NOTE(CONSTANTCONDITION) \ } while (0) -#define UPDATE_STATS(vlan, pktinfo, number) { \ - if ((pktinfo).isBroadcast) \ - (vlan)->gldv_stats->glds_brdcstxmt += (number); \ - else if ((pktinfo).isMulticast) \ - (vlan)->gldv_stats->glds_multixmt += (number); \ - (vlan)->gldv_stats->glds_bytexmt64 += (pktinfo).pktLen; \ - (vlan)->gldv_stats->glds_pktxmt64 += (number); \ +#define ATOMIC_BUMP(stats, vstats, stat, delta) do { \ + ATOMIC_BUMP_STAT((stats)->stat, (delta)); \ + _NOTE(CONSTANTCONDITION) \ + if ((vstats) != NULL) { \ + ATOMIC_BUMP_STAT(((struct gld_stats *)(vstats))->stat, \ + (delta)); \ + } \ + _NOTE(CONSTANTCONDITION) \ +} while (0) + +#define UPDATE_STATS(stats, vstats, pktinfo, delta) { \ + if ((pktinfo).isBroadcast) { \ + ATOMIC_BUMP((stats), (vstats), \ + glds_brdcstxmt, (delta)); \ + } else if ((pktinfo).isMulticast) { \ + ATOMIC_BUMP((stats), (vstats), glds_multixmt, (delta)); \ + } \ + ATOMIC_BUMP((stats), (vstats), glds_bytexmt64, \ + ((pktinfo).pktLen)); \ + ATOMIC_BUMP((stats), (vstats), glds_pktxmt64, (delta)); \ } #ifdef GLD_DEBUG @@ -114,12 +139,12 @@ static int gld_start(queue_t *, mblk_t *, int, uint32_t); static int gld_start_mdt(queue_t *, mblk_t *, int); /* called from gld_start[_mdt] to loopback packet(s) in promiscuous mode */ -static void gld_precv(gld_mac_info_t *, gld_vlan_t *, mblk_t *); +static void gld_precv(gld_mac_info_t *, mblk_t *, uint32_t, struct gld_stats *); static void gld_precv_mdt(gld_mac_info_t *, gld_vlan_t *, mblk_t *, pdesc_t *, pktinfo_t *); /* receive group: called from gld_recv and gld_precv* with maclock held */ -static void gld_sendup(gld_mac_info_t *, gld_vlan_t *, pktinfo_t *, mblk_t *, +static void gld_sendup(gld_mac_info_t *, pktinfo_t *, mblk_t *, int (*)()); static int gld_accept(gld_t *, pktinfo_t *); static int gld_mcmatch(gld_t *, pktinfo_t *); @@ -127,7 +152,7 @@ static int gld_multicast(unsigned char *, gld_t *); static int gld_paccept(gld_t *, pktinfo_t *); static void gld_passon(gld_t *, mblk_t *, pktinfo_t *, void (*)(queue_t *, mblk_t *)); -static mblk_t *gld_addudind(gld_t *, mblk_t *, pktinfo_t *); +static mblk_t *gld_addudind(gld_t *, mblk_t *, pktinfo_t *, boolean_t); /* wsrv group: called from wsrv, single threaded per queue */ static int gld_ioctl(queue_t *, mblk_t *); @@ -241,33 +266,6 @@ static char *gld_duplex[] = { "full" /* GLD_DUPLEX_FULL */ }; -extern int gld_interpret_ether(gld_mac_info_t *, mblk_t *, pktinfo_t *, int); -extern int gld_interpret_fddi(gld_mac_info_t *, mblk_t *, pktinfo_t *, int); -extern int gld_interpret_tr(gld_mac_info_t *, mblk_t *, pktinfo_t *, int); -extern int gld_interpret_ib(gld_mac_info_t *, mblk_t *, pktinfo_t *, int); -extern void gld_interpret_mdt_ib(gld_mac_info_t *, mblk_t *, pdescinfo_t *, - pktinfo_t *, int); - -extern mblk_t *gld_fastpath_ether(gld_t *, mblk_t *); -extern mblk_t *gld_fastpath_fddi(gld_t *, mblk_t *); -extern mblk_t *gld_fastpath_tr(gld_t *, mblk_t *); -extern mblk_t *gld_fastpath_ib(gld_t *, mblk_t *); - -extern mblk_t *gld_unitdata_ether(gld_t *, mblk_t *); -extern mblk_t *gld_unitdata_fddi(gld_t *, mblk_t *); -extern mblk_t *gld_unitdata_tr(gld_t *, mblk_t *); -extern mblk_t *gld_unitdata_ib(gld_t *, mblk_t *); - -extern void gld_init_ether(gld_mac_info_t *); -extern void gld_init_fddi(gld_mac_info_t *); -extern void gld_init_tr(gld_mac_info_t *); -extern void gld_init_ib(gld_mac_info_t *); - -extern void gld_uninit_ether(gld_mac_info_t *); -extern void gld_uninit_fddi(gld_mac_info_t *); -extern void gld_uninit_tr(gld_mac_info_t *); -extern void gld_uninit_ib(gld_mac_info_t *); - /* * Interface types currently supported by GLD. * If you add new types, you must check all "XXX" strings in the GLD source @@ -283,7 +281,7 @@ static gld_interface_t interfaces[] = { { DL_ETHER, (uint_t)-1, - sizeof (struct ether_mac_frm), + sizeof (struct ether_header), gld_interpret_ether, NULL, gld_fastpath_ether, @@ -1703,6 +1701,7 @@ gld_wput(queue_t *q, mblk_t *mp) gld_t *gld = (gld_t *)(q->q_ptr); int rc; boolean_t multidata = B_TRUE; + uint32_t upri; #ifdef GLD_DEBUG if (gld_debug & GLDTRACE) @@ -1720,6 +1719,11 @@ gld_wput(queue_t *q, mblk_t *mp) merror(q, mp, EPROTO); break; } + /* + * Cleanup MBLK_VTAG in case it is set by other + * modules. MBLK_VTAG is used to save the vtag information. + */ + GLD_CLEAR_MBLK_VTAG(mp); multidata = B_FALSE; /* LINTED: E_CASE_FALLTHRU */ case M_MULTIDATA: @@ -1752,8 +1756,15 @@ gld_wput(queue_t *q, mblk_t *mp) goto use_wsrv; } + /* + * Get the priority value. Note that in raw mode, the + * per-packet priority value kept in b_band is ignored. + */ + upri = (gld->gld_flags & GLD_RAW) ? gld->gld_upri : + UPRI(gld, mp->b_band); + rc = (multidata) ? gld_start_mdt(q, mp, GLD_WPUT) : - gld_start(q, mp, GLD_WPUT, UPRI(gld, mp->b_band)); + gld_start(q, mp, GLD_WPUT, upri); /* Allow DL_UNBIND again */ membar_exit(); @@ -1828,6 +1839,7 @@ gld_wsrv(queue_t *q) union DL_primitives *prim; int err; boolean_t multidata; + uint32_t upri; #ifdef GLD_DEBUG if (gld_debug & GLDTRACE) @@ -1868,8 +1880,16 @@ gld_wsrv(queue_t *q) gld->gld_sched_ran = B_FALSE; membar_enter(); + + /* + * Get the priority value. Note that in raw mode, the + * per-packet priority value kept in b_band is ignored. + */ + upri = (gld->gld_flags & GLD_RAW) ? gld->gld_upri : + UPRI(gld, mp->b_band); + err = (multidata) ? gld_start_mdt(q, mp, GLD_WSRV) : - gld_start(q, mp, GLD_WSRV, UPRI(gld, mp->b_band)); + gld_start(q, mp, GLD_WSRV, upri); if (err == GLD_NORESOURCES) { /* gld_sched will qenable us later */ gld->gld_xwait = B_TRUE; /* want qenable */ @@ -1992,6 +2012,25 @@ gld_wsrv(queue_t *q) * and the DL_DETACH will succeed. It's hard to test this since the odds * of the failure even trying to happen are so small. I probably could * have ignored the whole issue and never been the worse for it. + * + * Because some GLDv2 Ethernet drivers do not allow the size of transmitted + * packet to be greater than ETHERMAX, we must first strip the VLAN tag + * from a tagged packet before passing it to the driver's gld_send() entry + * point function, and pass the VLAN tag as a separate argument. The + * gld_send() function may fail. In that case, the packet will need to be + * queued in order to be processed again in GLD's service routine. As the + * VTAG has already been stripped at that time, we save the VTAG information + * in (the unused fields of) dblk using GLD_SAVE_MBLK_VTAG(), so that the + * VTAG can also be queued and be able to be got when gld_start() is called + * next time from gld_wsrv(). + * + * Some rules to use GLD_{CLEAR|SAVE}_MBLK_VTAG macros: + * + * - GLD_SAVE_MBLK_VTAG() must be called to save the VTAG information each time + * the message is queued by putbq(). + * + * - GLD_CLEAR_MBLK_VTAG() must be called to clear the bogus VTAG information + * (if any) in dblk before the message is passed to the gld_start() function. */ static int gld_start(queue_t *q, mblk_t *mp, int caller, uint32_t upri) @@ -2003,24 +2042,95 @@ gld_start(queue_t *q, mblk_t *mp, int caller, uint32_t upri) int rc; gld_interface_t *ifp; pktinfo_t pktinfo; - uint32_t vtag; + uint32_t vtag, vid; + uint32_t raw_vtag = 0; gld_vlan_t *vlan; + struct gld_stats *stats0, *stats = NULL; ASSERT(DB_TYPE(mp) == M_DATA); macinfo = gld->gld_mac_info; mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt; ifp = mac_pvt->interfacep; vlan = (gld_vlan_t *)gld->gld_vlan; + vid = vlan->gldv_id; + + /* + * If this interface is a VLAN, the kstats of corresponding + * "VLAN 0" should also be updated. Note that the gld_vlan_t + * structure for VLAN 0 might not exist if there are no DLPI + * consumers attaching on VLAN 0. Fortunately we can directly + * access VLAN 0's kstats from macinfo. + * + * Therefore, stats0 (VLAN 0's kstats) must always be + * updated, and stats must to be updated if it is not NULL. + */ + stats0 = mac_pvt->statistics; + if (vid != VLAN_VID_NONE) + stats = vlan->gldv_stats; if ((*ifp->interpreter)(macinfo, mp, &pktinfo, GLD_TX) != 0) { - freemsg(mp); #ifdef GLD_DEBUG if (gld_debug & GLDERRS) cmn_err(CE_WARN, "gld_start: failed to interpret outbound packet"); #endif - vlan->gldv_stats->glds_xmtbadinterp++; - return (GLD_BADARG); + goto badarg; + } + + vtag = VLAN_VID_NONE; + raw_vtag = GLD_GET_MBLK_VTAG(mp); + if (GLD_VTAG_TCI(raw_vtag) != 0) { + uint16_t raw_pri, raw_vid, evid; + + /* + * Tagged packet. + */ + raw_pri = GLD_VTAG_PRI(raw_vtag); + raw_vid = GLD_VTAG_VID(raw_vtag); + GLD_CLEAR_MBLK_VTAG(mp); + + if (gld->gld_flags & GLD_RAW) { + /* + * In raw mode, we only expect untagged packets or + * special priority-tagged packets on a VLAN stream. + * Drop the packet if its VID is not zero. + */ + if (vid != VLAN_VID_NONE && raw_vid != VLAN_VID_NONE) + goto badarg; + + /* + * If it is raw mode, use the per-stream priority if + * the priority is not specified in the packet. + * Otherwise, ignore the priority bits in the packet. + */ + upri = (raw_pri != 0) ? raw_pri : upri; + } + + if (vid == VLAN_VID_NONE && vid != raw_vid) { + gld_vlan_t *tmp_vlan; + + /* + * This link is a physical link but the packet is + * a VLAN tagged packet, the kstats of corresponding + * VLAN (if any) should also be updated. + */ + tmp_vlan = gld_find_vlan(macinfo, raw_vid); + if (tmp_vlan != NULL) + stats = tmp_vlan->gldv_stats; + } + + evid = (vid == VLAN_VID_NONE) ? raw_vid : vid; + if (evid != VLAN_VID_NONE || upri != 0) + vtag = GLD_MAKE_VTAG(upri, VLAN_CFI_ETHER, evid); + } else { + /* + * Untagged packet: + * Get vtag from the attached PPA of this stream. + */ + if ((vid != VLAN_VID_NONE) || + ((macinfo->gldm_type == DL_ETHER) && (upri != 0))) { + vtag = GLD_MAKE_VTAG(upri, VLAN_CFI_ETHER, vid); + } } /* @@ -2039,6 +2149,7 @@ gld_start(queue_t *q, mblk_t *mp, int caller, uint32_t upri) * driver's send routine. */ if (caller == GLD_WPUT) { + GLD_SAVE_MBLK_VTAG(mp, raw_vtag); (void) putbq(q, mp); return (GLD_NORESOURCES); } @@ -2049,11 +2160,9 @@ gld_start(queue_t *q, mblk_t *mp, int caller, uint32_t upri) } else nmp = NULL; /* we need no loopback */ - vtag = GLD_MK_VTAG(vlan->gldv_ptag, upri); if (ifp->hdr_size > 0 && pktinfo.pktLen > ifp->hdr_size + (vtag == 0 ? 0 : VTAG_SIZE) + macinfo->gldm_maxpkt) { - freemsg(mp); /* discard oversized outbound packet */ if (nmp) freemsg(nmp); /* free the duped message */ #ifdef GLD_DEBUG @@ -2061,23 +2170,24 @@ gld_start(queue_t *q, mblk_t *mp, int caller, uint32_t upri) cmn_err(CE_WARN, "gld_start: oversize outbound packet, size %d," "max %d", pktinfo.pktLen, - ifp->hdr_size + macinfo->gldm_maxpkt); + ifp->hdr_size + (vtag == 0 ? 0 : VTAG_SIZE) + + macinfo->gldm_maxpkt); #endif - vlan->gldv_stats->glds_xmtbadinterp++; - return (GLD_BADARG); + goto badarg; } rc = (*gld->gld_send)(macinfo, mp, vtag); if (rc != GLD_SUCCESS) { if (rc == GLD_NORESOURCES) { - vlan->gldv_stats->glds_xmtretry++; + ATOMIC_BUMP(stats0, stats, glds_xmtretry, 1); + GLD_SAVE_MBLK_VTAG(mp, raw_vtag); (void) putbq(q, mp); } else { /* transmit error; drop the packet */ freemsg(mp); /* We're supposed to count failed attempts as well */ - UPDATE_STATS(vlan, pktinfo, 1); + UPDATE_STATS(stats0, stats, pktinfo, 1); #ifdef GLD_DEBUG if (gld_debug & GLDERRS) cmn_err(CE_WARN, @@ -2089,21 +2199,27 @@ gld_start(queue_t *q, mblk_t *mp, int caller, uint32_t upri) return (rc); } - UPDATE_STATS(vlan, pktinfo, 1); + UPDATE_STATS(stats0, stats, pktinfo, 1); /* * Loopback case. The message needs to be returned back on - * the read side. This would silently fail if the dumpmsg fails + * the read side. This would silently fail if the dupmsg fails * above. This is probably OK, if there is no memory to dup the * block, then there isn't much we could do anyway. */ if (nmp) { GLDM_LOCK(macinfo, RW_WRITER); - gld_precv(macinfo, vlan, nmp); + gld_precv(macinfo, nmp, vtag, stats); GLDM_UNLOCK(macinfo); } return (GLD_SUCCESS); + +badarg: + freemsg(mp); + + ATOMIC_BUMP(stats0, stats, glds_xmtbadinterp, 1); + return (GLD_BADARG); } /* @@ -2244,7 +2360,7 @@ gld_start_mdt(queue_t *q, mblk_t *mp, int caller) } (*macinfo->gldm_mdt_post)(macinfo, mp, cookie); pktinfo.pktLen = totLen; - UPDATE_STATS(vlan, pktinfo, numpacks); + UPDATE_STATS(vlan->gldv_stats, NULL, pktinfo, numpacks); /* * In the noresources case (when driver indicates it @@ -2260,7 +2376,8 @@ gld_start_mdt(queue_t *q, mblk_t *mp, int caller) &pinfo); mmd_rempdesc(dl_pkt); } - vlan->gldv_stats->glds_xmtretry++; + ATOMIC_BUMP(vlan->gldv_stats, NULL, + glds_xmtretry, 1); mp->b_cont = nextmp; (void) putbq(q, mp); return (GLD_NORESOURCES); @@ -2270,7 +2387,7 @@ gld_start_mdt(queue_t *q, mblk_t *mp, int caller) * Driver indicates it can not transmit any packets * currently and will request retrial later. */ - vlan->gldv_stats->glds_xmtretry++; + ATOMIC_BUMP(vlan->gldv_stats, NULL, glds_xmtretry, 1); mp->b_cont = nextmp; (void) putbq(q, mp); return (GLD_NORESOURCES); @@ -2293,7 +2410,7 @@ gld_start_mdt(queue_t *q, mblk_t *mp, int caller) dl_pkt = mmd_getnextpdesc(dl_pkt, &pinfo); } pktinfo.pktLen = totLen; - UPDATE_STATS(vlan, pktinfo, mdtpacks); + UPDATE_STATS(vlan->gldv_stats, NULL, pktinfo, mdtpacks); /* * Transmit error; drop the message, move on @@ -2373,11 +2490,15 @@ gld_sched(gld_mac_info_t *macinfo) } /* - * gld_precv (macinfo, mp) + * gld_precv (macinfo, mp, vtag, stats) * called from gld_start to loopback a packet when in promiscuous mode + * + * VLAN 0's statistics need to be updated. If stats is not NULL, + * it needs to be updated as well. */ static void -gld_precv(gld_mac_info_t *macinfo, gld_vlan_t *vlan, mblk_t *mp) +gld_precv(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag, + struct gld_stats *stats) { gld_mac_pvt_t *mac_pvt; gld_interface_t *ifp; @@ -2393,7 +2514,7 @@ gld_precv(gld_mac_info_t *macinfo, gld_vlan_t *vlan, mblk_t *mp) */ if ((*ifp->interpreter)(macinfo, mp, &pktinfo, GLD_RXLOOP) != 0) { freemsg(mp); - BUMP(vlan->gldv_stats->glds_rcvbadinterp, 1); + BUMP(mac_pvt->statistics, stats, glds_rcvbadinterp, 1); #ifdef GLD_DEBUG if (gld_debug & GLDERRS) cmn_err(CE_WARN, @@ -2402,12 +2523,23 @@ gld_precv(gld_mac_info_t *macinfo, gld_vlan_t *vlan, mblk_t *mp) return; } - gld_sendup(macinfo, vlan, &pktinfo, mp, gld_paccept); + /* + * Update the vtag information. + */ + pktinfo.isTagged = (vtag != VLAN_VID_NONE); + pktinfo.vid = GLD_VTAG_VID(vtag); + pktinfo.cfi = GLD_VTAG_CFI(vtag); + pktinfo.user_pri = GLD_VTAG_PRI(vtag); + + gld_sendup(macinfo, &pktinfo, mp, gld_paccept); } /* - * called from gld_start_mdt to loopback packet(s) when in promiscuous mode + * Called from gld_start_mdt to loopback packet(s) when in promiscuous mode. + * Note that 'vlan' is always a physical link, because MDT can only be + * enabled on non-VLAN streams. */ +/*ARGSUSED*/ static void gld_precv_mdt(gld_mac_info_t *macinfo, gld_vlan_t *vlan, mblk_t *mp, pdesc_t *dl_pkt, pktinfo_t *pktinfo) @@ -2424,7 +2556,7 @@ gld_precv_mdt(gld_mac_info_t *macinfo, gld_vlan_t *vlan, mblk_t *mp, (void) (*ifp->interpreter_mdt)(macinfo, mp, NULL, pktinfo, GLD_MDT_RXLOOP); if ((adjmp = mmd_transform(dl_pkt)) != NULL) - gld_sendup(macinfo, vlan, pktinfo, adjmp, gld_paccept); + gld_sendup(macinfo, pktinfo, adjmp, gld_paccept); } /* @@ -2448,8 +2580,10 @@ gld_recv_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag) pktinfo_t pktinfo; gld_interface_t *ifp; queue_t *ipq = NULL; - gld_vlan_t *vlan; + gld_vlan_t *vlan = NULL, *vlan0 = NULL, *vlann = NULL; + struct gld_stats *stats0, *stats = NULL; uint32_t vid; + int err; ASSERT(macinfo != NULL); ASSERT(mp->b_datap->db_ref); @@ -2462,21 +2596,62 @@ gld_recv_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag) goto done; } + /* + * If this packet is a VLAN tagged packet, the kstats of corresponding + * "VLAN 0" should also be updated. We can directly access VLAN 0's + * kstats from macinfo. + * + * Further, the packets needs to be passed to VLAN 0 if there is + * any DLPI consumer on VLAN 0 who is interested in tagged packets + * (DL_PROMISC_SAP is on or is bounded to ETHERTYPE_VLAN SAP). + */ + mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt; + stats0 = mac_pvt->statistics; + vid = GLD_VTAG_VID(vtag); - if ((vlan = gld_find_vlan(macinfo, vid)) == NULL) { + vlan0 = gld_find_vlan(macinfo, VLAN_VID_NONE); + if (vid != VLAN_VID_NONE) { + /* + * If there are no physical DLPI consumers interested in the + * VLAN packet, clear vlan0. + */ + if ((vlan0 != NULL) && (vlan0->gldv_nvlan_sap == 0)) + vlan0 = NULL; + /* + * vlann is the VLAN with the same VID as the VLAN packet. + */ + vlann = gld_find_vlan(macinfo, vid); + if (vlann != NULL) + stats = vlann->gldv_stats; + } + + vlan = (vid == VLAN_VID_NONE) ? vlan0 : vlann; + + ifp = mac_pvt->interfacep; + err = (*ifp->interpreter)(macinfo, mp, &pktinfo, GLD_RXQUICK); + + BUMP(stats0, stats, glds_bytercv64, pktinfo.pktLen); + BUMP(stats0, stats, glds_pktrcv64, 1); + + if ((vlann == NULL) && (vlan0 == NULL)) { freemsg(mp); goto done; } /* - * Check whether underlying media code supports the IPQ hack, - * and if so, whether the interpreter can quickly parse the - * packet to get some relevant parameters. + * Check whether underlying media code supports the IPQ hack: + * + * - the interpreter could quickly parse the packet + * - the device type supports IPQ (ethernet and IPoIB) + * - there is one, and only one, IP stream bound (to this VLAN) + * - that stream is a "fastpath" stream + * - the packet is of type ETHERTYPE_IP or ETHERTYPE_IPV6 + * - there are no streams in promiscuous mode (on this VLAN) + * - if this packet is tagged, there is no need to send this + * packet to physical streams */ - mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt; - ifp = mac_pvt->interfacep; - if (((*ifp->interpreter)(macinfo, mp, &pktinfo, - GLD_RXQUICK) == 0) && (vlan->gldv_ipq_flags == 0)) { + if ((err != 0) && ((vlan != NULL) && (vlan->gldv_nprom == 0)) && + (vlan == vlan0 || vlan0 == NULL)) { switch (pktinfo.ethertype) { case ETHERTYPE_IP: ipq = vlan->gldv_ipq; @@ -2487,19 +2662,9 @@ gld_recv_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag) } } - BUMP(vlan->gldv_stats->glds_bytercv64, pktinfo.pktLen); - BUMP(vlan->gldv_stats->glds_pktrcv64, 1); - /* * Special case for IP; we can simply do the putnext here, if: - * o ipq != NULL, and therefore: - * - the device type supports IPQ (ethernet and IPoIB); - * - the interpreter could quickly parse the packet; - * - there are no PROMISC_SAP streams (on this VLAN); - * - there is one, and only one, IP stream bound (to this VLAN); - * - that stream is a "fastpath" stream; - * - the packet is of type ETHERTYPE_IP or ETHERTYPE_IPV6 - * + * o The IPQ hack is possible (ipq != NULL). * o the packet is specifically for me, and therefore: * - the packet is not multicast or broadcast (fastpath only * wants unicast packets). @@ -2522,7 +2687,7 @@ gld_recv_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag) * call the media specific packet interpreter routine */ if ((*ifp->interpreter)(macinfo, mp, &pktinfo, GLD_RX) != 0) { - BUMP(vlan->gldv_stats->glds_rcvbadinterp, 1); + BUMP(stats0, stats, glds_rcvbadinterp, 1); #ifdef GLD_DEBUG if (gld_debug & GLDERRS) cmn_err(CE_WARN, @@ -2535,7 +2700,6 @@ gld_recv_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag) /* * This is safe even if vtag is VLAN_VTAG_NONE */ - pktinfo.vid = vid; pktinfo.cfi = GLD_VTAG_CFI(vtag); #ifdef GLD_DEBUG @@ -2543,6 +2707,7 @@ gld_recv_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag) cmn_err(CE_WARN, "gld_recv_tagged: non-ETHER CFI"); #endif pktinfo.user_pri = GLD_VTAG_PRI(vtag); + pktinfo.isTagged = (vtag != VLAN_VID_NONE); #ifdef GLD_DEBUG if ((gld_debug & GLDRECV) && @@ -2567,7 +2732,7 @@ gld_recv_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag) } #endif - gld_sendup(macinfo, vlan, &pktinfo, mp, gld_accept); + gld_sendup(macinfo, &pktinfo, mp, gld_accept); done: GLDM_UNLOCK(macinfo); @@ -2578,63 +2743,33 @@ done: /* =================================================================== */ /* - * gld_sendup (macinfo, mp) - * called with an ethernet packet in a mblock; must decide whether - * packet is for us and which streams to queue it to. + * Search all the streams attached to the specified VLAN looking for + * those eligible to receive the packet. + * Note that in order to avoid an extra dupmsg(), if this is the first + * eligible stream, remember it (in fgldp) so that we can send up the + * message after this function. + * + * Return errno if fails. Currently the only error is ENOMEM. */ -static void -gld_sendup(gld_mac_info_t *macinfo, gld_vlan_t *vlan, pktinfo_t *pktinfo, - mblk_t *mp, int (*acceptfunc)()) +static int +gld_sendup_vlan(gld_vlan_t *vlan, pktinfo_t *pktinfo, mblk_t *mp, + int (*acceptfunc)(), void (*send)(), int (*cansend)(), gld_t **fgldp) { - gld_t *gld; - gld_t *fgld = NULL; mblk_t *nmp; - void (*send)(queue_t *qp, mblk_t *mp); - int (*cansend)(queue_t *qp); - -#ifdef GLD_DEBUG - if (gld_debug & GLDTRACE) - cmn_err(CE_NOTE, "gld_sendup(%p, %p)", (void *)mp, - (void *)macinfo); -#endif + gld_t *gld; + int err = 0; - ASSERT(mp != NULL); - ASSERT(macinfo != NULL); ASSERT(vlan != NULL); - ASSERT(pktinfo != NULL); - ASSERT(GLDM_LOCK_HELD(macinfo)); - - /* - * The "fast" in "GLDOPT_FAST_RECV" refers to the speed at which - * gld_recv returns to the caller's interrupt routine. The total - * network throughput would normally be lower when selecting this - * option, because we putq the messages and process them later, - * instead of sending them with putnext now. Some time critical - * device might need this, so it's here but undocumented. - */ - if (macinfo->gldm_options & GLDOPT_FAST_RECV) { - send = (void (*)(queue_t *, mblk_t *))putq; - cansend = canput; - } else { - send = (void (*)(queue_t *, mblk_t *))putnext; - cansend = canputnext; - } - - /* - * Search all the streams attached to this macinfo looking for - * those eligible to receive the present packet. - */ - for (gld = vlan->gldv_str_next; - gld != (gld_t *)&vlan->gldv_str_next; gld = gld->gld_next) { + for (gld = vlan->gldv_str_next; gld != (gld_t *)&vlan->gldv_str_next; + gld = gld->gld_next) { #ifdef GLD_VERBOSE_DEBUG - cmn_err(CE_NOTE, "gld_sendup: SAP: %4x QPTR: %p QSTATE: %s", + cmn_err(CE_NOTE, "gld_sendup: SAP: %4x QPTR: %p "QSTATE: %s", gld->gld_sap, (void *)gld->gld_qptr, gld->gld_state == DL_IDLE ? "IDLE": "NOT IDLE"); #endif ASSERT(gld->gld_qptr != NULL); ASSERT(gld->gld_state == DL_IDLE || gld->gld_state == DL_UNBOUND); - ASSERT(gld->gld_mac_info == macinfo); ASSERT(gld->gld_vlan == vlan); if (gld->gld_state != DL_IDLE) @@ -2660,7 +2795,7 @@ gld_sendup(gld_mac_info_t *macinfo, gld_vlan_t *vlan, pktinfo_t *pktinfo, */ if ((*acceptfunc)(gld, pktinfo)) { /* sap matches */ - pktinfo->wasAccepted = 1; /* known protocol */ + pktinfo->wasAccepted = 1; /* known protocol */ if (!(*cansend)(gld->gld_qptr)) { /* @@ -2673,36 +2808,114 @@ gld_sendup(gld_mac_info_t *macinfo, gld_vlan_t *vlan, pktinfo_t *pktinfo, cmn_err(CE_WARN, "gld_sendup: canput failed"); #endif - BUMP(vlan->gldv_stats->glds_blocked, 1); + BUMP(vlan->gldv_stats, NULL, glds_blocked, 1); qenable(gld->gld_qptr); continue; } /* - * we are trying to avoid an extra dumpmsg() here. - * If this is the first eligible queue, remember the - * queue and send up the message after the loop. + * In order to avoid an extra dupmsg(), remember this + * gld if this is the first eligible stream. */ - if (!fgld) { - fgld = gld; + if (*fgldp == NULL) { + *fgldp = gld; continue; } /* duplicate the packet for this stream */ nmp = dupmsg(mp); if (nmp == NULL) { - BUMP(vlan->gldv_stats->glds_gldnorcvbuf, 1); + BUMP(vlan->gldv_stats, NULL, + glds_gldnorcvbuf, 1); #ifdef GLD_DEBUG if (gld_debug & GLDERRS) cmn_err(CE_WARN, "gld_sendup: dupmsg failed"); #endif - break; /* couldn't get resources; drop it */ + /* couldn't get resources; drop it */ + err = ENOMEM; + break; } /* pass the message up the stream */ gld_passon(gld, nmp, pktinfo, send); } } + return (err); +} + +/* + * gld_sendup (macinfo, pktinfo, mp, acceptfunc) + * called with an ethernet packet in an mblk; must decide whether + * packet is for us and which streams to queue it to. + */ +static void +gld_sendup(gld_mac_info_t *macinfo, pktinfo_t *pktinfo, + mblk_t *mp, int (*acceptfunc)()) +{ + gld_t *fgld = NULL; + void (*send)(queue_t *qp, mblk_t *mp); + int (*cansend)(queue_t *qp); + gld_vlan_t *vlan0, *vlann = NULL; + struct gld_stats *stats0, *stats = NULL; + int err = 0; + +#ifdef GLD_DEBUG + if (gld_debug & GLDTRACE) + cmn_err(CE_NOTE, "gld_sendup(%p, %p)", (void *)mp, + (void *)macinfo); +#endif + + ASSERT(mp != NULL); + ASSERT(macinfo != NULL); + ASSERT(pktinfo != NULL); + ASSERT(GLDM_LOCK_HELD(macinfo)); + + /* + * The tagged packets should also be looped back (transmit-side) + * or sent up (receive-side) to VLAN 0 if VLAN 0 is set to + * DL_PROMISC_SAP or there is any DLPI consumer bind to the + * ETHERTYPE_VLAN SAP. The kstats of VLAN 0 needs to be updated + * as well. + */ + stats0 = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->statistics; + vlan0 = gld_find_vlan(macinfo, VLAN_VID_NONE); + if (pktinfo->vid != VLAN_VID_NONE) { + if ((vlan0 != NULL) && (vlan0->gldv_nvlan_sap == 0)) + vlan0 = NULL; + vlann = gld_find_vlan(macinfo, pktinfo->vid); + if (vlann != NULL) + stats = vlann->gldv_stats; + } + + ASSERT((vlan0 != NULL) || (vlann != NULL)); + + /* + * The "fast" in "GLDOPT_FAST_RECV" refers to the speed at which + * gld_recv returns to the caller's interrupt routine. The total + * network throughput would normally be lower when selecting this + * option, because we putq the messages and process them later, + * instead of sending them with putnext now. Some time critical + * device might need this, so it's here but undocumented. + */ + if (macinfo->gldm_options & GLDOPT_FAST_RECV) { + send = (void (*)(queue_t *, mblk_t *))putq; + cansend = canput; + } else { + send = (void (*)(queue_t *, mblk_t *))putnext; + cansend = canputnext; + } + + /* + * Send the packets for all eligible streams. + */ + if (vlan0 != NULL) { + err = gld_sendup_vlan(vlan0, pktinfo, mp, acceptfunc, send, + cansend, &fgld); + } + if ((err == 0) && (vlann != NULL)) { + err = gld_sendup_vlan(vlann, pktinfo, mp, acceptfunc, send, + cansend, &fgld); + } ASSERT(mp); /* send the original dup of the packet up the first stream found */ @@ -2716,23 +2929,28 @@ gld_sendup(gld_mac_info_t *macinfo, gld_vlan_t *vlan, pktinfo_t *pktinfo, return; /* transmit loopback case */ if (pktinfo->isBroadcast) - BUMP(vlan->gldv_stats->glds_brdcstrcv, 1); + BUMP(stats0, stats, glds_brdcstrcv, 1); else if (pktinfo->isMulticast) - BUMP(vlan->gldv_stats->glds_multircv, 1); + BUMP(stats0, stats, glds_multircv, 1); /* No stream accepted this packet */ if (!pktinfo->wasAccepted) - BUMP(vlan->gldv_stats->glds_unknowns, 1); + BUMP(stats0, stats, glds_unknowns, 1); } +#define GLD_IS_PHYS(gld) \ + (((gld_vlan_t *)gld->gld_vlan)->gldv_id == VLAN_VID_NONE) + /* * A packet matches a stream if: - * the stream accepts EtherType encoded packets and the type matches - * or the stream accepts LLC packets and the packet is an LLC packet + * The stream's VLAN id is the same as the one in the packet. + * and the stream accepts EtherType encoded packets and the type matches + * or the stream accepts LLC packets and the packet is an LLC packet */ #define MATCH(stream, pktinfo) \ + ((((gld_vlan_t *)stream->gld_vlan)->gldv_id == pktinfo->vid) && \ ((stream->gld_ethertype && stream->gld_sap == pktinfo->ethertype) || \ - (!stream->gld_ethertype && pktinfo->isLLC)) + (!stream->gld_ethertype && pktinfo->isLLC))) /* * This function validates a packet for sending up a particular @@ -2745,8 +2963,16 @@ gld_accept(gld_t *gld, pktinfo_t *pktinfo) { /* * if there is no match do not bother checking further. + * Note that it is okay to examine gld_vlan because + * macinfo->gldm_lock is held. + * + * Because all tagged packets have SAP value ETHERTYPE_VLAN, + * these packets will pass the SAP filter check if the stream + * is a ETHERTYPE_VLAN listener. */ - if (!MATCH(gld, pktinfo) && !(gld->gld_flags & GLD_PROM_SAP)) + if ((!MATCH(gld, pktinfo) && !(gld->gld_flags & GLD_PROM_SAP) && + !(GLD_IS_PHYS(gld) && gld->gld_sap == ETHERTYPE_VLAN && + pktinfo->isTagged))) return (0); /* @@ -2836,15 +3062,29 @@ gld_multicast(unsigned char *macaddr, gld_t *gld) static int gld_paccept(gld_t *gld, pktinfo_t *pktinfo) { + /* + * Note that it is okay to examine gld_vlan because macinfo->gldm_lock + * is held. + * + * If a stream is a ETHERTYPE_VLAN listener, it must + * accept all tagged packets as those packets have SAP value + * ETHERTYPE_VLAN. + */ return (gld->gld_flags & GLD_PROM_PHYS && - (MATCH(gld, pktinfo) || gld->gld_flags & GLD_PROM_SAP)); + (MATCH(gld, pktinfo) || gld->gld_flags & GLD_PROM_SAP || + (GLD_IS_PHYS(gld) && gld->gld_sap == ETHERTYPE_VLAN && + pktinfo->isTagged))); + } static void gld_passon(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo, void (*send)(queue_t *qp, mblk_t *mp)) { + boolean_t is_phys = GLD_IS_PHYS(gld); int skiplen; + boolean_t addtag = B_FALSE; + uint32_t vtag = 0; #ifdef GLD_DEBUG if (gld_debug & GLDTRACE) @@ -2857,26 +3097,39 @@ gld_passon(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo, (void *)gld->gld_qptr->q_next, (void *)mp, gld->gld_minor, gld->gld_sap); #endif - /* * Figure out how much of the packet header to throw away. * - * RAW streams expect to see the whole packet. - * - * Other streams expect to see the packet with the MAC header - * removed. - * * Normal DLPI (non RAW/FAST) streams also want the * DL_UNITDATA_IND M_PROTO message block prepended to the M_DATA. */ if (gld->gld_flags & GLD_RAW) { + /* + * The packet will be tagged in the following cases: + * - if priority is not 0 + * - a tagged packet sent on a physical link + */ + if ((pktinfo->isTagged && is_phys) || (pktinfo->user_pri != 0)) + addtag = B_TRUE; skiplen = 0; } else { + /* + * The packet will be tagged if it meets all below conditions: + * - this is a physical stream + * - this packet is tagged packet + * - the stream is either a DL_PROMISC_SAP listener or a + * ETHERTYPE_VLAN listener + */ + if (is_phys && pktinfo->isTagged && + ((gld->gld_sap == ETHERTYPE_VLAN) || + (gld->gld_flags & GLD_PROM_SAP))) { + addtag = B_TRUE; + } + skiplen = pktinfo->macLen; /* skip mac header */ if (gld->gld_ethertype) skiplen += pktinfo->hdrLen; /* skip any extra */ } - if (skiplen >= pktinfo->pktLen) { /* * If the interpreter did its job right, then it cannot be @@ -2891,6 +3144,17 @@ gld_passon(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo, return; } + if (addtag) { + mblk_t *savemp = mp; + + vtag = GLD_MAKE_VTAG(pktinfo->user_pri, pktinfo->cfi, + is_phys ? pktinfo->vid : VLAN_VID_NONE); + if ((mp = gld_insert_vtag_ether(mp, vtag)) == NULL) { + freemsg(savemp); + return; + } + } + /* * Skip over the header(s), taking care to possibly handle message * fragments shorter than the amount we need to skip. Hopefully @@ -2898,11 +3162,11 @@ gld_passon(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo, * header, into a single message block. But we handle it if not. */ while (skiplen >= MBLKL(mp)) { - mblk_t *tmp = mp; + mblk_t *savemp = mp; skiplen -= MBLKL(mp); mp = mp->b_cont; ASSERT(mp != NULL); /* because skiplen < pktinfo->pktLen */ - freeb(tmp); + freeb(savemp); } mp->b_rptr += skiplen; @@ -2913,7 +3177,7 @@ gld_passon(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo, (*send)(gld->gld_qptr, mp); } else { /* everybody else wants to see a unitdata_ind structure */ - mp = gld_addudind(gld, mp, pktinfo); + mp = gld_addudind(gld, mp, pktinfo, addtag); if (mp) (*send)(gld->gld_qptr, mp); /* if it failed, gld_addudind already bumped statistic */ @@ -2925,7 +3189,7 @@ gld_passon(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo, * format a DL_UNITDATA_IND message to be sent upstream to the user */ static mblk_t * -gld_addudind(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo) +gld_addudind(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo, boolean_t tagged) { gld_mac_info_t *macinfo = gld->gld_mac_info; gld_vlan_t *vlan = (gld_vlan_t *)gld->gld_vlan; @@ -2949,7 +3213,7 @@ gld_addudind(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo) 2 * (macinfo->gldm_addrlen + abs(macinfo->gldm_saplen)); if ((nmp = allocb(size, BPRI_MED)) == NULL) { freemsg(mp); - BUMP(vlan->gldv_stats->glds_gldnorcvbuf, 1); + BUMP(vlan->gldv_stats, NULL, glds_gldnorcvbuf, 1); #ifdef GLD_DEBUG if (gld_debug & GLDERRS) cmn_err(CE_WARN, @@ -2960,7 +3224,11 @@ gld_addudind(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo) DB_TYPE(nmp) = M_PROTO; nmp->b_rptr = nmp->b_datap->db_lim - size; - type = (gld->gld_ethertype) ? pktinfo->ethertype : 0; + if (tagged) + type = ETHERTYPE_VLAN; + else + type = (gld->gld_ethertype) ? pktinfo->ethertype : 0; + /* * now setup the DL_UNITDATA_IND header @@ -3116,7 +3384,12 @@ gld_ioctl(queue_t *q, mblk_t *mp) break; case DL_IOC_HDR_INFO: /* fastpath */ - if (gld_global_options & GLD_OPT_NO_FASTPATH) { + /* + * DL_IOC_HDR_INFO should only come from IP. The one + * initiated from user-land should not be allowed. + */ + if ((gld_global_options & GLD_OPT_NO_FASTPATH) || + (iocp->ioc_cr != kcred)) { miocnak(q, mp, 0, EINVAL); break; } @@ -3157,7 +3430,6 @@ gld_fastpath(gld_t *gld, queue_t *q, mblk_t *mp) t_scalar_t off, len; uint_t maclen; int error; - gld_vlan_t *vlan; if (gld->gld_state != DL_IDLE) { miocnak(q, mp, 0, EINVAL); @@ -3194,8 +3466,6 @@ gld_fastpath(gld_t *gld, queue_t *q, mblk_t *mp) */ GLDM_LOCK(macinfo, RW_WRITER); gld->gld_flags |= GLD_FAST; - vlan = (gld_vlan_t *)gld->gld_vlan; - vlan->gldv_ipq_flags &= ~IPQ_DISABLED; GLDM_UNLOCK(macinfo); ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep; @@ -3952,6 +4222,8 @@ gld_bind(queue_t *q, mblk_t *mp) GLDM_LOCK(macinfo, RW_WRITER); gld->gld_state = DL_IDLE; /* bound and ready */ gld->gld_sap = sap; + if ((macinfo->gldm_type == DL_ETHER) && (sap == ETHERTYPE_VLAN)) + ((gld_vlan_t *)gld->gld_vlan)->gldv_nvlan_sap++; gld_set_ipq(gld); #ifdef GLD_DEBUG @@ -4017,6 +4289,10 @@ gld_unbind(queue_t *q, mblk_t *mp) } GLDM_LOCK(macinfo, RW_WRITER); + if ((macinfo->gldm_type == DL_ETHER) && + (gld->gld_sap == ETHERTYPE_VLAN)) { + ((gld_vlan_t *)gld->gld_vlan)->gldv_nvlan_sap--; + } gld->gld_state = DL_UNBOUND; gld->gld_sap = 0; gld_set_ipq(gld); @@ -4052,7 +4328,6 @@ gld_inforeq(queue_t *q, mblk_t *mp) int sap_length; int brdcst_offset; int brdcst_length; - gld_vlan_t *vlan; uchar_t *sapp; #ifdef GLD_DEBUG @@ -4088,8 +4363,7 @@ gld_inforeq(queue_t *q, mblk_t *mp) brdcst_offset = bufsize; bufsize += brdcst_length; - if ((vlan = (gld_vlan_t *)gld->gld_vlan) != NULL && - vlan->gldv_id != VLAN_VID_NONE) { + if (((gld_vlan_t *)gld->gld_vlan) != NULL) { sel_offset = P2ROUNDUP(bufsize, sizeof (int64_t)); bufsize = sel_offset + sizeof (dl_qos_cl_sel1_t); @@ -4276,6 +4550,7 @@ gld_unitdata(queue_t *q, mblk_t *mp) (void) hcksum_assoc(nmp, NULL, NULL, start, stuff, end, value, flags, 0); + GLD_CLEAR_MBLK_VTAG(nmp); if (gld_start(q, nmp, GLD_WSRV, upri) == GLD_NORESOURCES) { qenable(q); return (GLDE_RETRY); @@ -4458,8 +4733,6 @@ gldunattach(queue_t *q, mblk_t *mp) mult_off = (gld->gld_flags & GLD_PROM_MULT && --mac_pvt->nprom_multi == 0); - gld->gld_flags &= ~(GLD_PROM_PHYS | GLD_PROM_SAP | GLD_PROM_MULT); - if (phys_off) { op = (mac_pvt->nprom_multi == 0) ? GLD_MAC_PROMISC_NONE : GLD_MAC_PROMISC_MULTI; @@ -4471,6 +4744,18 @@ gldunattach(queue_t *q, mblk_t *mp) if (op != GLD_MAC_PROMISC_NOOP) (void) (*macinfo->gldm_set_promiscuous)(macinfo, op); + vlan = (gld_vlan_t *)gld->gld_vlan; + if (gld->gld_flags & GLD_PROM_PHYS) + vlan->gldv_nprom--; + if (gld->gld_flags & GLD_PROM_MULT) + vlan->gldv_nprom--; + if (gld->gld_flags & GLD_PROM_SAP) { + vlan->gldv_nprom--; + vlan->gldv_nvlan_sap--; + } + + gld->gld_flags &= ~(GLD_PROM_PHYS | GLD_PROM_SAP | GLD_PROM_MULT); + GLDM_UNLOCK(macinfo); if (phys_off) @@ -4486,7 +4771,6 @@ gldunattach(queue_t *q, mblk_t *mp) /* disassociate this stream with its vlan and underlying mac */ gldremque(gld); - vlan = (gld_vlan_t *)gld->gld_vlan; if (--vlan->gldv_nstreams == 0) { gld_rem_vlan(vlan); gld->gld_vlan = NULL; @@ -4909,16 +5193,20 @@ gld_promisc(queue_t *q, mblk_t *mp, t_uscalar_t req, boolean_t on) switch (prim->promiscon_req.dl_level) { case DL_PROMISC_PHYS: mac_pvt->nprom++; + vlan->gldv_nprom++; gld->gld_flags |= GLD_PROM_PHYS; break; case DL_PROMISC_MULTI: mac_pvt->nprom_multi++; + vlan->gldv_nprom++; gld->gld_flags |= GLD_PROM_MULT; break; case DL_PROMISC_SAP: gld->gld_flags |= GLD_PROM_SAP; + vlan->gldv_nprom++; + vlan->gldv_nvlan_sap++; break; default: @@ -4928,16 +5216,20 @@ gld_promisc(queue_t *q, mblk_t *mp, t_uscalar_t req, boolean_t on) switch (prim->promiscoff_req.dl_level) { case DL_PROMISC_PHYS: mac_pvt->nprom--; + vlan->gldv_nprom--; gld->gld_flags &= ~GLD_PROM_PHYS; break; case DL_PROMISC_MULTI: mac_pvt->nprom_multi--; + vlan->gldv_nprom--; gld->gld_flags &= ~GLD_PROM_MULT; break; case DL_PROMISC_SAP: gld->gld_flags &= ~GLD_PROM_SAP; + vlan->gldv_nvlan_sap--; + vlan->gldv_nprom--; break; default: @@ -4953,14 +5245,6 @@ gld_promisc(queue_t *q, mblk_t *mp, t_uscalar_t req, boolean_t on) gld->gld_xwait = B_TRUE; } - /* - * Update VLAN IPQ status -- it may have changed - */ - if (gld->gld_flags & (GLD_PROM_SAP | GLD_PROM_MULT | GLD_PROM_PHYS)) - vlan->gldv_ipq_flags |= IPQ_FORBIDDEN; - else - vlan->gldv_ipq_flags &= ~IPQ_FORBIDDEN; - GLDM_UNLOCK(macinfo); /* diff --git a/usr/src/uts/common/io/gldutil.c b/usr/src/uts/common/io/gldutil.c index 7fe5cb66c5..c3e9f2bedb 100644 --- a/usr/src/uts/common/io/gldutil.c +++ b/usr/src/uts/common/io/gldutil.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,7 +18,7 @@ * * CDDL HEADER END * - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -98,7 +97,7 @@ gld_init_ether(gld_mac_info_t *macinfo) ASSERT(macinfo->gldm_addrlen == 6); ASSERT(macinfo->gldm_saplen == -2); #ifndef lint - ASSERT(sizeof (struct ether_mac_frm) == 14); + ASSERT(sizeof (struct ether_header) == 14); ASSERT(sizeof (mac_addr_t) == 6); #endif @@ -145,11 +144,12 @@ int gld_interpret_ether(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo, packet_flag_t flags) { - struct ether_mac_frm *mh; + struct ether_header *mh; gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt; struct llc_snap_hdr *snaphdr; - mblk_t *pmp = NULL; + mblk_t *pmp = NULL, *savemp = mp; unsigned short typelen; + int ret = 0; /* * Quickly handle receive fastpath for IPQ hack. @@ -160,13 +160,13 @@ gld_interpret_ether(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo, * Check whether the header is contiguous, which * also implicitly makes sure the packet is big enough. */ - if (MBLKL(mp) < sizeof (struct ether_mac_frm)) + if (MBLKL(mp) < sizeof (struct ether_header)) return (-1); - mh = (struct ether_mac_frm *)mp->b_rptr; + mh = (struct ether_header *)mp->b_rptr; pktinfo->ethertype = REF_NET_USHORT(mh->ether_type); - pktinfo->isForMe = mac_eq(mh->ether_dhost, + pktinfo->isForMe = mac_eq(&mh->ether_dhost, mac_pvt->curr_macaddr, macinfo->gldm_addrlen); - pktinfo->macLen = sizeof (struct ether_mac_frm); + pktinfo->macLen = sizeof (struct ether_header); return (0); } @@ -176,11 +176,11 @@ gld_interpret_ether(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo, pktinfo->pktLen = msgdsize(mp); /* make sure packet has at least a whole mac header */ - if (pktinfo->pktLen < sizeof (struct ether_mac_frm)) + if (pktinfo->pktLen < sizeof (struct ether_header)) return (-1); /* make sure the mac header falls into contiguous memory */ - if (MBLKL(mp) < sizeof (struct ether_mac_frm)) { + if (MBLKL(mp) < sizeof (struct ether_header)) { if ((pmp = msgpullup(mp, -1)) == NULL) { #ifdef GLD_DEBUG if (gld_debug & GLDERRS) @@ -192,12 +192,12 @@ gld_interpret_ether(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo, mp = pmp; /* this mblk contains the whole mac header */ } - mh = (struct ether_mac_frm *)mp->b_rptr; + mh = (struct ether_header *)mp->b_rptr; /* Check to see if the mac is a broadcast or multicast address. */ - if (mac_eq(mh->ether_dhost, ether_broadcast, macinfo->gldm_addrlen)) + if (mac_eq(&mh->ether_dhost, ether_broadcast, macinfo->gldm_addrlen)) pktinfo->isBroadcast = 1; - else if (mh->ether_dhost[0] & 1) + else if (mh->ether_dhost.ether_addr_octet[0] & 1) pktinfo->isMulticast = 1; typelen = REF_NET_USHORT(mh->ether_type); @@ -208,11 +208,40 @@ gld_interpret_ether(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo, * of non null 'macinfo->gldm_send_tagged'. */ if (flags == GLD_TX) { - if ((typelen == VLAN_TPID) && - (macinfo->gldm_send_tagged != NULL)) { - ovbcopy(mp->b_rptr, - mp->b_rptr + VTAG_SIZE, - 2 * ETHERADDRL); + if ((typelen == ETHERTYPE_VLAN) && + (macinfo->gldm_send_tagged != NULL)) { + struct ether_vlan_header *evhp; + uint16_t tci; + + if ((MBLKL(mp) < sizeof (struct ether_vlan_header)) && + (pullupmsg(mp, sizeof (struct ether_vlan_header)) + == 0)) { + ret = -1; + goto out; + } + evhp = (struct ether_vlan_header *)mp->b_rptr; + tci = REF_NET_USHORT(evhp->ether_tci); + + /* + * We don't allow the VID and priority are both zero. + */ + if ((GLD_VTAG_PRI((int32_t)tci) == 0 && + GLD_VTAG_VID((int32_t)tci) == VLAN_VID_NONE) || + (GLD_VTAG_CFI((uint32_t)tci)) != VLAN_CFI_ETHER) { + ret = -1; + goto out; + } + + /* + * Remember the VTAG info in order to reinsert it, + * Then strip the tag. This is required because some + * drivers do not allow the size of message (passed + * by the gldm_send_tagged() function) to be greater + * than ETHERMAX. + */ + GLD_SAVE_MBLK_VTAG(savemp, GLD_TCI2VTAG(tci)); + ovbcopy(mp->b_rptr, mp->b_rptr + VTAG_SIZE, + 2 * ETHERADDRL); mp->b_rptr += VTAG_SIZE; } goto out; /* Got all info we need for xmit case */ @@ -224,15 +253,15 @@ gld_interpret_ether(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo, * Deal with the mac header */ - mac_copy(mh->ether_dhost, pktinfo->dhost, macinfo->gldm_addrlen); - mac_copy(mh->ether_shost, pktinfo->shost, macinfo->gldm_addrlen); + mac_copy(&mh->ether_dhost, pktinfo->dhost, macinfo->gldm_addrlen); + mac_copy(&mh->ether_shost, pktinfo->shost, macinfo->gldm_addrlen); pktinfo->isLooped = mac_eq(pktinfo->shost, mac_pvt->curr_macaddr, macinfo->gldm_addrlen); pktinfo->isForMe = mac_eq(pktinfo->dhost, mac_pvt->curr_macaddr, macinfo->gldm_addrlen); - pktinfo->macLen = sizeof (struct ether_mac_frm); + pktinfo->macLen = sizeof (struct ether_header); if (typelen > ETHERMTU) { pktinfo->ethertype = typelen; /* use type interpretation */ @@ -247,7 +276,7 @@ gld_interpret_ether(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo, */ { int delta = pktinfo->pktLen - - (sizeof (struct ether_mac_frm) + typelen); + (sizeof (struct ether_header) + typelen); if (delta > 0 && adjmsg(mp, -delta)) pktinfo->pktLen -= delta; @@ -263,10 +292,10 @@ gld_interpret_ether(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo, pktinfo->isLLC = 1; if (gld_global_options & GLD_OPT_NO_ETHRXSNAP || - pktinfo->pktLen < pktinfo->macLen + LLC_SNAP_HDR_LEN) + pktinfo->pktLen < pktinfo->macLen + LLC_SNAP_HDR_LEN) goto out; - if (MBLKL(mp) < sizeof (struct ether_mac_frm) + LLC_SNAP_HDR_LEN && + if (MBLKL(mp) < sizeof (struct ether_header) + LLC_SNAP_HDR_LEN && MBLKL(mp) < pktinfo->pktLen) { /* * we don't have the entire packet within the first mblk (and @@ -298,7 +327,7 @@ out: if (pmp != NULL) freemsg(pmp); - return (0); + return (ret); } mblk_t * @@ -310,7 +339,7 @@ gld_unitdata_ether(gld_t *gld, mblk_t *mp) mac_addr_t dhost; unsigned short typelen; mblk_t *nmp; - struct ether_mac_frm *mh; + struct ether_header *mh; int hdrlen; uint32_t vptag; gld_vlan_t *gld_vlan; @@ -335,7 +364,7 @@ gld_unitdata_ether(gld_t *gld, mblk_t *mp) if (typelen <= ETHERMTU) typelen = msgdsize(mp); - hdrlen = sizeof (struct ether_mac_frm); + hdrlen = sizeof (struct ether_header); /* * Check to see if VLAN is enabled on this stream @@ -371,7 +400,7 @@ gld_unitdata_ether(gld_t *gld, mblk_t *mp) nmp->b_rptr -= sizeof (typelen); SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, typelen); - if (hdrlen > sizeof (struct ether_mac_frm)) { + if (hdrlen > sizeof (struct ether_header)) { nmp->b_rptr -= sizeof (uint16_t); SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, vptag); vptag >>= 16; @@ -379,16 +408,67 @@ gld_unitdata_ether(gld_t *gld, mblk_t *mp) SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, vptag); } nmp->b_rptr -= (ETHERADDRL * 2); - mh = (struct ether_mac_frm *)nmp->b_rptr; - mac_copy(dhost, mh->ether_dhost, macinfo->gldm_addrlen); + mh = (struct ether_header *)nmp->b_rptr; + mac_copy(dhost, &mh->ether_dhost, macinfo->gldm_addrlen); /* * We access the mac address without the mutex to prevent * mutex contention (BUG 4211361) */ mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr, - mh->ether_shost, macinfo->gldm_addrlen); + &mh->ether_shost, macinfo->gldm_addrlen); + + return (nmp); +} + +/* + * Insert the VLAN tag into the packet. The packet now is an Ethernet header + * without VLAN tag information. + */ +mblk_t * +gld_insert_vtag_ether(mblk_t *mp, uint32_t vtag) +{ + struct ether_vlan_header *evhp; + struct ether_header *ehp; + mblk_t *nmp; + + if (vtag == VLAN_VID_NONE) + return (mp); + + if (DB_REF(mp) == 1 && MBLKHEAD(mp) >= VTAG_SIZE) { + /* it fits at the beginning of the message block */ + nmp = mp; + ovbcopy(nmp->b_rptr, nmp->b_rptr - VTAG_SIZE, 2 * ETHERADDRL); + nmp->b_rptr -= VTAG_SIZE; + evhp = (struct ether_vlan_header *)nmp->b_rptr; + } else { + /* we need to allocate one */ + if ((nmp = allocb(sizeof (struct ether_vlan_header), + BPRI_MED)) == NULL) { + return (NULL); + } + nmp->b_wptr += sizeof (struct ether_vlan_header); + + /* transfer the ether_header fields */ + evhp = (struct ether_vlan_header *)nmp->b_rptr; + ehp = (struct ether_header *)mp->b_rptr; + mac_copy(&ehp->ether_dhost, &evhp->ether_dhost, ETHERADDRL); + mac_copy(&ehp->ether_shost, &evhp->ether_shost, ETHERADDRL); + bcopy(&ehp->ether_type, &evhp->ether_type, sizeof (uint16_t)); + + /* offset the mp of the MAC header length. */ + mp->b_rptr += sizeof (struct ether_header); + if (MBLKL(mp) == 0) { + nmp->b_cont = mp->b_cont; + freeb(mp); + } else { + nmp->b_cont = mp; + } + } + SET_NET_USHORT(evhp->ether_tci, vtag); + vtag >>= 16; + SET_NET_USHORT(evhp->ether_tpid, vtag); return (nmp); } @@ -400,7 +480,7 @@ gld_fastpath_ether(gld_t *gld, mblk_t *mp) struct gld_dlsap *gldp = DLSAP(dlp, dlp->dl_dest_addr_offset); unsigned short typelen; mblk_t *nmp; - struct ether_mac_frm *mh; + struct ether_header *mh; int hdrlen; uint32_t vptag; gld_vlan_t *gld_vlan; @@ -425,7 +505,7 @@ gld_fastpath_ether(gld_t *gld, mblk_t *mp) * Initialize the fast path header to include the * basic source address information and type field. */ - hdrlen = sizeof (struct ether_mac_frm); + hdrlen = sizeof (struct ether_header); /* * Check to see if VLAN is enabled on this stream @@ -452,7 +532,7 @@ gld_fastpath_ether(gld_t *gld, mblk_t *mp) * If the header is for a VLAN stream, then add * in the VLAN tag to the clone header. */ - if (hdrlen > sizeof (struct ether_mac_frm)) { + if (hdrlen > sizeof (struct ether_header)) { nmp->b_rptr -= sizeof (uint16_t); SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, vptag); vptag >>= 16; @@ -460,12 +540,12 @@ gld_fastpath_ether(gld_t *gld, mblk_t *mp) SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, vptag); } nmp->b_rptr -= (ETHERADDRL * 2); - mh = (struct ether_mac_frm *)nmp->b_rptr; - mac_copy(gldp->glda_addr, mh->ether_dhost, macinfo->gldm_addrlen); + mh = (struct ether_header *)nmp->b_rptr; + mac_copy(gldp->glda_addr, &mh->ether_dhost, macinfo->gldm_addrlen); GLDM_LOCK(macinfo, RW_WRITER); mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr, - mh->ether_shost, macinfo->gldm_addrlen); + &mh->ether_shost, macinfo->gldm_addrlen); GLDM_UNLOCK(macinfo); return (nmp); diff --git a/usr/src/uts/common/io/mac/mac.c b/usr/src/uts/common/io/mac/mac.c index 80d3583fbd..3f414af351 100644 --- a/usr/src/uts/common/io/mac/mac.c +++ b/usr/src/uts/common/io/mac/mac.c @@ -1719,6 +1719,8 @@ mac_header_cook(mac_handle_t mh, mblk_t *mp) if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) { if (DB_REF(mp) > 1) { mblk_t *newmp = copymsg(mp); + if (newmp == NULL) + return (NULL); freemsg(mp); mp = newmp; } @@ -1735,6 +1737,8 @@ mac_header_uncook(mac_handle_t mh, mblk_t *mp) if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) { if (DB_REF(mp) > 1) { mblk_t *newmp = copymsg(mp); + if (newmp == NULL) + return (NULL); freemsg(mp); mp = newmp; } diff --git a/usr/src/uts/common/io/pfmod.c b/usr/src/uts/common/io/pfmod.c index 8f13b47877..9a7d66e995 100644 --- a/usr/src/uts/common/io/pfmod.c +++ b/usr/src/uts/common/io/pfmod.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -343,7 +342,9 @@ pfioctl(queue_t *wq, mblk_t *mp) struct Pf_ext_packetfilt *upfp; struct packetfilt *opfp; ushort_t *fwp; - int maxoff, arg; + int arg; + int maxoff = 0; + int maxoffreg = 0; struct iocblk *iocp = (struct iocblk *)mp->b_rptr; int error; @@ -406,7 +407,6 @@ pfioctl(queue_t *wq, mblk_t *mp) * body to pull up. This code depends on the * filter encoding. */ - maxoff = 0; for (fwp = pfp->pf_Filter; fwp < pfp->pf_FilterEnd; fwp++) { arg = *fwp & ((1 << ENF_NBPA) - 1); switch (arg) { @@ -415,7 +415,16 @@ pfioctl(queue_t *wq, mblk_t *mp) maxoff = arg; break; + case ENF_LOAD_OFFSET: + /* Point to the offset */ + fwp++; + if (*fwp > maxoffreg) + maxoffreg = *fwp; + break; + case ENF_PUSHLIT: + case ENF_BRTR: + case ENF_BRFL: /* Skip over the literal. */ fwp++; break; @@ -426,6 +435,7 @@ pfioctl(queue_t *wq, mblk_t *mp) case ENF_PUSHFF00: case ENF_PUSH00FF: case ENF_NOPUSH: + case ENF_POP: break; } } @@ -433,8 +443,7 @@ pfioctl(queue_t *wq, mblk_t *mp) /* * Convert word offset to length in bytes. */ - pfp->pf_PByteLen = (maxoff + 1) * sizeof (ushort_t); - + pfp->pf_PByteLen = (maxoff + maxoffreg + 1) * sizeof (ushort_t); miocack(wq, mp, 0, 0); break; @@ -448,23 +457,10 @@ pfioctl(queue_t *wq, mblk_t *mp) /* #define INNERDEBUG 1 */ #ifdef INNERDEBUG -#define enprintf(flags) if (enDebug & (flags)) printf - -/* - * Symbolic definitions for enDebug flag bits - * ENDBG_TRACE should be 1 because it is the most common - * use in the code, and the compiler generates faster code - * for testing the low bit in a word. - */ - -#define ENDBG_TRACE 1 /* trace most operations */ -#define ENDBG_DESQ 2 /* trace descriptor queues */ -#define ENDBG_INIT 4 /* initialization info */ -#define ENDBG_SCAV 8 /* scavenger operation */ -#define ENDBG_ABNORM 16 /* abnormal events */ - -int enDebug = /* ENDBG_ABNORM | ENDBG_INIT | ENDBG_TRACE */ -1; -#endif /* INNERDEBUG */ +#define enprintf(a) printf a +#else +#define enprintf(a) +#endif /* * Apply the packet filter given by pfp to the packet given by @@ -493,15 +489,13 @@ FilterPacket(struct packdesc *pp, struct epacketfilt *pfp) ushort_t *fpe; unsigned op; unsigned arg; + unsigned offreg = 0; ushort_t stack[ENMAXFILTERS+1]; fp = &pfp->pf_Filter[0]; fpe = pfp->pf_FilterEnd; -#ifdef INNERDEBUG - enprintf(ENDBG_TRACE)("FilterPacket(%p, %p, %p, %p):\n", - pp, pfp, fp, fpe); -#endif + enprintf(("FilterPacket(%p, %p, %p, %p):\n", pp, pfp, fp, fpe)); /* * Push TRUE on stack to start. The stack size is chosen such @@ -525,14 +519,12 @@ FilterPacket(struct packdesc *pp, struct epacketfilt *pfp) * if it were less than ENF_PUSHWORD before, * it would now be huge. */ - if (arg < maxhdr) - *--sp = pp->pd_hdr[arg]; - else if (arg < maxword) - *--sp = pp->pd_body[arg - maxhdr]; + if (arg + offreg < maxhdr) + *--sp = pp->pd_hdr[arg + offreg]; + else if (arg + offreg < maxword) + *--sp = pp->pd_body[arg - maxhdr + offreg]; else { -#ifdef INNERDEBUG - enprintf(ENDBG_TRACE)("=>0(len)\n"); -#endif + enprintf(("=>0(len)\n")); return (0); } break; @@ -554,14 +546,42 @@ FilterPacket(struct packdesc *pp, struct epacketfilt *pfp) case ENF_PUSH00FF: *--sp = 0x00ff; break; + case ENF_LOAD_OFFSET: + offreg = *fp++; + break; + case ENF_BRTR: + if (*sp != 0) + fp += *fp; + else + fp++; + if (fp >= fpe) { + enprintf(("BRTR: fp>=fpe\n")); + return (0); + } + break; + case ENF_BRFL: + if (*sp == 0) + fp += *fp; + else + fp++; + if (fp >= fpe) { + enprintf(("BRFL: fp>=fpe\n")); + return (0); + } + break; + case ENF_POP: + ++sp; + if (sp > &stack[ENMAXFILTERS]) { + enprintf(("stack underflow\n")); + return (0); + } + break; case ENF_NOPUSH: break; } if (sp < &stack[2]) { /* check stack overflow: small yellow zone */ -#ifdef INNERDEBUG - enprintf(ENDBG_TRACE)("=>0(--sp)\n"); -#endif + enprintf(("=>0(--sp)\n")); return (0); } @@ -573,18 +593,14 @@ FilterPacket(struct packdesc *pp, struct epacketfilt *pfp) * on stack to evaluate. */ if (sp > &stack[ENMAXFILTERS-2]) { -#ifdef INNERDEBUG - enprintf(ENDBG_TRACE)("=>0(sp++)\n"); -#endif + enprintf(("=>0(sp++)\n")); return (0); } arg = *sp++; switch (op) { default: -#ifdef INNERDEBUG - enprintf(ENDBG_TRACE)("=>0(def)\n"); -#endif + enprintf(("=>0(def)\n")); return (0); case opx(ENF_AND): *sp &= arg; @@ -618,40 +634,30 @@ FilterPacket(struct packdesc *pp, struct epacketfilt *pfp) case opx(ENF_COR): if (*sp++ == arg) { -#ifdef INNERDEBUG - enprintf(ENDBG_TRACE)("=>COR %x\n", *sp); -#endif + enprintf(("=>COR %x\n", *sp)); return (1); } break; case opx(ENF_CAND): if (*sp++ != arg) { -#ifdef INNERDEBUG - enprintf(ENDBG_TRACE)("=>CAND %x\n", *sp); -#endif + enprintf(("=>CAND %x\n", *sp)); return (0); } break; case opx(ENF_CNOR): if (*sp++ == arg) { -#ifdef INNERDEBUG - enprintf(ENDBG_TRACE)("=>COR %x\n", *sp); -#endif + enprintf(("=>COR %x\n", *sp)); return (0); } break; case opx(ENF_CNAND): if (*sp++ != arg) { -#ifdef INNERDEBUG - enprintf(ENDBG_TRACE)("=>CNAND %x\n", *sp); -#endif + enprintf(("=>CNAND %x\n", *sp)); return (1); } break; } } -#ifdef INNERDEBUG - enprintf(ENDBG_TRACE)("=>%x\n", *sp); -#endif + enprintf(("=>%x\n", *sp)); return (*sp); } diff --git a/usr/src/uts/common/io/rge/rge_rxtx.c b/usr/src/uts/common/io/rge/rge_rxtx.c index 561800271d..3585da8135 100755 --- a/usr/src/uts/common/io/rge/rge_rxtx.c +++ b/usr/src/uts/common/io/rge/rge_rxtx.c @@ -276,7 +276,7 @@ rge_receive_packet(rge_t *rgep, uint32_t slot) 2 * ETHERADDRL); mp->b_rptr -= VLAN_TAGSZ; ehp = (struct ether_vlan_header *)mp->b_rptr; - ehp->ether_tpid = htons(VLAN_TPID); + ehp->ether_tpid = htons(ETHERTYPE_VLAN); ehp->ether_tci = htons(vtag); rgep->stats.rbytes += VLAN_TAGSZ; } @@ -627,7 +627,7 @@ rge_send(rge_t *rgep, mblk_t *mp) ASSERT(MBLKL(mp) >= sizeof (struct ether_header)); tci = 0; ehp = (struct ether_vlan_header *)mp->b_rptr; - if (ehp->ether_tpid == htons(VLAN_TPID)) + if (ehp->ether_tpid == htons(ETHERTYPE_VLAN)) tci = ntohs(ehp->ether_tci); /* diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile index 2754405b01..df16a73f89 100644 --- a/usr/src/uts/common/sys/Makefile +++ b/usr/src/uts/common/sys/Makefile @@ -533,6 +533,7 @@ CHKHDRS= \ vfstab.h \ vgareg.h \ visual_io.h \ + vlan.h \ vm.h \ vmem.h \ vmem_impl.h \ diff --git a/usr/src/uts/common/sys/dld_impl.h b/usr/src/uts/common/sys/dld_impl.h index 6c1c3ade21..c3274aea0b 100644 --- a/usr/src/uts/common/sys/dld_impl.h +++ b/usr/src/uts/common/sys/dld_impl.h @@ -216,17 +216,16 @@ extern void dld_str_destroy(dld_str_t *); extern int dld_str_attach(dld_str_t *, t_uscalar_t); extern void dld_str_detach(dld_str_t *); extern void dld_str_rx_raw(void *, mac_resource_handle_t, - mblk_t *, size_t); + mblk_t *, mac_header_info_t *); extern void dld_str_rx_fastpath(void *, mac_resource_handle_t, - mblk_t *, size_t); + mblk_t *, mac_header_info_t *); extern void dld_str_rx_unitdata(void *, mac_resource_handle_t, - mblk_t *, size_t); + mblk_t *, mac_header_info_t *); extern void dld_tx_flush(dld_str_t *); extern void dld_tx_enqueue(dld_str_t *, mblk_t *, boolean_t); extern void dld_str_notify_ind(dld_str_t *); - extern void str_mdata_fastpath_put(dld_str_t *, mblk_t *); -extern void str_mdata_raw_put(dld_str_t *, mblk_t *); +extern void dld_tx_single(dld_str_t *, mblk_t *); /* * dld_proto.c diff --git a/usr/src/uts/common/sys/dls.h b/usr/src/uts/common/sys/dls.h index 12f9a6a8a2..f43cb816de 100644 --- a/usr/src/uts/common/sys/dls.h +++ b/usr/src/uts/common/sys/dls.h @@ -91,10 +91,11 @@ extern int dls_multicst_add(dls_channel_t, const uint8_t *); extern int dls_multicst_remove(dls_channel_t, const uint8_t *); extern mblk_t *dls_header(dls_channel_t, const uint8_t *, uint16_t, uint_t, - mblk_t *); + mblk_t **); extern int dls_header_info(dls_channel_t, mblk_t *, mac_header_info_t *); -typedef void (*dls_rx_t)(void *, mac_resource_handle_t, mblk_t *, size_t); +typedef void (*dls_rx_t)(void *, mac_resource_handle_t, mblk_t *, + mac_header_info_t *); extern void dls_rx_set(dls_channel_t, dls_rx_t, void *); diff --git a/usr/src/uts/common/sys/dls_impl.h b/usr/src/uts/common/sys/dls_impl.h index ad97fe72da..0b5dec3fb1 100644 --- a/usr/src/uts/common/sys/dls_impl.h +++ b/usr/src/uts/common/sys/dls_impl.h @@ -118,7 +118,7 @@ extern void dls_link_rele(dls_link_t *); extern void dls_link_add(dls_link_t *, uint32_t, dls_impl_t *); extern void dls_link_remove(dls_link_t *, dls_impl_t *); extern int dls_link_header_info(dls_link_t *, mblk_t *, - mac_header_info_t *, uint16_t *); + mac_header_info_t *); extern int dls_mac_hold(dls_link_t *); extern void dls_mac_rele(dls_link_t *); @@ -138,7 +138,8 @@ extern void dls_init(void); extern int dls_fini(void); extern boolean_t dls_accept(dls_impl_t *, mac_header_info_t *, dls_rx_t *, void **); -extern boolean_t dls_accept_loopback(dls_impl_t *, dls_rx_t *, void **); +extern boolean_t dls_accept_loopback(dls_impl_t *, mac_header_info_t *, + dls_rx_t *, void **); #ifdef __cplusplus } diff --git a/usr/src/uts/common/sys/dls_soft_ring.h b/usr/src/uts/common/sys/dls_soft_ring.h index 96a5e7ccc4..cc7365c9dc 100644 --- a/usr/src/uts/common/sys/dls_soft_ring.h +++ b/usr/src/uts/common/sys/dls_soft_ring.h @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -16,10 +16,11 @@ extern "C" { #include <sys/processor.h> #include <sys/stream.h> #include <sys/squeue.h> +#include <sys/mac.h> #define S_RING_NAMELEN 64 -typedef void (*s_ring_proc_t)(void *, void *, mblk_t *, size_t); +typedef void (*s_ring_proc_t)(void *, void *, mblk_t *, mac_header_info_t *); typedef struct soft_ring_s { /* Keep the most used members 64bytes cache aligned */ @@ -85,8 +86,8 @@ extern void soft_ring_set_destroy(soft_ring_t **, int); extern void soft_ring_process(soft_ring_t *, mblk_t *, uint8_t); extern void soft_ring_bind(void *, processorid_t); extern void soft_ring_unbind(void *); -extern void dls_ether_soft_ring_fanout(void *, - void *, mblk_t *, size_t); +extern void dls_ether_soft_ring_fanout(void *, void *, mblk_t *, + mac_header_info_t *); extern boolean_t dls_soft_ring_enable(dls_channel_t, dl_capab_dls_t *); extern void dls_soft_ring_disable(dls_channel_t); extern boolean_t dls_soft_ring_workers(dls_channel_t); diff --git a/usr/src/uts/common/sys/ethernet.h b/usr/src/uts/common/sys/ethernet.h index 3161f73608..9e35b2ec3d 100644 --- a/usr/src/uts/common/sys/ethernet.h +++ b/usr/src/uts/common/sys/ethernet.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -71,6 +70,15 @@ struct ether_vlan_header { ushort_t ether_type; }; +/* + * The VLAN tag. Available for applications that cannot make use of struct + * ether_vlan_header because they assume Ethernet encapsulation. + */ +struct ether_vlan_extinfo { + ushort_t ether_tci; + ushort_t ether_type; +}; + #define ETHERTYPE_PUP (0x0200) /* PUP protocol */ #define ETHERTYPE_802_MIN (0x0600) /* Min valid ethernet type */ /* under IEEE 802.3 rules */ @@ -79,6 +87,7 @@ struct ether_vlan_header { #define ETHERTYPE_REVARP (0x8035) /* Reverse ARP */ #define ETHERTYPE_AT (0x809b) /* AppleTalk protocol */ #define ETHERTYPE_AARP (0x80f3) /* AppleTalk ARP */ +#define ETHERTYPE_VLAN (0x8100) /* 802.1Q VLAN */ #define ETHERTYPE_IPV6 (0x86dd) /* IPv6 */ #define ETHERTYPE_SLOW (0x8809) /* Slow Protocol */ #define ETHERTYPE_PPPOED (0x8863) /* PPPoE Discovery Stage */ diff --git a/usr/src/uts/common/sys/gld.h b/usr/src/uts/common/sys/gld.h index e42bb62f28..3f3c01848e 100644 --- a/usr/src/uts/common/sys/gld.h +++ b/usr/src/uts/common/sys/gld.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -344,21 +343,27 @@ extern int gld_rsrv(queue_t *); /* * Macros to construct a TCI or VTAG. The user must ensure values are in - * range. In particular, VID 0 is not a valid argument to these constructor - * macros; when the VID is 0 (VLAN_VID_NONE), the whole VTAG should be 0 - * (VLAN_VTAG_NONE), not 0x81000000. + * range. Note that in the special case of priority tag, VLAN_VID_NONE + * is also a valid argument to these constructor macros. */ #define GLD_MAKE_TCI(pri, cfi, vid) (((pri) << VLAN_PRI_SHIFT) | \ ((cfi) << VLAN_CFI_SHIFT) | \ ((vid) << VLAN_VID_SHIFT)) -#define GLD_MAKE_VTAG(tci) ((VLAN_TPID << VLAN_TPID_SHIFT) | (tci)) +#define GLD_MAKE_VTAG(pri, cfi, vid) \ + (((uint32_t)ETHERTYPE_VLAN << VLAN_TPID_SHIFT) | \ + ((pri) << VLAN_PRI_SHIFT) | \ + ((cfi) << VLAN_CFI_SHIFT) | \ + ((vid) << VLAN_VID_SHIFT)) + +#define GLD_TCI2VTAG(tci) \ + (((uint32_t)ETHERTYPE_VLAN << VLAN_TPID_SHIFT) | (tci)) /* * Macros to construct a prototype TCI/VTAG and then convert it to a real one */ #define GLD_MK_PTCI(cfi, vid) GLD_MAKE_TCI(VLAN_PRI_MAX, cfi, vid) -#define GLD_MK_PTAG(cfi, vid) GLD_MAKE_VTAG(GLD_MK_PTCI(cfi, vid)) +#define GLD_MK_PTAG(cfi, vid) GLD_MAKE_VTAG(VLAN_PRI_MAX, cfi, vid) #define GLD_MK_PMSK(pri) (((pri) << VLAN_PRI_SHIFT) | ~VLAN_PRI_MASK) #define GLD_MK_VTAG(ptag, pri) ((ptag) & GLD_MK_PMSK(pri)) diff --git a/usr/src/uts/common/sys/gldpriv.h b/usr/src/uts/common/sys/gldpriv.h index 6b864064b9..cbbb872232 100644 --- a/usr/src/uts/common/sys/gldpriv.h +++ b/usr/src/uts/common/sys/gldpriv.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -207,6 +206,7 @@ typedef struct pktinfo { uint_t vid:12; uint_t wasAccepted:1; uint_t nosource:1; + uint_t isTagged:1; uint_t macLen; uint_t hdrLen; uint_t pktLen; @@ -246,9 +246,10 @@ typedef struct { uint_t mac_type; uint_t mtu_size; int hdr_size; - int (*interpreter)(gld_mac_info_t *, mblk_t *, pktinfo_t *, int); + int (*interpreter)(gld_mac_info_t *, mblk_t *, pktinfo_t *, + packet_flag_t); void (*interpreter_mdt)(gld_mac_info_t *, mblk_t *, - struct pdescinfo_s *, pktinfo_t *, int); + struct pdescinfo_s *, pktinfo_t *, mdt_packet_flag_t); mblk_t *(*mkfastpath)(gld_t *, mblk_t *); mblk_t *(*mkunitdata)(gld_t *, mblk_t *); void (*init)(gld_mac_info_t *); @@ -338,16 +339,16 @@ typedef struct gld_vlan { gld_mac_info_t *gldv_mac; queue_t *gldv_ipq; queue_t *gldv_ipv6q; - uint8_t gldv_ipq_flags; struct gld *gldv_str_next; /* list of attached streams */ struct gld *gldv_str_prev; kstat_t *gldv_kstatp; struct gld_stats *gldv_stats; + /* The number of streams that are in promiscous mode */ + uint_t gldv_nprom; + /* The number of streams that are interested in VLAN tagged packets. */ + uint_t gldv_nvlan_sap; } gld_vlan_t; -#define IPQ_DISABLED 0x01 -#define IPQ_FORBIDDEN 0x02 - #define VLAN_HASHSZ 23 /* Per-mac info used by GLD */ @@ -587,16 +588,6 @@ struct llc_snap_hdr { #define LSAP_SNAP 0xaa /* SAP for SubNet Access Protocol */ #define CNTL_LLC_UI 0x03 /* un-numbered information packet */ -/* ============================ */ -/* Ethernet related definitions */ -/* ============================ */ - -struct ether_mac_frm { - mac_addr_t ether_dhost; - mac_addr_t ether_shost; - ushort_t ether_type; -}; - /* ======================== */ /* FDDI related definitions */ /* ======================== */ @@ -626,6 +617,42 @@ struct tr_mac_frm { struct gld_ri tr_ri; /* Routing Information Field */ }; +/* + * Note that the pad field is used to save the value of tci. + */ +#define GLD_SAVE_MBLK_VTAG(mp, vtag) (DB_TCI(mp) = GLD_VTAG_TCI(vtag)) +#define GLD_CLEAR_MBLK_VTAG(mp) GLD_SAVE_MBLK_VTAG(mp, 0) +#define GLD_GET_MBLK_VTAG(mp) GLD_TCI2VTAG(DB_TCI(mp)) + +int gld_interpret_ether(gld_mac_info_t *, mblk_t *, pktinfo_t *, packet_flag_t); +int gld_interpret_fddi(gld_mac_info_t *, mblk_t *, pktinfo_t *, packet_flag_t); +int gld_interpret_tr(gld_mac_info_t *, mblk_t *, pktinfo_t *, packet_flag_t); +int gld_interpret_ib(gld_mac_info_t *, mblk_t *, pktinfo_t *, packet_flag_t); +void gld_interpret_mdt_ib(gld_mac_info_t *, mblk_t *, pdescinfo_t *, + pktinfo_t *, mdt_packet_flag_t); + +mblk_t *gld_fastpath_ether(gld_t *, mblk_t *); +mblk_t *gld_fastpath_fddi(gld_t *, mblk_t *); +mblk_t *gld_fastpath_tr(gld_t *, mblk_t *); +mblk_t *gld_fastpath_ib(gld_t *, mblk_t *); + +mblk_t *gld_insert_vtag_ether(mblk_t *, uint32_t); + +mblk_t *gld_unitdata_ether(gld_t *, mblk_t *); +mblk_t *gld_unitdata_fddi(gld_t *, mblk_t *); +mblk_t *gld_unitdata_tr(gld_t *, mblk_t *); +mblk_t *gld_unitdata_ib(gld_t *, mblk_t *); + +void gld_init_ether(gld_mac_info_t *); +void gld_init_fddi(gld_mac_info_t *); +void gld_init_tr(gld_mac_info_t *); +void gld_init_ib(gld_mac_info_t *); + +void gld_uninit_ether(gld_mac_info_t *); +void gld_uninit_fddi(gld_mac_info_t *); +void gld_uninit_tr(gld_mac_info_t *); +void gld_uninit_ib(gld_mac_info_t *); + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/common/sys/mac.h b/usr/src/uts/common/sys/mac.h index 729ecfaa9e..ee51f24423 100644 --- a/usr/src/uts/common/sys/mac.h +++ b/usr/src/uts/common/sys/mac.h @@ -28,6 +28,7 @@ #pragma ident "%Z%%M% %I% %E% SMI" +#include <sys/types.h> #include <sys/ddi.h> #include <sys/sunddi.h> #include <sys/stream.h> @@ -350,6 +351,8 @@ typedef struct mac_header_info_s { uint32_t mhi_origsap; uint32_t mhi_bindsap; mac_addrtype_t mhi_dsttype; + boolean_t mhi_istagged; + uint16_t mhi_tci; } mac_header_info_t; /* diff --git a/usr/src/uts/common/sys/pfmod.h b/usr/src/uts/common/sys/pfmod.h index 682f3ec03d..379847e3e6 100644 --- a/usr/src/uts/common/sys/pfmod.h +++ b/usr/src/uts/common/sys/pfmod.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1991,1997-1998 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #ifndef _SYS_PFMOD_H @@ -43,7 +42,7 @@ extern "C" { #define PF_MAXFILTERS 2047 /* max short words for newpacketfilt */ /* - * filter structure for SETF + * filter structure for SETF */ struct packetfilt { uchar_t Pf_Priority; /* priority of filter */ @@ -61,34 +60,34 @@ struct Pf_ext_packetfilt { }; /* - * We now allow specification of up to MAXFILTERS (short) words of a filter - * command list to be applied to incoming packets to determine if - * those packets should be given to a particular open ethernet file. - * Alternatively, PF_MAXFILTERS and Pf_ext_packetfilt structure can be - * used in case even bigger filter command list is needed. + * We now allow specification of up to MAXFILTERS (short) words of a filter + * command list to be applied to incoming packets to determine if + * those packets should be given to a particular open ethernet file. + * Alternatively, PF_MAXFILTERS and Pf_ext_packetfilt structure can be + * used in case even bigger filter command list is needed. * - * In this context, "word" means a short (16-bit) integer. + * In this context, "word" means a short (16-bit) integer. * - * Each open enet file specifies the filter command list via ioctl. - * Each filter command list specifies a sequence of actions that leaves a - * boolean value on the top of an internal stack. Each word of the - * command list specifies an action from the set {PUSHLIT, PUSHZERO, - * PUSHWORD+N} which respectively push the next word of the filter, zero, - * or word N of the incoming packet on the stack, and a binary operator - * from the set {EQ, LT, LE, GT, GE, AND, OR, XOR} which operates on the - * top two elements of the stack and replaces them with its result. The - * special action NOPUSH and the special operator NOP can be used to only - * perform the binary operation or to only push a value on the stack. + * The filter command list is specified using ioctl(). Each filter command + * list specifies a sequence of actions that leaves a boolean value on the + * top of an internal stack. There is also an offset register which is + * initialized to zero. Each word of the command list specifies an action + * from the set {PUSHLIT, PUSHZERO, PUSHWORD+N, LOAD_OFFSET, BRTR, BRFL, POP} + * (see #defines below for definitions), and a binary operator from the set + * {EQ, LT, LE, GT, GE, AND, OR, XOR} which operates on the top two elements + * of the stack and replaces them with its result. The special action NOPUSH + * and the special operator NOP can be used to only perform the binary + * operation or to only push a value on the stack. * - * If the final value of the filter operation is true, then the packet is - * accepted for the open file which specified the filter. + * If the final value of the filter operation is true, then the packet is + * accepted for the open file which specified the filter. */ -/* these must sum to sizeof (ushort_t)! */ +/* these must sum to sizeof (ushort_t)! */ #define ENF_NBPA 10 /* # bits / action */ #define ENF_NBPO 6 /* # bits / operator */ -/* binary operators */ +/* binary operators */ #define ENF_NOP (0 << ENF_NBPA) #define ENF_EQ (1 << ENF_NBPA) #define ENF_LT (2 << ENF_NBPA) @@ -104,14 +103,18 @@ struct Pf_ext_packetfilt { #define ENF_CNAND (12 << ENF_NBPA) #define ENF_NEQ (13 << ENF_NBPA) -/* stack actions */ +/* stack actions */ #define ENF_NOPUSH 0 -#define ENF_PUSHLIT 1 -#define ENF_PUSHZERO 2 -#define ENF_PUSHONE 3 -#define ENF_PUSHFFFF 4 -#define ENF_PUSHFF00 5 -#define ENF_PUSH00FF 6 +#define ENF_PUSHLIT 1 /* Push the next word on the stack */ +#define ENF_PUSHZERO 2 /* Push 0 on the stack */ +#define ENF_PUSHONE 3 /* Push 1 on the stack */ +#define ENF_PUSHFFFF 4 /* Push 0xffff on the stack */ +#define ENF_PUSHFF00 5 /* Push 0xff00 on the stack */ +#define ENF_PUSH00FF 6 /* Push 0x00ff on the stack */ +#define ENF_LOAD_OFFSET 7 /* Load the next word into the offset register */ +#define ENF_BRTR 8 /* Branch if the stack's top element is true */ +#define ENF_BRFL 9 /* Branch if the stack's top element is false */ +#define ENF_POP 10 /* Pop the top element from the stack */ #define ENF_PUSHWORD 16 #ifdef __cplusplus diff --git a/usr/src/uts/common/sys/stream.h b/usr/src/uts/common/sys/stream.h index 6fd38f724a..cb5a92b7d3 100644 --- a/usr/src/uts/common/sys/stream.h +++ b/usr/src/uts/common/sys/stream.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -357,6 +356,10 @@ typedef struct datab { #define DB_CRED(mp) ((mp)->b_datap->db_credp) #define DB_CREDDEF(mp, cr) (DB_CRED(mp) != NULL ? DB_CRED(mp) : (cr)) #define DB_FTHDR(mp) ((mp)->b_datap->db_fthdr) +/* + * Used by GLDv2 to store the TCI information. + */ +#define DB_TCI(mp) ((mp)->b_datap->db_struioun.cksum.pad) /* * Message block descriptor diff --git a/usr/src/uts/common/sys/vlan.h b/usr/src/uts/common/sys/vlan.h index eba8ea3c4e..2a4e4c8ef0 100644 --- a/usr/src/uts/common/sys/vlan.h +++ b/usr/src/uts/common/sys/vlan.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -39,8 +38,6 @@ extern "C" { #define VLAN_TAGSZ 4 -#define VLAN_TPID 0x8100u - #define VLAN_ID_MASK 0x0fffu #define VLAN_ID_SIZE 12 #define VLAN_ID_SHIFT 0 @@ -69,6 +66,12 @@ extern "C" { #define VLAN_CFI(tci) (((tci) >> VLAN_CFI_SHIFT) & VLAN_CFI_MASK) #define VLAN_ID(tci) (((tci) >> VLAN_ID_SHIFT) & VLAN_ID_MASK) +#define VLAN_BAND_MAP 32 + +#define VLAN_MBLKPRI(mp) \ + ((((mp)->b_band) / VLAN_BAND_MAP) > 7 ? 0 : \ + (((mp)->b_band) / VLAN_BAND_MAP)) + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/sun4u/io/dmfe/dmfe_main.c b/usr/src/uts/sun4u/io/dmfe/dmfe_main.c index 20e616f24d..c8c1d479dd 100644 --- a/usr/src/uts/sun4u/io/dmfe/dmfe_main.c +++ b/usr/src/uts/sun4u/io/dmfe/dmfe_main.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -760,7 +759,8 @@ dmfe_getp(dmfe_t *dmfep) #if !defined(VLAN_VID_NONE) bcopy(rxb, dp, packet_length); #else - if (ehp->ether_type != VLAN_TPID || gld_recv_tagged == NULL) { + if (ehp->ether_type != ETHERTYPE_VLAN || + gld_recv_tagged == NULL) { /* * An untagged packet (or, there's no runtime support * for tagging so we treat all packets as untagged). |