Skip to contentSkip to conversation

: VLAN update

PATCH In review Patrick McHardy 3 participants 13 messages Jul 9, 2008 – Jul 15, 2008

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

cover : VLAN update

These patches include an updated set of the VLAN packet socket fixes, now also supporting VLAN TCI delivery to userspace using mmaped packet sockets, as well as a patch to add ->get_flags ethtool support and a few minor cleanup patches.

To recap the VLAN packet socket problems fixed by these patches:

- With hardware tagging, outgoing packets are visible without the VLAN header, while with software tagging the full VLAN header is visible

- With hardware stripping, incoming packets for locally configured VLANs appear on the VLAN device without being visible on the underlying device. Packets for unknown VLANs are not visible at all. Without hardware stripping, all VLAN packets are visible on the underlying device.

The patches move the VLAN TCI from skb->cb to a new skb member to avoid clashes with qdiscs and packet sockets use of skb->cb. On the TX path this is enough to make sure that packet sockets can be made aware of the VLAN TCI. On the hardware accelerated RX path, we also store the VLAN TCI in the skb and manually invoke the ptype_all handlers. The packet socket code stores the TCI in either the auxdata (for regular packet sockets) or the new tpacket2_hdr (for mmaped packet sockets) and delivers it to userspace, where it can be used to reconstruct the VLAN header.

The only remaining problem is that socket filters contructed for VLAN headers don't work properly since no header is present. Since with the approach taken by these patches, userspace has to be aware of VLAN acceleration anyway, it seems reasonable to add a new filter instruction for getting the VLAN TCI from the skb and expect it to construct its filters accordingly. This is not done so far however, other suggestions are still welcome :)

 include/linux/if_packet.h |   23 ++++++
 include/linux/if_vlan.h   |   31 ++------
 include/linux/netdevice.h |    1 +
 include/linux/skbuff.h    |    3 +
 net/8021q/vlan.c          |    8 +--
 net/8021q/vlan_core.c     |    4 +
 net/8021q/vlan_dev.c      |  116 +++++++----------------------
 net/8021q/vlanproc.c      |   11 +--
 net/core/dev.c            |   27 +++++++
 net/core/skbuff.c         |    3 +
 net/packet/af_packet.c    |  181 ++++++++++++++++++++++++++++++++++++--------
 11 files changed, 248 insertions(+), 160 deletions(-)

Patrick McHardy (8):
vlan: Don't store VLAN tag in cb
vlan: deliver packets received with VLAN acceleration to network taps
packet: support extensible, 64 bit clean mmaped ring structure
packet: deliver VLAN TCI to userspace
vlan: ethtool ->get_flags support
vlan: clean up vlan_dev_hard_header()
vlan: clean up hard_start_xmit functions
vlan: remove unnecessary include statements

#1 lore raw

PATCH 1/8 : vlan: Don't store VLAN tag in cb

vlan: Don't store VLAN tag in cb

Use a real skb member to store the skb to avoid clashes with qdiscs, which are allowed to use the cb area themselves. As currently only real devices that consume the skb set the NETIF_F_HW_VLAN_TX flag, no explicit invalidation is neccessary.

The new member fills a hole on 64 bit, the skb layout changes from:

        __u32                      mark;                 /*   172     4 */
        sk_buff_data_t             transport_header;     /*   176     4 */
        sk_buff_data_t             network_header;       /*   180     4 */
        sk_buff_data_t             mac_header;           /*   184     4 */
        sk_buff_data_t             tail;                 /*   188     4 */
        /* --- cacheline 3 boundary (192 bytes) --- */
        sk_buff_data_t             end;                  /*   192     4 */

        /* XXX 4 bytes hole, try to pack */

to

        __u32                      mark;                 /*   172     4 */
        __u16                      vlan_tci;             /*   176     2 */

/* XXX 2 bytes hole, try to pack */

sk_buff_data_t transport_header; /* 180 4 */
sk_buff_data_t network_header; /* 184 4 */

---
commit 5188944208232be946dbfa41e4e81cd13a5cc63f
tree c64a83b5852c11c1e970ca8d4955892a210138eb
parent 66f29353205907c92f202b6db8c143c7969cbedf
author Patrick McHardy <[email protected]> Wed, 09 Jul 2008 12:38:27 +0200 committer Patrick McHardy <[email protected]> Wed, 09 Jul 2008 12:38:27 +0200

 include/linux/if_vlan.h |   31 +++++++------------------------
 include/linux/skbuff.h  |    3 +++
 net/core/skbuff.c       |    3 +++
 3 files changed, 13 insertions(+), 24 deletions(-)
include/linux/if_vlan.h +7 -24
index 93f5d9b..9e7b49b 100644
@@ -105,17 +105,8 @@ static inline void vlan_group_set_device(struct vlan_group *vg,
 	array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] = dev;
 }
 
-/* VLAN tx hw acceleration helpers. */
-struct vlan_skb_tx_cookie {
-	u32	magic;
-	u32	vlan_tag;
-};
-
-#define VLAN_TX_COOKIE_MAGIC	0x564c414e	/* "VLAN" in ascii. */
-#define VLAN_TX_SKB_CB(__skb)	((struct vlan_skb_tx_cookie *)&((__skb)->cb[0]))
-#define vlan_tx_tag_present(__skb) \
-	(VLAN_TX_SKB_CB(__skb)->magic == VLAN_TX_COOKIE_MAGIC)
-#define vlan_tx_tag_get(__skb)	(VLAN_TX_SKB_CB(__skb)->vlan_tag)
+#define vlan_tx_tag_present(__skb)	((__skb)->vlan_tci)
+#define vlan_tx_tag_get(__skb)		((__skb)->vlan_tci)
 
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 extern struct net_device *vlan_dev_real_dev(const struct net_device *dev);
@@ -210,17 +201,12 @@ static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, u16 vlan_tci)
  * @skb: skbuff to tag
  * @vlan_tci: VLAN TCI to insert
  *
- * Puts the VLAN TCI in @skb->cb[] and lets the device do the rest
+ * Puts the VLAN TCI in @skb->vlan_tci and lets the device do the rest
  */
 static inline struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb,
 						     u16 vlan_tci)
 {
-	struct vlan_skb_tx_cookie *cookie;
-
-	cookie = VLAN_TX_SKB_CB(skb);
-	cookie->magic = VLAN_TX_COOKIE_MAGIC;
-	cookie->vlan_tag = vlan_tci;
-
+	skb->vlan_tci = vlan_tci;
 	return skb;
 }
 
@@ -267,16 +253,13 @@ static inline int __vlan_get_tag(const struct sk_buff *skb, u16 *vlan_tci)
  * @skb: skbuff to query
  * @vlan_tci: buffer to store vlaue
  *
- * Returns error if @skb->cb[] is not set correctly
+ * Returns error if @skb->vlan_tci is not set correctly
  */
 static inline int __vlan_hwaccel_get_tag(const struct sk_buff *skb,
 					 u16 *vlan_tci)
 {
-	struct vlan_skb_tx_cookie *cookie;
-
-	cookie = VLAN_TX_SKB_CB(skb);
-	if (cookie->magic == VLAN_TX_COOKIE_MAGIC) {
-		*vlan_tci = cookie->vlan_tag;
+	if (vlan_tx_tag_present(skb)) {
+		*vlan_tci = skb->vlan_tci;
 		return 0;
 	} else {
 		*vlan_tci = 0;
include/linux/skbuff.h +3 -0
index 8f10e3d..7ea44f6 100644
@@ -246,6 +246,7 @@ typedef unsigned char *sk_buff_data_t;
  *	@dma_cookie: a cookie to one of several possible DMA operations
  *		done by skb DMA functions
  *	@secmark: security marking
+ *	@vlan_tci: vlan tag control information
  */
 
 struct sk_buff {
@@ -326,6 +327,8 @@ struct sk_buff {
 
 	__u32			mark;
 
+	__u16			vlan_tci;
+
 	sk_buff_data_t		transport_header;
 	sk_buff_data_t		network_header;
 	sk_buff_data_t		mac_header;
net/core/skbuff.c +3 -0
index 7c57156..50a853f 100644
@@ -459,6 +459,8 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
 	new->tc_verd		= old->tc_verd;
 #endif
 #endif
+	new->vlan_tci		= old->vlan_tci;
+
 	skb_copy_secmark(new, old);
 }
 
@@ -2286,6 +2288,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features)
 		skb_copy_queue_mapping(nskb, skb);
 		nskb->priority = skb->priority;
 		nskb->protocol = skb->protocol;
+		nskb->vlan_tci = skb->vlan_tci;
 		nskb->dst = dst_clone(skb->dst);
 		memcpy(nskb->cb, skb->cb, sizeof(skb->cb));
 		nskb->pkt_type = skb->pkt_type;
#2 lore raw

PATCH 2/8 : vlan: deliver packets received with VLAN acceleration to network taps

In reply to Patrick McHardy

vlan: deliver packets received with VLAN acceleration to network taps

When VLAN header stripping is used, packets currently bypass packet sockets (and other network taps) completely. For locally existing VLANs, they appear directly on the VLAN device, for unknown VLANs they are silently dropped.

Add a new function netif_nit_deliver() to deliver incoming packets to all network interface taps and use it in __vlan_hwaccel_rx() to make VLAN packets visible on the underlying device.

---
commit 2150bca3247c0b497a83937005367092bca86530
tree 1a1c894d2d360dd2b90a759485ae0e2e0a441b41
parent 5188944208232be946dbfa41e4e81cd13a5cc63f
author Patrick McHardy <[email protected]> Wed, 09 Jul 2008 12:38:27 +0200 committer Patrick McHardy <[email protected]> Wed, 09 Jul 2008 12:38:27 +0200

 include/linux/netdevice.h |    1 +
 net/8021q/vlan_core.c     |    4 ++++
 net/core/dev.c            |   27 +++++++++++++++++++++++++++
 3 files changed, 32 insertions(+), 0 deletions(-)
include/linux/netdevice.h +1 -0
index 203c550..85c5db8 100644
@@ -1152,6 +1152,7 @@ extern int		netif_rx(struct sk_buff *skb);
 extern int		netif_rx_ni(struct sk_buff *skb);
 #define HAVE_NETIF_RECEIVE_SKB 1
 extern int		netif_receive_skb(struct sk_buff *skb);
+extern void		netif_nit_deliver(struct sk_buff *skb);
 extern int		dev_valid_name(const char *name);
 extern int		dev_ioctl(struct net *net, unsigned int cmd, void __user *);
 extern int		dev_ethtool(struct net *net, struct ifreq *);
net/8021q/vlan_core.c +4 -0
index 68df12d..916061f 100644
@@ -14,6 +14,9 @@ int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
 		return NET_RX_DROP;
 	}
 
+	skb->vlan_tci = vlan_tci;
+	netif_nit_deliver(skb);
+
 	skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK);
 	if (skb->dev == NULL) {
 		dev_kfree_skb_any(skb);
@@ -22,6 +25,7 @@ int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
 		return NET_RX_SUCCESS;
 	}
 	skb->dev->last_rx = jiffies;
+	skb->vlan_tci = 0;
 
 	stats = &skb->dev->stats;
 	stats->rx_packets++;
net/core/dev.c +27 -0
index a29a359..c3bec22 100644
@@ -2068,6 +2068,33 @@ out:
 }
 #endif
 
+/*
+ * 	netif_tap_deliver - deliver received packets to network taps
+ * 	@skb: buffer
+ *
+ * 	This function is used to deliver incoming packets to network
+ * 	taps. It should be used when the normal netif_receive_skb path
+ * 	is bypassed, for example because of VLAN acceleration.
+ */
+void netif_nit_deliver(struct sk_buff *skb)
+{
+	struct packet_type *ptype;
+
+	if (list_empty(&ptype_all))
+		return;
+
+	skb_reset_network_header(skb);
+	skb_reset_transport_header(skb);
+	skb->mac_len = skb->network_header - skb->mac_header;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(ptype, &ptype_all, list) {
+		if (!ptype->dev || ptype->dev == skb->dev)
+			deliver_skb(skb, ptype, skb->dev);
+	}
+	rcu_read_unlock();
+}
+
 /**
  *	netif_receive_skb - process receive buffer from network
  *	@skb: buffer to process
#3 lore raw

Re: [PATCH 02/08]: vlan: deliver packets received with VLAN acceleration to network taps

Quoted 10 lines · Patrick McHardy

vlan: deliver packets received with VLAN acceleration to network taps

When VLAN header stripping is used, packets currently bypass packet sockets (and other network taps) completely. For locally existing VLANs, they appear directly on the VLAN device, for unknown VLANs they are silently dropped.

Add a new function netif_nit_deliver() to deliver incoming packets to all network interface taps and use it in __vlan_hwaccel_rx() to make VLAN packets visible on the underlying device.

[...]

net/core/dev.c out: · line 2079

Quoted 9 lines
net/core/dev.c +9 -0
+/*
+ * 	netif_tap_deliver - deliver received packets to network taps
+ * 	@skb: buffer
+ *
+ * 	This function is used to deliver incoming packets to network
+ * 	taps. It should be used when the normal netif_receive_skb path
+ * 	is bypassed, for example because of VLAN acceleration.
+ */
+void netif_nit_deliver(struct sk_buff *skb)

[...]

Is it supposed to be called netif_nit_deliver() or netif_tap_deliver()?

Ben.

Signature · 2 lines
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
#4 lore raw

Re: [PATCH 02/08]: vlan: deliver packets received with VLAN acceleration to network taps

Quoted 23 lines · Ben Hutchings
Quoted 10 lines · Patrick McHardy

vlan: deliver packets received with VLAN acceleration to network taps

When VLAN header stripping is used, packets currently bypass packet sockets (and other network taps) completely. For locally existing VLANs, they appear directly on the VLAN device, for unknown VLANs they are silently dropped.

Add a new function netif_nit_deliver() to deliver incoming packets to all network interface taps and use it in __vlan_hwaccel_rx() to make VLAN packets visible on the underlying device.

[...]

Quoted 9 lines
(quoted diff) +9 -0
+/*
+ * 	netif_tap_deliver - deliver received packets to network taps
+ * 	@skb: buffer
+ *
+ * 	This function is used to deliver incoming packets to network
+ * 	taps. It should be used when the normal netif_receive_skb path
+ * 	is bypassed, for example because of VLAN acceleration.
+ */
+void netif_nit_deliver(struct sk_buff *skb)

[...]

Quoted 1 line

Is it supposed to be called netif_nit_deliver() or netif_tap_deliver()?

Thanks, seems I only renamed it half way :)

Fixed patch attached.

commit d5c10a9dd25c8c9333e12d92cd81191a37376097

Author: Patrick McHardy <[email protected]>
Date:   Wed Jul 9 14:37:44 2008 +0200

vlan: deliver packets received with VLAN acceleration to network taps

When VLAN header stripping is used, packets currently bypass packet sockets (and other network taps) completely. For locally existing VLANs, they appear directly on the VLAN device, for unknown VLANs they are silently dropped.

Add a new function netif_nit_deliver() to deliver incoming packets to all network interface taps and use it in __vlan_hwaccel_rx() to make VLAN packets visible on the underlying device.

include/linux/netdevice.h +1 -0
index 203c550..85c5db8 100644
@@ -1152,6 +1152,7 @@ extern int		netif_rx(struct sk_buff *skb);
 extern int		netif_rx_ni(struct sk_buff *skb);
 #define HAVE_NETIF_RECEIVE_SKB 1
 extern int		netif_receive_skb(struct sk_buff *skb);
+extern void		netif_nit_deliver(struct sk_buff *skb);
 extern int		dev_valid_name(const char *name);
 extern int		dev_ioctl(struct net *net, unsigned int cmd, void __user *);
 extern int		dev_ethtool(struct net *net, struct ifreq *);
net/8021q/vlan_core.c +4 -0
index 68df12d..916061f 100644
@@ -14,6 +14,9 @@ int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
 		return NET_RX_DROP;
 	}
 
+	skb->vlan_tci = vlan_tci;
+	netif_nit_deliver(skb);
+
 	skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK);
 	if (skb->dev == NULL) {
 		dev_kfree_skb_any(skb);
@@ -22,6 +25,7 @@ int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
 		return NET_RX_SUCCESS;
 	}
 	skb->dev->last_rx = jiffies;
+	skb->vlan_tci = 0;
 
 	stats = &skb->dev->stats;
 	stats->rx_packets++;
net/core/dev.c +27 -0
index a29a359..feaab48 100644
@@ -2068,6 +2068,33 @@ out:
 }
 #endif
 
+/*
+ * 	netif_nit_deliver - deliver received packets to network taps
+ * 	@skb: buffer
+ *
+ * 	This function is used to deliver incoming packets to network
+ * 	taps. It should be used when the normal netif_receive_skb path
+ * 	is bypassed, for example because of VLAN acceleration.
+ */
+void netif_nit_deliver(struct sk_buff *skb)
+{
+	struct packet_type *ptype;
+
+	if (list_empty(&ptype_all))
+		return;
+
+	skb_reset_network_header(skb);
+	skb_reset_transport_header(skb);
+	skb->mac_len = skb->network_header - skb->mac_header;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(ptype, &ptype_all, list) {
+		if (!ptype->dev || ptype->dev == skb->dev)
+			deliver_skb(skb, ptype, skb->dev);
+	}
+	rcu_read_unlock();
+}
+
 /**
  *	netif_receive_skb - process receive buffer from network
  *	@skb: buffer to process
#5 lore raw

PATCH 3/8 : packet: support extensible, 64 bit clean mmaped ring structure

In reply to Patrick McHardy

packet: support extensible, 64 bit clean mmaped ring structure

The tpacket_hdr is not 64 bit clean due to use of an unsigned long and can't be extended because the following struct sockaddr_ll needs to be at a fixed offset.

Add support for a version 2 tpacket protocol that removes these limitations.

Userspace can query the header size through a new getsockopt option and change the protocol version through a setsockopt option. The changes needed to switch to the new protocol version are:

1. replace struct tpacket_hdr by struct tpacket2_hdr
2. query header len and save
3. set protocol version to 2
- set up ring as usual
4. for getting the sockaddr_ll, use (void *)hdr + TPACKET_ALIGN(hdrlen) instead of (void *)hdr + TPACKET_ALIGN(sizeof(struct tpacket_hdr))

Steps 2 and 4 can be omitted if the struct sockaddr_ll isn't needed.

---
commit 67facd0da49b1c2061e17a6623904f675d0b1bc9
tree 3c3f7e5bcd481da693fbdda775c618abf9f89584
parent 2150bca3247c0b497a83937005367092bca86530
author Patrick McHardy <[email protected]> Wed, 09 Jul 2008 13:04:26 +0200 committer Patrick McHardy <[email protected]> Wed, 09 Jul 2008 13:04:26 +0200

 include/linux/if_packet.h |   21 +++++
 net/packet/af_packet.c    |  179 +++++++++++++++++++++++++++++++++++++--------
 2 files changed, 167 insertions(+), 33 deletions(-)
include/linux/if_packet.h +21 -0
index ad09609..d4d3c82 100644
@@ -43,6 +43,8 @@ struct sockaddr_ll
 #define PACKET_COPY_THRESH		7
 #define PACKET_AUXDATA			8
 #define PACKET_ORIGDEV			9
+#define PACKET_VERSION			10
+#define PACKET_HDRLEN			11
 
 struct tpacket_stats
 {
@@ -79,6 +81,25 @@ struct tpacket_hdr
 #define TPACKET_ALIGN(x)	(((x)+TPACKET_ALIGNMENT-1)&~(TPACKET_ALIGNMENT-1))
 #define TPACKET_HDRLEN		(TPACKET_ALIGN(sizeof(struct tpacket_hdr)) + sizeof(struct sockaddr_ll))
 
+struct tpacket2_hdr
+{
+	__u32		tp_status;
+	__u32		tp_len;
+	__u32		tp_snaplen;
+	__u16		tp_mac;
+	__u16		tp_net;
+	__u32		tp_sec;
+	__u32		tp_nsec;
+};
+
+#define TPACKET2_HDRLEN		(TPACKET_ALIGN(sizeof(struct tpacket2_hdr)) + sizeof(struct sockaddr_ll))
+
+enum tpacket_versions
+{
+	TPACKET_V1,
+	TPACKET_V2,
+};
+
 /*
    Frame structure:
 
net/packet/af_packet.c +146 -33

280 lines not on this page · raw message

#6 lore raw

PATCH 4/8 : packet: deliver VLAN TCI to userspace

In reply to Patrick McHardy

packet: deliver VLAN TCI to userspace

Store the VLAN tag in the auxillary data/tpacket2_hdr so userspace can properly deal with hardware VLAN tagging/stripping.

---
commit 1e655d00db6762d05f8d99912a70f58fe4c4f977
tree 605cd8de3e2752890703706e7dd9acaaadcf5324
parent 67facd0da49b1c2061e17a6623904f675d0b1bc9
author Patrick McHardy <[email protected]> Wed, 09 Jul 2008 13:56:52 +0200 committer Patrick McHardy <[email protected]> Wed, 09 Jul 2008 13:56:52 +0200

 include/linux/if_packet.h |    2 ++
 net/packet/af_packet.c    |    2 ++
 2 files changed, 4 insertions(+), 0 deletions(-)
include/linux/if_packet.h +2 -0
index d4d3c82..a630295 100644
@@ -59,6 +59,7 @@ struct tpacket_auxdata
 	__u32		tp_snaplen;
 	__u16		tp_mac;
 	__u16		tp_net;
+	__u16		tp_vlan_tci;
 };
 
 struct tpacket_hdr
@@ -90,6 +91,7 @@ struct tpacket2_hdr
 	__u16		tp_net;
 	__u32		tp_sec;
 	__u32		tp_nsec;
+	__u16		tp_vlan_tci;
 };
 
 #define TPACKET2_HDRLEN		(TPACKET_ALIGN(sizeof(struct tpacket2_hdr)) + sizeof(struct sockaddr_ll))
net/packet/af_packet.c +2 -0
index 85ab3e3..250e9b8 100644
@@ -702,6 +702,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
 			getnstimeofday(&ts);
 		h.h2->tp_sec = ts.tv_sec;
 		h.h2->tp_nsec = ts.tv_nsec;
+		h.h2->tp_vlan_tci = skb->vlan_tci;
 		hdrlen = sizeof(*h.h2);
 		break;
 	default:
@@ -1172,6 +1173,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
 		aux.tp_snaplen = skb->len;
 		aux.tp_mac = 0;
 		aux.tp_net = skb_network_offset(skb);
+		aux.tp_vlan_tci = skb->vlan_tci;
 
 		put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux);
 	}
#7 lore raw

PATCH 5/8 : vlan: ethtool ->get_flags support

In reply to Patrick McHardy

vlan: ethtool ->get_flags support

Allow to query LRO settings of underlying device when VLAN RX acceleration is used.

Suggested by Ben Hutchings <[email protected]>.

---
commit b7ed86e1c799275adf2d36b8801abe91ffe66aec
tree 7374b192f8b6b88df2e2a9f6d92764423a14df9f
parent 1e655d00db6762d05f8d99912a70f58fe4c4f977
author Patrick McHardy <[email protected]> Wed, 09 Jul 2008 13:57:00 +0200 committer Patrick McHardy <[email protected]> Wed, 09 Jul 2008 13:57:00 +0200

 net/8021q/vlan_dev.c |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)
net/8021q/vlan_dev.c +13 -0
index 8efa399..48617c1 100644
@@ -709,9 +709,22 @@ static u32 vlan_ethtool_get_rx_csum(struct net_device *dev)
 	return real_dev->ethtool_ops->get_rx_csum(real_dev);
 }
 
+static u32 vlan_ethtool_get_flags(struct net_device *dev)
+{
+	const struct vlan_dev_info *vlan = vlan_dev_info(dev);
+	struct net_device *real_dev = vlan->real_dev;
+
+	if (!(real_dev->features & NETIF_F_HW_VLAN_RX) ||
+	    real_dev->ethtool_ops == NULL ||
+	    real_dev->ethtool_ops->get_flags == NULL)
+		return 0;
+	return real_dev->ethtool_ops->get_flags(real_dev);
+}
+
 static const struct ethtool_ops vlan_ethtool_ops = {
 	.get_link		= ethtool_op_get_link,
 	.get_rx_csum		= vlan_ethtool_get_rx_csum,
+	.get_flags		= vlan_ethtool_get_flags,
 };
 
 void vlan_setup(struct net_device *dev)
#8 lore raw

PATCH 6/8 : vlan: clean up vlan_dev_hard_header()

In reply to Patrick McHardy

vlan: clean up vlan_dev_hard_header()

Remove some debugging and excessive comments, merge the two dev_hard_header calls into one.

---
commit 731075279c2229b454f9441da2b6bc82a39cde67
tree 4c7354bbc74d1d75da1a8fbc79fd6d19e7ec5021
parent b7ed86e1c799275adf2d36b8801abe91ffe66aec
author Patrick McHardy <[email protected]> Wed, 09 Jul 2008 13:57:00 +0200 committer Patrick McHardy <[email protected]> Wed, 09 Jul 2008 13:57:00 +0200

 net/8021q/vlan_dev.c |   55 ++++++++------------------------------------------
 1 files changed, 9 insertions(+), 46 deletions(-)
net/8021q/vlan_dev.c +9 -46
index 48617c1..8cd57c4 100644
@@ -256,43 +256,18 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
 				unsigned int len)
 {
 	struct vlan_hdr *vhdr;
+	unsigned int vhdrlen = 0;
 	u16 vlan_tci = 0;
-	int rc = 0;
-	int build_vlan_header = 0;
-
-	pr_debug("%s: skb: %p type: %hx len: %u vlan_id: %hx, daddr: %p\n",
-		 __func__, skb, type, len, vlan_dev_info(dev)->vlan_id,
-		 daddr);
+	int rc;
 
 	if (WARN_ON(skb_headroom(skb) < dev->hard_header_len))
 		return -ENOSPC;
 
-	/* build vlan header only if re_order_header flag is NOT set.  This
-	 * fixes some programs that get confused when they see a VLAN device
-	 * sending a frame that is VLAN encoded (the consensus is that the VLAN
-	 * device should look completely like an Ethernet device when the
-	 * REORDER_HEADER flag is set)	The drawback to this is some extra
-	 * header shuffling in the hard_start_xmit.  Users can turn off this
-	 * REORDER behaviour with the vconfig tool.
-	 */
-	if (!(vlan_dev_info(dev)->flags & VLAN_FLAG_REORDER_HDR))
-		build_vlan_header = 1;
-
-	if (build_vlan_header) {
+	if (!(vlan_dev_info(dev)->flags & VLAN_FLAG_REORDER_HDR)) {
 		vhdr = (struct vlan_hdr *) skb_push(skb, VLAN_HLEN);
 
-		/* build the four bytes that make this a VLAN header. */
-
-		/* Now, construct the second two bytes. This field looks
-		 * something like:
-		 * usr_priority: 3 bits	 (high bits)
-		 * CFI		 1 bit
-		 * VLAN ID	 12 bits (low bits)
-		 *
-		 */
 		vlan_tci = vlan_dev_info(dev)->vlan_id;
 		vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb);
-
 		vhdr->h_vlan_TCI = htons(vlan_tci);
 
 		/*
@@ -300,37 +275,25 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
 		 *  put the length in here instead. It is up to the 802.2
 		 *  layer to carry protocol information.
 		 */
-
 		if (type != ETH_P_802_3)
 			vhdr->h_vlan_encapsulated_proto = htons(type);
 		else
 			vhdr->h_vlan_encapsulated_proto = htons(len);
 
 		skb->protocol = htons(ETH_P_8021Q);
+		type = ETH_P_8021Q;
+		vhdrlen = VLAN_HLEN;
 	}
 
 	/* Before delegating work to the lower layer, enter our MAC-address */
 	if (saddr == NULL)
 		saddr = dev->dev_addr;
 
+	/* Now make the underlying real hard header */
 	dev = vlan_dev_info(dev)->real_dev;
-
-	if (build_vlan_header) {
-		/* Now make the underlying real hard header */
-		rc = dev_hard_header(skb, dev, ETH_P_8021Q, daddr, saddr,
-				     len + VLAN_HLEN);
-		if (rc > 0)
-			rc += VLAN_HLEN;
-		else if (rc < 0)
-			rc -= VLAN_HLEN;
-	} else
-		/* If here, then we'll just make a normal looking ethernet
-		 * frame, but, the hard_start_xmit method will insert the tag
-		 * (it has to be able to do this for bridged and other skbs
-		 * that don't come down the protocol stack in an orderly manner.
-		 */
-		rc = dev_hard_header(skb, dev, type, daddr, saddr, len);
-
+	rc = dev_hard_header(skb, dev, type, daddr, saddr, len + vhdrlen);
+	if (rc > 0)
+		rc += vhdrlen;
 	return rc;
 }
 
#9 lore raw

PATCH 7/8 : vlan: clean up hard_start_xmit functions

In reply to Patrick McHardy

vlan: clean up hard_start_xmit functions

Remove excessive comments and debugging, use NETDEV_TX codes, remove some empty lines.

---
commit a1f83d7cbe06c3c104cfa7cf298fb0ccb26cb5a8
tree e5d55d0d2cc56417cc00788215050ae4f371cfe8
parent 731075279c2229b454f9441da2b6bc82a39cde67
author Patrick McHardy <[email protected]> Wed, 09 Jul 2008 13:57:01 +0200 committer Patrick McHardy <[email protected]> Wed, 09 Jul 2008 13:57:01 +0200

 net/8021q/vlan_dev.c |   41 ++++++-----------------------------------
 1 files changed, 6 insertions(+), 35 deletions(-)
net/8021q/vlan_dev.c +6 -35
index 8cd57c4..c5290c6 100644
@@ -307,53 +307,31 @@ static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	 * NOTE: THIS ASSUMES DIX ETHERNET, SPECIFICALLY NOT SUPPORTING
 	 * OTHER THINGS LIKE FDDI/TokenRing/802.3 SNAPs...
 	 */
-
 	if (veth->h_vlan_proto != htons(ETH_P_8021Q) ||
-		vlan_dev_info(dev)->flags & VLAN_FLAG_REORDER_HDR) {
-		int orig_headroom = skb_headroom(skb);
+	    vlan_dev_info(dev)->flags & VLAN_FLAG_REORDER_HDR) {
+		unsigned int orig_headroom = skb_headroom(skb);
 		u16 vlan_tci;
 
-		/* This is not a VLAN frame...but we can fix that! */
 		vlan_dev_info(dev)->cnt_encap_on_xmit++;
 
-		pr_debug("%s: proto to encap: 0x%hx\n",
-			 __func__, ntohs(veth->h_vlan_proto));
-		/* Construct the second two bytes. This field looks something
-		 * like:
-		 * usr_priority: 3 bits	 (high bits)
-		 * CFI		 1 bit
-		 * VLAN ID	 12 bits (low bits)
-		 */
 		vlan_tci = vlan_dev_info(dev)->vlan_id;
 		vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb);
-
 		skb = __vlan_put_tag(skb, vlan_tci);
 		if (!skb) {
 			stats->tx_dropped++;
-			return 0;
+			return NETDEV_TX_OK;
 		}
 
 		if (orig_headroom < VLAN_HLEN)
 			vlan_dev_info(dev)->cnt_inc_headroom_on_tx++;
 	}
 
-	pr_debug("%s: about to send skb: %p to dev: %s\n",
-		__func__, skb, skb->dev->name);
-	pr_debug("  " MAC_FMT " " MAC_FMT " %4hx %4hx %4hx\n",
-		 veth->h_dest[0], veth->h_dest[1], veth->h_dest[2],
-		 veth->h_dest[3], veth->h_dest[4], veth->h_dest[5],
-		 veth->h_source[0], veth->h_source[1], veth->h_source[2],
-		 veth->h_source[3], veth->h_source[4], veth->h_source[5],
-		 veth->h_vlan_proto, veth->h_vlan_TCI,
-		 veth->h_vlan_encapsulated_proto);
-
-	stats->tx_packets++; /* for statics only */
+	stats->tx_packets++;
 	stats->tx_bytes += skb->len;
 
 	skb->dev = vlan_dev_info(dev)->real_dev;
 	dev_queue_xmit(skb);
-
-	return 0;
+	return NETDEV_TX_OK;
 }
 
 static int vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb,
@@ -362,12 +340,6 @@ static int vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb,
 	struct net_device_stats *stats = &dev->stats;
 	u16 vlan_tci;
 
-	/* Construct the second two bytes. This field looks something
-	 * like:
-	 * usr_priority: 3 bits	 (high bits)
-	 * CFI		 1 bit
-	 * VLAN ID	 12 bits (low bits)
-	 */
 	vlan_tci = vlan_dev_info(dev)->vlan_id;
 	vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb);
 	skb = __vlan_hwaccel_put_tag(skb, vlan_tci);
@@ -377,8 +349,7 @@ static int vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb,
 
 	skb->dev = vlan_dev_info(dev)->real_dev;
 	dev_queue_xmit(skb);
-
-	return 0;
+	return NETDEV_TX_OK;
 }
 
 static int vlan_dev_change_mtu(struct net_device *dev, int new_mtu)
#10 lore raw

PATCH 8/8 : vlan: remove unnecessary include statements

In reply to Patrick McHardy

vlan: remove unnecessary include statements

---
commit 0b1a2cdc7acdd1fed69d6eefb16744f205fcd418
tree 3267d6c92125ad3918072c1ba180ed47c36b23f0
parent a1f83d7cbe06c3c104cfa7cf298fb0ccb26cb5a8
author Patrick McHardy <[email protected]> Wed, 09 Jul 2008 13:57:01 +0200 committer Patrick McHardy <[email protected]> Wed, 09 Jul 2008 13:57:01 +0200

 net/8021q/vlan.c     |    8 ++------
 net/8021q/vlan_dev.c |    7 -------
 net/8021q/vlanproc.c |   11 ++---------
 3 files changed, 4 insertions(+), 22 deletions(-)
net/8021q/vlan.c +2 -6
index 68bdcf4..9f04cab 100644
@@ -18,21 +18,17 @@
  *		2 of the License, or (at your option) any later version.
  */
 
-#include <asm/uaccess.h> /* for copy_from_user */
 #include <linux/capability.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
-#include <net/datalink.h>
-#include <linux/mm.h>
-#include <linux/in.h>
 #include <linux/init.h>
-#include <net/p8022.h>
-#include <net/arp.h>
 #include <linux/rtnetlink.h>
 #include <linux/notifier.h>
+#include <net/rtnetlink.h>
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
+#include <asm/uaccess.h>
 
 #include <linux/if_vlan.h>
 #include "vlan.h"
net/8021q/vlan_dev.c +0 -7
index c5290c6..044fa0b 100644
@@ -21,22 +21,15 @@
  */
 
 #include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/in.h>
-#include <linux/init.h>
-#include <asm/uaccess.h> /* for copy_from_user */
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
-#include <net/datalink.h>
-#include <net/p8022.h>
 #include <net/arp.h>
 
 #include "vlan.h"
 #include "vlanproc.h"
 #include <linux/if_vlan.h>
-#include <net/ip.h>
 
 /*
  *	Rebuild the Ethernet MAC header. This is called after an ARP
net/8021q/vlanproc.c +2 -9
index 6073a88..0feefa4 100644
@@ -18,16 +18,9 @@
  *****************************************************************************/
 
 #include <linux/module.h>
-#include <linux/stddef.h>	/* offsetof(), etc. */
-#include <linux/errno.h>	/* return codes */
+#include <linux/errno.h>
 #include <linux/kernel.h>
-#include <linux/slab.h>		/* kmalloc(), kfree() */
-#include <linux/mm.h>
-#include <linux/string.h>	/* inline mem*, str* functions */
-#include <linux/init.h>		/* __initfunc et al. */
-#include <asm/byteorder.h>	/* htons(), etc. */
-#include <asm/uaccess.h>	/* copy_to_user */
-#include <asm/io.h>
+#include <linux/string.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/fs.h>
#11 lore raw
In reply to Patrick McHardy
Quoted 4 lines · Patrick McHardy

These patches include an updated set of the VLAN packet socket fixes, now also supporting VLAN TCI delivery to userspace using mmaped packet sockets, as well as a patch to add ->get_flags ethtool support and a few minor cleanup patches.

And for reference, attached is a patch for libpcap to reconstruct the VLAN header from the auxdata, as well as a ugly small program for testing the new mmaped packet socket protocol version (since I couldn't find a version of libpcap that already supports this for some reason).

pcap-linux.c +60 -6
index e9db010..e877cd8 100644
@@ -471,7 +471,13 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
 	socklen_t		fromlen;
 	int			packet_len, caplen;
 	struct pcap_pkthdr	pcap_header;
-
+	struct iovec		iov;
+	struct msghdr		msg;
+	struct cmsghdr		*cmsg;
+	union {
+		struct cmsghdr	cmsg;
+		char		buf[CMSG_SPACE(sizeof(struct tpacket_auxdata))];
+	} cmsg_buf;
 #ifdef HAVE_PF_PACKET_SOCKETS
 	/*
 	 * If this is a cooked device, leave extra room for a
@@ -492,6 +498,15 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
 	/* Receive a single packet from the kernel */
 
 	bp = handle->buffer + handle->offset;
+
+	msg.msg_name		= &from;
+	msg.msg_namelen		= sizeof(from);
+	msg.msg_iov		= &iov;
+	msg.msg_iovlen		= 1;
+	msg.msg_control		= &cmsg_buf;
+	msg.msg_controllen	= sizeof(cmsg_buf);
+	msg.msg_flags		= 0;
+
 	do {
 		/*
 		 * Has "pcap_breakloop()" been called?
@@ -505,11 +520,11 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
 			handle->break_loop = 0;
 			return -2;
 		}
-		fromlen = sizeof(from);
-		packet_len = recvfrom(
-			handle->fd, bp + offset,
-			handle->bufsize - offset, MSG_TRUNC,
-			(struct sockaddr *) &from, &fromlen);
+
+		iov.iov_len	= handle->bufsize - offset;
+		iov.iov_base	= bp + offset;
+
+		packet_len = recvmsg(handle->fd, &msg, MSG_TRUNC);
 	} while (packet_len == -1 && errno == EINTR);
 
 	/* Check if an error occured */
@@ -524,6 +539,38 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
 		}
 	}
 
+	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+		struct tpacket_auxdata *aux;
+		unsigned int len, copy;
+		unsigned short *ptr;
+
+		if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct tpacket_auxdata)) ||
+		    cmsg->cmsg_level != SOL_PACKET ||
+		    cmsg->cmsg_type != PACKET_AUXDATA)
+			continue;
+
+		aux = (struct tpacket_auxdata *)CMSG_DATA(cmsg);
+		if (aux->tp_vlan_tci == 0)
+			continue;
+
+		len = packet_len > iov.iov_len ? iov.iov_len : packet_len;
+		if (len > 2 * ETH_ALEN + 4) {
+			copy = len - 2 * ETH_ALEN - 4;
+			if (copy > iov.iov_len - 2 * ETH_ALEN - 4)
+				copy = iov.iov_len - 2 * ETH_ALEN - 4;
+
+			memmove(iov.iov_base + 2 * ETH_ALEN + 4,
+				iov.iov_base + 2 * ETH_ALEN, copy);
+		}
+
+		ptr = (unsigned short *)(iov.iov_base + 2 * ETH_ALEN);
+		if (len >= 2 * ETH_ALEN + 2)
+			*(ptr++) = htons(ETH_P_8021Q);
+		if (len >= 2 * ETH_ALEN + 4)
+			*(ptr++) = htons(aux->tp_vlan_tci);
+		packet_len += 4;
+	}
+
 #ifdef HAVE_PF_PACKET_SOCKETS
 	if (!handle->md.sock_packet) {
 		/*
@@ -1631,6 +1678,7 @@ iface_bind(int fd, int ifindex, char *ebuf)
 	struct sockaddr_ll	sll;
 	int			err;
 	socklen_t		errlen = sizeof(err);
+	int			val;
 
 	memset(&sll, 0, sizeof(sll));
 	sll.sll_family		= AF_PACKET;
@@ -1657,6 +1705,12 @@ iface_bind(int fd, int ifindex, char *ebuf)
 		return -2;
 	}
 
+	val = 1;
+	if (setsockopt(fd, SOL_PACKET, PACKET_AUXDATA, &val, sizeof(val)) == -1) {
+		snprintf(ebuf, PCAP_ERRBUF_SIZE,
+			 "setsockopt: %s", pcap_strerror(errno));
+		return -3;
+	}
 	return 0;
 }
 
if_packet.h renamed from tmp/null/if_packet.h +144 -0

144 lines not on this page · raw message

Makefile renamed from tmp/null/Makefile +3 -0
diff -urN /tmp/null/Makefile mmap-test/Makefile
@@ -0,0 +1,3 @@
+CFLAGS	+= -O2 -I. -Wall -g
+
+all: test
test.c renamed from tmp/null/test.c +150 -0

150 lines not on this page · raw message

maintainer
#12 lore raw
In reply to Patrick McHardy

From: Patrick McHardy <[email protected]>
Date: Wed, 9 Jul 2008 14:09:45 +0200 (MEST)

Quoted 4 lines

These patches include an updated set of the VLAN packet socket fixes, now also supporting VLAN TCI delivery to userspace using mmaped packet sockets, as well as a patch to add ->get_flags ethtool support and a few minor cleanup patches.

Applied and pushed out to net-next-2.6, thanks Patrick.