aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Chavent <Paul.Chavent@onera.fr>2012-11-06 18:10:47 -0500
committerDavid S. Miller <davem@davemloft.net>2012-11-07 18:54:30 -0500
commit5920cd3a41f1aefc30e9ce86384fc2fe9f5fe0c0 (patch)
treececc965a19e1ffe6957d8dcf2e55566562f93e0c
parent7da716aee2532399e213a14f656d304098f67a11 (diff)
packet: tx_ring: allow the user to choose tx data offset
The tx data offset of packet mmap tx ring used to be : (TPACKET2_HDRLEN - sizeof(struct sockaddr_ll)) The problem is that, with SOCK_RAW socket, the payload (14 bytes after the beginning of the user data) is misaligned. This patch allows to let the user gives an offset for it's tx data if he desires. Set sock option PACKET_TX_HAS_OFF to 1, then specify in each frame of your tx ring tp_net for SOCK_DGRAM, or tp_mac for SOCK_RAW. Signed-off-by: Paul Chavent <paul.chavent@onera.fr> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/networking/packet_mmap.txt13
-rw-r--r--include/uapi/linux/if_packet.h1
-rw-r--r--net/packet/af_packet.c46
-rw-r--r--net/packet/internal.h1
4 files changed, 60 insertions, 1 deletions
diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt
index 1c08a4b0981f..7cd879eba5dc 100644
--- a/Documentation/networking/packet_mmap.txt
+++ b/Documentation/networking/packet_mmap.txt
@@ -163,6 +163,19 @@ As capture, each frame contains two parts:
163 163
164 A complete tutorial is available at: http://wiki.gnu-log.net/ 164 A complete tutorial is available at: http://wiki.gnu-log.net/
165 165
166By default, the user should put data at :
167 frame base + TPACKET_HDRLEN - sizeof(struct sockaddr_ll)
168
169So, whatever you choose for the socket mode (SOCK_DGRAM or SOCK_RAW),
170the beginning of the user data will be at :
171 frame base + TPACKET_ALIGN(sizeof(struct tpacket_hdr))
172
173If you wish to put user data at a custom offset from the beginning of
174the frame (for payload alignment with SOCK_RAW mode for instance) you
175can set tp_net (with SOCK_DGRAM) or tp_mac (with SOCK_RAW). In order
176to make this work it must be enabled previously with setsockopt()
177and the PACKET_TX_HAS_OFF option.
178
166-------------------------------------------------------------------------------- 179--------------------------------------------------------------------------------
167+ PACKET_MMAP settings 180+ PACKET_MMAP settings
168-------------------------------------------------------------------------------- 181--------------------------------------------------------------------------------
diff --git a/include/uapi/linux/if_packet.h b/include/uapi/linux/if_packet.h
index f3799295d231..f9a60375f0d0 100644
--- a/include/uapi/linux/if_packet.h
+++ b/include/uapi/linux/if_packet.h
@@ -50,6 +50,7 @@ struct sockaddr_ll {
50#define PACKET_TX_TIMESTAMP 16 50#define PACKET_TX_TIMESTAMP 16
51#define PACKET_TIMESTAMP 17 51#define PACKET_TIMESTAMP 17
52#define PACKET_FANOUT 18 52#define PACKET_FANOUT 18
53#define PACKET_TX_HAS_OFF 19
53 54
54#define PACKET_FANOUT_HASH 0 55#define PACKET_FANOUT_HASH 0
55#define PACKET_FANOUT_LB 1 56#define PACKET_FANOUT_LB 1
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 9034f52659b5..f262dbfc7f06 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1881,7 +1881,35 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
1881 skb_reserve(skb, hlen); 1881 skb_reserve(skb, hlen);
1882 skb_reset_network_header(skb); 1882 skb_reset_network_header(skb);
1883 1883
1884 data = ph.raw + po->tp_hdrlen - sizeof(struct sockaddr_ll); 1884 if (po->tp_tx_has_off) {
1885 int off_min, off_max, off;
1886 off_min = po->tp_hdrlen - sizeof(struct sockaddr_ll);
1887 off_max = po->tx_ring.frame_size - tp_len;
1888 if (sock->type == SOCK_DGRAM) {
1889 switch (po->tp_version) {
1890 case TPACKET_V2:
1891 off = ph.h2->tp_net;
1892 break;
1893 default:
1894 off = ph.h1->tp_net;
1895 break;
1896 }
1897 } else {
1898 switch (po->tp_version) {
1899 case TPACKET_V2:
1900 off = ph.h2->tp_mac;
1901 break;
1902 default:
1903 off = ph.h1->tp_mac;
1904 break;
1905 }
1906 }
1907 if (unlikely((off < off_min) || (off_max < off)))
1908 return -EINVAL;
1909 data = ph.raw + off;
1910 } else {
1911 data = ph.raw + po->tp_hdrlen - sizeof(struct sockaddr_ll);
1912 }
1885 to_write = tp_len; 1913 to_write = tp_len;
1886 1914
1887 if (sock->type == SOCK_DGRAM) { 1915 if (sock->type == SOCK_DGRAM) {
@@ -3109,6 +3137,19 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
3109 3137
3110 return fanout_add(sk, val & 0xffff, val >> 16); 3138 return fanout_add(sk, val & 0xffff, val >> 16);
3111 } 3139 }
3140 case PACKET_TX_HAS_OFF:
3141 {
3142 unsigned int val;
3143
3144 if (optlen != sizeof(val))
3145 return -EINVAL;
3146 if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
3147 return -EBUSY;
3148 if (copy_from_user(&val, optval, sizeof(val)))
3149 return -EFAULT;
3150 po->tp_tx_has_off = !!val;
3151 return 0;
3152 }
3112 default: 3153 default:
3113 return -ENOPROTOOPT; 3154 return -ENOPROTOOPT;
3114 } 3155 }
@@ -3200,6 +3241,9 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
3200 ((u32)po->fanout->type << 16)) : 3241 ((u32)po->fanout->type << 16)) :
3201 0); 3242 0);
3202 break; 3243 break;
3244 case PACKET_TX_HAS_OFF:
3245 val = po->tp_tx_has_off;
3246 break;
3203 default: 3247 default:
3204 return -ENOPROTOOPT; 3248 return -ENOPROTOOPT;
3205 } 3249 }
diff --git a/net/packet/internal.h b/net/packet/internal.h
index 44945f6b7252..e84cab8cb7a9 100644
--- a/net/packet/internal.h
+++ b/net/packet/internal.h
@@ -109,6 +109,7 @@ struct packet_sock {
109 unsigned int tp_hdrlen; 109 unsigned int tp_hdrlen;
110 unsigned int tp_reserve; 110 unsigned int tp_reserve;
111 unsigned int tp_loss:1; 111 unsigned int tp_loss:1;
112 unsigned int tp_tx_has_off:1;
112 unsigned int tp_tstamp; 113 unsigned int tp_tstamp;
113 struct packet_type prot_hook ____cacheline_aligned_in_smp; 114 struct packet_type prot_hook ____cacheline_aligned_in_smp;
114}; 115};