aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2013-03-26 12:45:12 -0400
committerDavid S. Miller <davem@davemloft.net>2013-03-26 12:45:12 -0400
commit33b7f0282e077db234afcf368a7a179b638e50a2 (patch)
tree59a450599ed491e4bd117ea56a60f5ab79821586
parentnetlink: remove duplicated NLMSG_ALIGN (diff)
parentnet_sched: better precise estimation on packet length for untrusted packets (diff)
downloadlinux-dev-33b7f0282e077db234afcf368a7a179b638e50a2.tar.xz
linux-dev-33b7f0282e077db234afcf368a7a179b638e50a2.zip
Merge branch 'transport-header'
Jason Wang says: ==================== We don't set transport header for untrusted packets in the past, but for the follwoing reasons, we need to do it now. - Better packet length estimation (introduced in 1def9238) needs l4 header for gso packets to compute the header length. - Some driver needs l4 header (e.g. ixgbe needs tcp header to do atr). So this patches tries to set transport header for packets from untrusted source (netback, packet, tuntap, macvtap). Plus a fix for better estimation on packet length for DODGY packet. Tested on tun/macvtap/packet, compile test on netback. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/macvtap.c9
-rw-r--r--drivers/net/tun.c10
-rw-r--r--drivers/net/xen-netback/netback.c12
-rw-r--r--net/core/dev.c8
-rw-r--r--net/packet/af_packet.c21
5 files changed, 59 insertions, 1 deletions
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index a449439bd653..acf6450ceff5 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -21,6 +21,7 @@
#include <net/rtnetlink.h>
#include <net/sock.h>
#include <linux/virtio_net.h>
+#include <net/flow_keys.h>
/*
* A macvtap queue is the central object of this driver, it connects
@@ -645,6 +646,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
int vnet_hdr_len = 0;
int copylen = 0;
bool zerocopy = false;
+ struct flow_keys keys;
if (q->flags & IFF_VNET_HDR) {
vnet_hdr_len = q->vnet_hdr_sz;
@@ -725,6 +727,13 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
goto err_kfree;
}
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ skb_set_transport_header(skb, skb_checksum_start_offset(skb));
+ else if (skb_flow_dissect(skb, &keys))
+ skb_set_transport_header(skb, keys.thoff);
+ else
+ skb_set_transport_header(skb, ETH_HLEN);
+
rcu_read_lock_bh();
vlan = rcu_dereference_bh(q->vlan);
/* copy skb_ubuf_info for callback when skb has no error */
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 95837c1b197a..48cd73a2dc55 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -70,6 +70,7 @@
#include <net/sock.h>
#include <asm/uaccess.h>
+#include <net/flow_keys.h>
/* Uncomment to enable debugging */
/* #define TUN_DEBUG 1 */
@@ -1049,6 +1050,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
bool zerocopy = false;
int err;
u32 rxhash;
+ struct flow_keys keys;
if (!(tun->flags & TUN_NO_PI)) {
if ((len -= sizeof(pi)) > total_len)
@@ -1203,6 +1205,14 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
}
skb_reset_network_header(skb);
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ skb_set_transport_header(skb, skb_checksum_start_offset(skb));
+ else if (skb_flow_dissect(skb, &keys))
+ skb_set_transport_header(skb, keys.thoff);
+ else
+ skb_reset_transport_header(skb);
+
rxhash = skb_get_rxhash(skb);
netif_rx_ni(skb);
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index aa28550fc9b6..fc8faa74b250 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -39,6 +39,7 @@
#include <linux/udp.h>
#include <net/tcp.h>
+#include <net/flow_keys.h>
#include <xen/xen.h>
#include <xen/events.h>
@@ -1184,6 +1185,7 @@ static int checksum_setup(struct xenvif *vif, struct sk_buff *skb)
if (th >= skb_tail_pointer(skb))
goto out;
+ skb_set_transport_header(skb, 4 * iph->ihl);
skb->csum_start = th - skb->head;
switch (iph->protocol) {
case IPPROTO_TCP:
@@ -1495,6 +1497,7 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
skb->dev = vif->dev;
skb->protocol = eth_type_trans(skb, skb->dev);
+ skb_reset_network_header(skb);
if (checksum_setup(vif, skb)) {
netdev_dbg(vif->dev,
@@ -1503,6 +1506,15 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
continue;
}
+ if (!skb_transport_header_was_set(skb)) {
+ struct flow_keys keys;
+
+ if (skb_flow_dissect(skb, &keys))
+ skb_set_transport_header(skb, keys.thoff);
+ else
+ skb_reset_transport_header(skb);
+ }
+
vif->dev->stats.rx_bytes += skb->len;
vif->dev->stats.rx_packets++;
diff --git a/net/core/dev.c b/net/core/dev.c
index de930b751712..f5ad23bb24fc 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2588,6 +2588,7 @@ static void qdisc_pkt_len_init(struct sk_buff *skb)
*/
if (shinfo->gso_size) {
unsigned int hdr_len;
+ u16 gso_segs = shinfo->gso_segs;
/* mac layer + network layer */
hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
@@ -2597,7 +2598,12 @@ static void qdisc_pkt_len_init(struct sk_buff *skb)
hdr_len += tcp_hdrlen(skb);
else
hdr_len += sizeof(struct udphdr);
- qdisc_skb_cb(skb)->pkt_len += (shinfo->gso_segs - 1) * hdr_len;
+
+ if (shinfo->gso_type & SKB_GSO_DODGY)
+ gso_segs = DIV_ROUND_UP(skb->len - hdr_len,
+ shinfo->gso_size);
+
+ qdisc_skb_cb(skb)->pkt_len += (gso_segs - 1) * hdr_len;
}
}
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index bd0d14c97d41..83fdd0a87eb6 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -88,6 +88,7 @@
#include <linux/virtio_net.h>
#include <linux/errqueue.h>
#include <linux/net_tstamp.h>
+#include <net/flow_keys.h>
#ifdef CONFIG_INET
#include <net/inet_common.h>
@@ -1412,6 +1413,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
__be16 proto = 0;
int err;
int extra_len = 0;
+ struct flow_keys keys;
/*
* Get and verify the address.
@@ -1512,6 +1514,11 @@ retry:
if (unlikely(extra_len == 4))
skb->no_fcs = 1;
+ if (skb_flow_dissect(skb, &keys))
+ skb_set_transport_header(skb, keys.thoff);
+ else
+ skb_reset_transport_header(skb);
+
dev_queue_xmit(skb);
rcu_read_unlock();
return len;
@@ -1918,6 +1925,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
struct page *page;
void *data;
int err;
+ struct flow_keys keys;
ph.raw = frame;
@@ -1943,6 +1951,11 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
skb_reserve(skb, hlen);
skb_reset_network_header(skb);
+ if (skb_flow_dissect(skb, &keys))
+ skb_set_transport_header(skb, keys.thoff);
+ else
+ skb_reset_transport_header(skb);
+
if (po->tp_tx_has_off) {
int off_min, off_max, off;
off_min = po->tp_hdrlen - sizeof(struct sockaddr_ll);
@@ -2199,6 +2212,7 @@ static int packet_snd(struct socket *sock,
unsigned short gso_type = 0;
int hlen, tlen;
int extra_len = 0;
+ struct flow_keys keys;
/*
* Get and verify the address.
@@ -2351,6 +2365,13 @@ static int packet_snd(struct socket *sock,
len += vnet_hdr_len;
}
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ skb_set_transport_header(skb, skb_checksum_start_offset(skb));
+ else if (skb_flow_dissect(skb, &keys))
+ skb_set_transport_header(skb, keys.thoff);
+ else
+ skb_set_transport_header(skb, reserve);
+
if (unlikely(extra_len == 4))
skb->no_fcs = 1;