forked from mirrors/linux
		
	net: vlan: make non-hw-accel rx path similar to hw-accel
Now there are 2 paths for rx vlan frames. When rx-vlan-hw-accel is enabled, skb is untagged by NIC, vlan_tci is set and the skb gets into vlan code in __netif_receive_skb - vlan_hwaccel_do_receive. For non-rx-vlan-hw-accel however, tagged skb goes thru whole __netif_receive_skb, it's untagged in ptype_base hander and reinjected This incosistency is fixed by this patch. Vlan untagging happens early in __netif_receive_skb so the rest of code (ptype_all handlers, rx_handlers) see the skb like it was untagged by hw. Signed-off-by: Jiri Pirko <jpirko@redhat.com> v1->v2: remove "inline" from vlan_core.c functions Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									143780c656
								
							
						
					
					
						commit
						bcc6d47903
					
				
					 6 changed files with 99 additions and 187 deletions
				
			
		| 
						 | 
					@ -132,7 +132,8 @@ extern u16 vlan_dev_vlan_id(const struct net_device *dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
 | 
					extern int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
 | 
				
			||||||
			     u16 vlan_tci, int polling);
 | 
								     u16 vlan_tci, int polling);
 | 
				
			||||||
extern bool vlan_hwaccel_do_receive(struct sk_buff **skb);
 | 
					extern bool vlan_do_receive(struct sk_buff **skb);
 | 
				
			||||||
 | 
					extern struct sk_buff *vlan_untag(struct sk_buff *skb);
 | 
				
			||||||
extern gro_result_t
 | 
					extern gro_result_t
 | 
				
			||||||
vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp,
 | 
					vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp,
 | 
				
			||||||
		 unsigned int vlan_tci, struct sk_buff *skb);
 | 
							 unsigned int vlan_tci, struct sk_buff *skb);
 | 
				
			||||||
| 
						 | 
					@ -166,13 +167,18 @@ static inline int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
 | 
				
			||||||
	return NET_XMIT_SUCCESS;
 | 
						return NET_XMIT_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline bool vlan_hwaccel_do_receive(struct sk_buff **skb)
 | 
					static inline bool vlan_do_receive(struct sk_buff **skb)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if ((*skb)->vlan_tci & VLAN_VID_MASK)
 | 
						if ((*skb)->vlan_tci & VLAN_VID_MASK)
 | 
				
			||||||
		(*skb)->pkt_type = PACKET_OTHERHOST;
 | 
							(*skb)->pkt_type = PACKET_OTHERHOST;
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline struct sk_buff *vlan_untag(struct sk_buff *skb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return skb;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline gro_result_t
 | 
					static inline gro_result_t
 | 
				
			||||||
vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp,
 | 
					vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp,
 | 
				
			||||||
		 unsigned int vlan_tci, struct sk_buff *skb)
 | 
							 unsigned int vlan_tci, struct sk_buff *skb)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,11 +49,6 @@ const char vlan_version[] = DRV_VERSION;
 | 
				
			||||||
static const char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>";
 | 
					static const char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>";
 | 
				
			||||||
static const char vlan_buggyright[] = "David S. Miller <davem@redhat.com>";
 | 
					static const char vlan_buggyright[] = "David S. Miller <davem@redhat.com>";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct packet_type vlan_packet_type __read_mostly = {
 | 
					 | 
				
			||||||
	.type = cpu_to_be16(ETH_P_8021Q),
 | 
					 | 
				
			||||||
	.func = vlan_skb_recv, /* VLAN receive method */
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* End of global variables definitions. */
 | 
					/* End of global variables definitions. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void vlan_group_free(struct vlan_group *grp)
 | 
					static void vlan_group_free(struct vlan_group *grp)
 | 
				
			||||||
| 
						 | 
					@ -684,7 +679,6 @@ static int __init vlan_proto_init(void)
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		goto err4;
 | 
							goto err4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_add_pack(&vlan_packet_type);
 | 
					 | 
				
			||||||
	vlan_ioctl_set(vlan_ioctl_handler);
 | 
						vlan_ioctl_set(vlan_ioctl_handler);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -705,8 +699,6 @@ static void __exit vlan_cleanup_module(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unregister_netdevice_notifier(&vlan_notifier_block);
 | 
						unregister_netdevice_notifier(&vlan_notifier_block);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_remove_pack(&vlan_packet_type);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	unregister_pernet_subsys(&vlan_net_ops);
 | 
						unregister_pernet_subsys(&vlan_net_ops);
 | 
				
			||||||
	rcu_barrier(); /* Wait for completion of call_rcu()'s */
 | 
						rcu_barrier(); /* Wait for completion of call_rcu()'s */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -75,8 +75,6 @@ static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* found in vlan_dev.c */
 | 
					/* found in vlan_dev.c */
 | 
				
			||||||
int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
 | 
					 | 
				
			||||||
		  struct packet_type *ptype, struct net_device *orig_dev);
 | 
					 | 
				
			||||||
void vlan_dev_set_ingress_priority(const struct net_device *dev,
 | 
					void vlan_dev_set_ingress_priority(const struct net_device *dev,
 | 
				
			||||||
				   u32 skb_prio, u16 vlan_prio);
 | 
									   u32 skb_prio, u16 vlan_prio);
 | 
				
			||||||
int vlan_dev_set_egress_priority(const struct net_device *dev,
 | 
					int vlan_dev_set_egress_priority(const struct net_device *dev,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,7 @@
 | 
				
			||||||
#include <linux/netpoll.h>
 | 
					#include <linux/netpoll.h>
 | 
				
			||||||
#include "vlan.h"
 | 
					#include "vlan.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool vlan_hwaccel_do_receive(struct sk_buff **skbp)
 | 
					bool vlan_do_receive(struct sk_buff **skbp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sk_buff *skb = *skbp;
 | 
						struct sk_buff *skb = *skbp;
 | 
				
			||||||
	u16 vlan_id = skb->vlan_tci & VLAN_VID_MASK;
 | 
						u16 vlan_id = skb->vlan_tci & VLAN_VID_MASK;
 | 
				
			||||||
| 
						 | 
					@ -88,3 +88,86 @@ gro_result_t vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp,
 | 
				
			||||||
	return napi_gro_frags(napi);
 | 
						return napi_gro_frags(napi);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(vlan_gro_frags);
 | 
					EXPORT_SYMBOL(vlan_gro_frags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (vlan_dev_info(skb->dev)->flags & VLAN_FLAG_REORDER_HDR) {
 | 
				
			||||||
 | 
							if (skb_cow(skb, skb_headroom(skb)) < 0)
 | 
				
			||||||
 | 
								skb = NULL;
 | 
				
			||||||
 | 
							if (skb) {
 | 
				
			||||||
 | 
								/* Lifted from Gleb's VLAN code... */
 | 
				
			||||||
 | 
								memmove(skb->data - ETH_HLEN,
 | 
				
			||||||
 | 
									skb->data - VLAN_ETH_HLEN, 12);
 | 
				
			||||||
 | 
								skb->mac_header += VLAN_HLEN;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return skb;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void vlan_set_encap_proto(struct sk_buff *skb, struct vlan_hdr *vhdr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						__be16 proto;
 | 
				
			||||||
 | 
						unsigned char *rawp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Was a VLAN packet, grab the encapsulated protocol, which the layer
 | 
				
			||||||
 | 
						 * three protocols care about.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						proto = vhdr->h_vlan_encapsulated_proto;
 | 
				
			||||||
 | 
						if (ntohs(proto) >= 1536) {
 | 
				
			||||||
 | 
							skb->protocol = proto;
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rawp = skb->data;
 | 
				
			||||||
 | 
						if (*(unsigned short *) rawp == 0xFFFF)
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * This is a magic hack to spot IPX packets. Older Novell
 | 
				
			||||||
 | 
							 * breaks the protocol design and runs IPX over 802.3 without
 | 
				
			||||||
 | 
							 * an 802.2 LLC layer. We look for FFFF which isn't a used
 | 
				
			||||||
 | 
							 * 802.2 SSAP/DSAP. This won't work for fault tolerant netware
 | 
				
			||||||
 | 
							 * but does for the rest.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							skb->protocol = htons(ETH_P_802_3);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * Real 802.2 LLC
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							skb->protocol = htons(ETH_P_802_2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct sk_buff *vlan_untag(struct sk_buff *skb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct vlan_hdr *vhdr;
 | 
				
			||||||
 | 
						u16 vlan_tci;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (unlikely(vlan_tx_tag_present(skb))) {
 | 
				
			||||||
 | 
							/* vlan_tci is already set-up so leave this for another time */
 | 
				
			||||||
 | 
							return skb;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						skb = skb_share_check(skb, GFP_ATOMIC);
 | 
				
			||||||
 | 
						if (unlikely(!skb))
 | 
				
			||||||
 | 
							goto err_free;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (unlikely(!pskb_may_pull(skb, VLAN_HLEN)))
 | 
				
			||||||
 | 
							goto err_free;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vhdr = (struct vlan_hdr *) skb->data;
 | 
				
			||||||
 | 
						vlan_tci = ntohs(vhdr->h_vlan_TCI);
 | 
				
			||||||
 | 
						__vlan_hwaccel_put_tag(skb, vlan_tci);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						skb_pull_rcsum(skb, VLAN_HLEN);
 | 
				
			||||||
 | 
						vlan_set_encap_proto(skb, vhdr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						skb = vlan_check_reorder_header(skb);
 | 
				
			||||||
 | 
						if (unlikely(!skb))
 | 
				
			||||||
 | 
							goto err_free;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return skb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err_free:
 | 
				
			||||||
 | 
						kfree_skb(skb);
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -65,179 +65,6 @@ static int vlan_dev_rebuild_header(struct sk_buff *skb)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (vlan_dev_info(skb->dev)->flags & VLAN_FLAG_REORDER_HDR) {
 | 
					 | 
				
			||||||
		if (skb_cow(skb, skb_headroom(skb)) < 0)
 | 
					 | 
				
			||||||
			skb = NULL;
 | 
					 | 
				
			||||||
		if (skb) {
 | 
					 | 
				
			||||||
			/* Lifted from Gleb's VLAN code... */
 | 
					 | 
				
			||||||
			memmove(skb->data - ETH_HLEN,
 | 
					 | 
				
			||||||
				skb->data - VLAN_ETH_HLEN, 12);
 | 
					 | 
				
			||||||
			skb->mac_header += VLAN_HLEN;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return skb;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline void vlan_set_encap_proto(struct sk_buff *skb,
 | 
					 | 
				
			||||||
		struct vlan_hdr *vhdr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	__be16 proto;
 | 
					 | 
				
			||||||
	unsigned char *rawp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * Was a VLAN packet, grab the encapsulated protocol, which the layer
 | 
					 | 
				
			||||||
	 * three protocols care about.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	proto = vhdr->h_vlan_encapsulated_proto;
 | 
					 | 
				
			||||||
	if (ntohs(proto) >= 1536) {
 | 
					 | 
				
			||||||
		skb->protocol = proto;
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rawp = skb->data;
 | 
					 | 
				
			||||||
	if (*(unsigned short *)rawp == 0xFFFF)
 | 
					 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * This is a magic hack to spot IPX packets. Older Novell
 | 
					 | 
				
			||||||
		 * breaks the protocol design and runs IPX over 802.3 without
 | 
					 | 
				
			||||||
		 * an 802.2 LLC layer. We look for FFFF which isn't a used
 | 
					 | 
				
			||||||
		 * 802.2 SSAP/DSAP. This won't work for fault tolerant netware
 | 
					 | 
				
			||||||
		 * but does for the rest.
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		skb->protocol = htons(ETH_P_802_3);
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * Real 802.2 LLC
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		skb->protocol = htons(ETH_P_802_2);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 *	Determine the packet's protocol ID. The rule here is that we
 | 
					 | 
				
			||||||
 *	assume 802.3 if the type field is short enough to be a length.
 | 
					 | 
				
			||||||
 *	This is normal practice and works for any 'now in use' protocol.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  Also, at this point we assume that we ARE dealing exclusively with
 | 
					 | 
				
			||||||
 *  VLAN packets, or packets that should be made into VLAN packets based
 | 
					 | 
				
			||||||
 *  on a default VLAN ID.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  NOTE:  Should be similar to ethernet/eth.c.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  SANITY NOTE:  This method is called when a packet is moving up the stack
 | 
					 | 
				
			||||||
 *                towards userland.  To get here, it would have already passed
 | 
					 | 
				
			||||||
 *                through the ethernet/eth.c eth_type_trans() method.
 | 
					 | 
				
			||||||
 *  SANITY NOTE 2: We are referencing to the VLAN_HDR frields, which MAY be
 | 
					 | 
				
			||||||
 *                 stored UNALIGNED in the memory.  RISC systems don't like
 | 
					 | 
				
			||||||
 *                 such cases very much...
 | 
					 | 
				
			||||||
 *  SANITY NOTE 2a: According to Dave Miller & Alexey, it will always be
 | 
					 | 
				
			||||||
 *  		    aligned, so there doesn't need to be any of the unaligned
 | 
					 | 
				
			||||||
 *  		    stuff.  It has been commented out now...  --Ben
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
 | 
					 | 
				
			||||||
		  struct packet_type *ptype, struct net_device *orig_dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct vlan_hdr *vhdr;
 | 
					 | 
				
			||||||
	struct vlan_pcpu_stats *rx_stats;
 | 
					 | 
				
			||||||
	struct net_device *vlan_dev;
 | 
					 | 
				
			||||||
	u16 vlan_id;
 | 
					 | 
				
			||||||
	u16 vlan_tci;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	skb = skb_share_check(skb, GFP_ATOMIC);
 | 
					 | 
				
			||||||
	if (skb == NULL)
 | 
					 | 
				
			||||||
		goto err_free;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (unlikely(!pskb_may_pull(skb, VLAN_HLEN)))
 | 
					 | 
				
			||||||
		goto err_free;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	vhdr = (struct vlan_hdr *)skb->data;
 | 
					 | 
				
			||||||
	vlan_tci = ntohs(vhdr->h_vlan_TCI);
 | 
					 | 
				
			||||||
	vlan_id = vlan_tci & VLAN_VID_MASK;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rcu_read_lock();
 | 
					 | 
				
			||||||
	vlan_dev = vlan_find_dev(dev, vlan_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* If the VLAN device is defined, we use it.
 | 
					 | 
				
			||||||
	 * If not, and the VID is 0, it is a 802.1p packet (not
 | 
					 | 
				
			||||||
	 * really a VLAN), so we will just netif_rx it later to the
 | 
					 | 
				
			||||||
	 * original interface, but with the skb->proto set to the
 | 
					 | 
				
			||||||
	 * wrapped proto: we do nothing here.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!vlan_dev) {
 | 
					 | 
				
			||||||
		if (vlan_id) {
 | 
					 | 
				
			||||||
			pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n",
 | 
					 | 
				
			||||||
				 __func__, vlan_id, dev->name);
 | 
					 | 
				
			||||||
			goto err_unlock;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		rx_stats = NULL;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		skb->dev = vlan_dev;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		rx_stats = this_cpu_ptr(vlan_dev_info(skb->dev)->vlan_pcpu_stats);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		u64_stats_update_begin(&rx_stats->syncp);
 | 
					 | 
				
			||||||
		rx_stats->rx_packets++;
 | 
					 | 
				
			||||||
		rx_stats->rx_bytes += skb->len;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		pr_debug("%s: priority: %u for TCI: %hu\n",
 | 
					 | 
				
			||||||
			 __func__, skb->priority, vlan_tci);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		switch (skb->pkt_type) {
 | 
					 | 
				
			||||||
		case PACKET_BROADCAST:
 | 
					 | 
				
			||||||
			/* Yeah, stats collect these together.. */
 | 
					 | 
				
			||||||
			/* stats->broadcast ++; // no such counter :-( */
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		case PACKET_MULTICAST:
 | 
					 | 
				
			||||||
			rx_stats->rx_multicast++;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		case PACKET_OTHERHOST:
 | 
					 | 
				
			||||||
			/* Our lower layer thinks this is not local, let's make
 | 
					 | 
				
			||||||
			 * sure.
 | 
					 | 
				
			||||||
			 * This allows the VLAN to have a different MAC than the
 | 
					 | 
				
			||||||
			 * underlying device, and still route correctly.
 | 
					 | 
				
			||||||
			 */
 | 
					 | 
				
			||||||
			if (!compare_ether_addr(eth_hdr(skb)->h_dest,
 | 
					 | 
				
			||||||
						skb->dev->dev_addr))
 | 
					 | 
				
			||||||
				skb->pkt_type = PACKET_HOST;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		u64_stats_update_end(&rx_stats->syncp);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	skb_pull_rcsum(skb, VLAN_HLEN);
 | 
					 | 
				
			||||||
	vlan_set_encap_proto(skb, vhdr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (vlan_dev) {
 | 
					 | 
				
			||||||
		skb = vlan_check_reorder_header(skb);
 | 
					 | 
				
			||||||
		if (!skb) {
 | 
					 | 
				
			||||||
			rx_stats->rx_errors++;
 | 
					 | 
				
			||||||
			goto err_unlock;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	netif_rx(skb);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rcu_read_unlock();
 | 
					 | 
				
			||||||
	return NET_RX_SUCCESS;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
err_unlock:
 | 
					 | 
				
			||||||
	rcu_read_unlock();
 | 
					 | 
				
			||||||
err_free:
 | 
					 | 
				
			||||||
	atomic_long_inc(&dev->rx_dropped);
 | 
					 | 
				
			||||||
	kfree_skb(skb);
 | 
					 | 
				
			||||||
	return NET_RX_DROP;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline u16
 | 
					static inline u16
 | 
				
			||||||
vlan_dev_get_egress_qos_mask(struct net_device *dev, struct sk_buff *skb)
 | 
					vlan_dev_get_egress_qos_mask(struct net_device *dev, struct sk_buff *skb)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3130,6 +3130,12 @@ static int __netif_receive_skb(struct sk_buff *skb)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	__this_cpu_inc(softnet_data.processed);
 | 
						__this_cpu_inc(softnet_data.processed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) {
 | 
				
			||||||
 | 
							skb = vlan_untag(skb);
 | 
				
			||||||
 | 
							if (unlikely(!skb))
 | 
				
			||||||
 | 
								goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_NET_CLS_ACT
 | 
					#ifdef CONFIG_NET_CLS_ACT
 | 
				
			||||||
	if (skb->tc_verd & TC_NCLS) {
 | 
						if (skb->tc_verd & TC_NCLS) {
 | 
				
			||||||
		skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
 | 
							skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
 | 
				
			||||||
| 
						 | 
					@ -3177,7 +3183,7 @@ static int __netif_receive_skb(struct sk_buff *skb)
 | 
				
			||||||
			ret = deliver_skb(skb, pt_prev, orig_dev);
 | 
								ret = deliver_skb(skb, pt_prev, orig_dev);
 | 
				
			||||||
			pt_prev = NULL;
 | 
								pt_prev = NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (vlan_hwaccel_do_receive(&skb)) {
 | 
							if (vlan_do_receive(&skb)) {
 | 
				
			||||||
			ret = __netif_receive_skb(skb);
 | 
								ret = __netif_receive_skb(skb);
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
		} else if (unlikely(!skb))
 | 
							} else if (unlikely(!skb))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue