Commit a58f7f8a authored by David S. Miller's avatar David S. Miller

Merge branch 'vlan_tpid'

Atzm Watanabe says:

====================
packet: deliver VLAN TPID to userspace

This patchset enables userspace to get VLAN TPID as well as the VLAN TCI.

After the 802.1AD support, userspace packet receivers (packet dumper,
software switch, and the like) need how to know VLAN TPID in order to
reconstruct original tagged frame.

v4: Simply use sizeof(tp_padding) for zeroing the padding bytes,
    commented by David Laight.
    Use __u16 for tp_vlan_tpid in tpacket_hdr_variant1,
    commented by Daniel Borkmann.

v3: Add a definition which indicates whether tp_vlan_tpid is valid.
    Explicitly define pad bytes for tpacket{2,3}_hdr and pick the area
    for tp_vlan_tpid from the definition.  Commented by David Laight.

v2: Add BUILD_BUG_ON() to make current aligned size of
    struct tpacket{2,3}_hdr clear.  Commented by Ben Hutchings.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9f605acf a0cdfcf3
...@@ -84,17 +84,18 @@ struct tpacket_auxdata { ...@@ -84,17 +84,18 @@ struct tpacket_auxdata {
__u16 tp_mac; __u16 tp_mac;
__u16 tp_net; __u16 tp_net;
__u16 tp_vlan_tci; __u16 tp_vlan_tci;
__u16 tp_padding; __u16 tp_vlan_tpid;
}; };
/* Rx ring - header status */ /* Rx ring - header status */
#define TP_STATUS_KERNEL 0 #define TP_STATUS_KERNEL 0
#define TP_STATUS_USER (1 << 0) #define TP_STATUS_USER (1 << 0)
#define TP_STATUS_COPY (1 << 1) #define TP_STATUS_COPY (1 << 1)
#define TP_STATUS_LOSING (1 << 2) #define TP_STATUS_LOSING (1 << 2)
#define TP_STATUS_CSUMNOTREADY (1 << 3) #define TP_STATUS_CSUMNOTREADY (1 << 3)
#define TP_STATUS_VLAN_VALID (1 << 4) /* auxdata has valid tp_vlan_tci */ #define TP_STATUS_VLAN_VALID (1 << 4) /* auxdata has valid tp_vlan_tci */
#define TP_STATUS_BLK_TMO (1 << 5) #define TP_STATUS_BLK_TMO (1 << 5)
#define TP_STATUS_VLAN_TPID_VALID (1 << 6) /* auxdata has valid tp_vlan_tpid */
/* Tx ring - header status */ /* Tx ring - header status */
#define TP_STATUS_AVAILABLE 0 #define TP_STATUS_AVAILABLE 0
...@@ -133,12 +134,15 @@ struct tpacket2_hdr { ...@@ -133,12 +134,15 @@ struct tpacket2_hdr {
__u32 tp_sec; __u32 tp_sec;
__u32 tp_nsec; __u32 tp_nsec;
__u16 tp_vlan_tci; __u16 tp_vlan_tci;
__u16 tp_padding; __u16 tp_vlan_tpid;
__u8 tp_padding[4];
}; };
struct tpacket_hdr_variant1 { struct tpacket_hdr_variant1 {
__u32 tp_rxhash; __u32 tp_rxhash;
__u32 tp_vlan_tci; __u32 tp_vlan_tci;
__u16 tp_vlan_tpid;
__u16 tp_padding;
}; };
struct tpacket3_hdr { struct tpacket3_hdr {
...@@ -154,6 +158,7 @@ struct tpacket3_hdr { ...@@ -154,6 +158,7 @@ struct tpacket3_hdr {
union { union {
struct tpacket_hdr_variant1 hv1; struct tpacket_hdr_variant1 hv1;
}; };
__u8 tp_padding[8];
}; };
struct tpacket_bd_ts { struct tpacket_bd_ts {
......
...@@ -977,9 +977,11 @@ static void prb_fill_vlan_info(struct tpacket_kbdq_core *pkc, ...@@ -977,9 +977,11 @@ static void prb_fill_vlan_info(struct tpacket_kbdq_core *pkc,
{ {
if (vlan_tx_tag_present(pkc->skb)) { if (vlan_tx_tag_present(pkc->skb)) {
ppd->hv1.tp_vlan_tci = vlan_tx_tag_get(pkc->skb); ppd->hv1.tp_vlan_tci = vlan_tx_tag_get(pkc->skb);
ppd->tp_status = TP_STATUS_VLAN_VALID; ppd->hv1.tp_vlan_tpid = ntohs(pkc->skb->vlan_proto);
ppd->tp_status = TP_STATUS_VLAN_VALID | TP_STATUS_VLAN_TPID_VALID;
} else { } else {
ppd->hv1.tp_vlan_tci = 0; ppd->hv1.tp_vlan_tci = 0;
ppd->hv1.tp_vlan_tpid = 0;
ppd->tp_status = TP_STATUS_AVAILABLE; ppd->tp_status = TP_STATUS_AVAILABLE;
} }
} }
...@@ -987,6 +989,7 @@ static void prb_fill_vlan_info(struct tpacket_kbdq_core *pkc, ...@@ -987,6 +989,7 @@ static void prb_fill_vlan_info(struct tpacket_kbdq_core *pkc,
static void prb_run_all_ft_ops(struct tpacket_kbdq_core *pkc, static void prb_run_all_ft_ops(struct tpacket_kbdq_core *pkc,
struct tpacket3_hdr *ppd) struct tpacket3_hdr *ppd)
{ {
ppd->hv1.tp_padding = 0;
prb_fill_vlan_info(pkc, ppd); prb_fill_vlan_info(pkc, ppd);
if (pkc->feature_req_word & TP_FT_REQ_FILL_RXHASH) if (pkc->feature_req_word & TP_FT_REQ_FILL_RXHASH)
...@@ -1812,6 +1815,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -1812,6 +1815,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
struct timespec ts; struct timespec ts;
__u32 ts_status; __u32 ts_status;
/* struct tpacket{2,3}_hdr is aligned to a multiple of TPACKET_ALIGNMENT.
* We may add members to them until current aligned size without forcing
* userspace to call getsockopt(..., PACKET_HDRLEN, ...).
*/
BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32);
BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48);
if (skb->pkt_type == PACKET_LOOPBACK) if (skb->pkt_type == PACKET_LOOPBACK)
goto drop; goto drop;
...@@ -1918,11 +1928,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -1918,11 +1928,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
h.h2->tp_nsec = ts.tv_nsec; h.h2->tp_nsec = ts.tv_nsec;
if (vlan_tx_tag_present(skb)) { if (vlan_tx_tag_present(skb)) {
h.h2->tp_vlan_tci = vlan_tx_tag_get(skb); h.h2->tp_vlan_tci = vlan_tx_tag_get(skb);
status |= TP_STATUS_VLAN_VALID; h.h2->tp_vlan_tpid = ntohs(skb->vlan_proto);
status |= TP_STATUS_VLAN_VALID | TP_STATUS_VLAN_TPID_VALID;
} else { } else {
h.h2->tp_vlan_tci = 0; h.h2->tp_vlan_tci = 0;
h.h2->tp_vlan_tpid = 0;
} }
h.h2->tp_padding = 0; memset(h.h2->tp_padding, 0, sizeof(h.h2->tp_padding));
hdrlen = sizeof(*h.h2); hdrlen = sizeof(*h.h2);
break; break;
case TPACKET_V3: case TPACKET_V3:
...@@ -1936,6 +1948,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -1936,6 +1948,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
h.h3->tp_net = netoff; h.h3->tp_net = netoff;
h.h3->tp_sec = ts.tv_sec; h.h3->tp_sec = ts.tv_sec;
h.h3->tp_nsec = ts.tv_nsec; h.h3->tp_nsec = ts.tv_nsec;
memset(h.h3->tp_padding, 0, sizeof(h.h3->tp_padding));
hdrlen = sizeof(*h.h3); hdrlen = sizeof(*h.h3);
break; break;
default: default:
...@@ -2867,11 +2880,12 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -2867,11 +2880,12 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
aux.tp_net = skb_network_offset(skb); aux.tp_net = skb_network_offset(skb);
if (vlan_tx_tag_present(skb)) { if (vlan_tx_tag_present(skb)) {
aux.tp_vlan_tci = vlan_tx_tag_get(skb); aux.tp_vlan_tci = vlan_tx_tag_get(skb);
aux.tp_status |= TP_STATUS_VLAN_VALID; aux.tp_vlan_tpid = ntohs(skb->vlan_proto);
aux.tp_status |= TP_STATUS_VLAN_VALID | TP_STATUS_VLAN_TPID_VALID;
} else { } else {
aux.tp_vlan_tci = 0; aux.tp_vlan_tci = 0;
aux.tp_vlan_tpid = 0;
} }
aux.tp_padding = 0;
put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux); put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment