Merge branch 'iptunnel-pkt-scrub-consolidate'

Jiri Benc says:

====================
iptunnel: scrub packet in iptunnel_pull_header

As every IP tunnel has to scrub skb on decapsulation, iptunnel_pull_header
tried to do that and open coded part of skb_scrub_packet. Various tunneling
protocols (VXLAN, Geneve) then called full skb_scrub_packet on their own,
duplicating part of the scrubbing already done.

Consolidate the code, calling skb_scrub_packet from iptunnel_pull_header.
This will allow additional cleanups in VXLAN code, as the packet is scrubbed
early during rx processing after this patchset and VXLAN can start filling
out skb fields earlier.

The full picture of vxlan cleanup patches can be seen at:
https://github.com/jbenc/linux-vxlan/commits/master
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2016-02-18 14:35:02 -05:00
commit f0a404505c
7 changed files with 76 additions and 64 deletions

View File

@ -110,6 +110,11 @@ static __be64 vni_to_tunnel_id(const __u8 *vni)
#endif #endif
} }
static sa_family_t geneve_get_sk_family(struct geneve_sock *gs)
{
return gs->sock->sk->sk_family;
}
static struct geneve_dev *geneve_lookup(struct geneve_sock *gs, static struct geneve_dev *geneve_lookup(struct geneve_sock *gs,
__be32 addr, u8 vni[]) __be32 addr, u8 vni[])
{ {
@ -153,58 +158,60 @@ static inline struct genevehdr *geneve_hdr(const struct sk_buff *skb)
return (struct genevehdr *)(udp_hdr(skb) + 1); return (struct genevehdr *)(udp_hdr(skb) + 1);
} }
/* geneve receive/decap routine */ static struct geneve_dev *geneve_lookup_skb(struct geneve_sock *gs,
static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb) struct sk_buff *skb)
{ {
struct genevehdr *gnvh = geneve_hdr(skb); u8 *vni;
struct metadata_dst *tun_dst = NULL;
struct geneve_dev *geneve = NULL;
struct pcpu_sw_netstats *stats;
struct iphdr *iph = NULL;
__be32 addr; __be32 addr;
static u8 zero_vni[3]; static u8 zero_vni[3];
u8 *vni;
int err = 0;
sa_family_t sa_family;
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
struct ipv6hdr *ip6h = NULL;
struct in6_addr addr6;
static struct in6_addr zero_addr6; static struct in6_addr zero_addr6;
#endif #endif
sa_family = gs->sock->sk->sk_family; if (geneve_get_sk_family(gs) == AF_INET) {
struct iphdr *iph;
if (sa_family == AF_INET) {
iph = ip_hdr(skb); /* outer IP header... */ iph = ip_hdr(skb); /* outer IP header... */
if (gs->collect_md) { if (gs->collect_md) {
vni = zero_vni; vni = zero_vni;
addr = 0; addr = 0;
} else { } else {
vni = gnvh->vni; vni = geneve_hdr(skb)->vni;
addr = iph->saddr; addr = iph->saddr;
} }
geneve = geneve_lookup(gs, addr, vni); return geneve_lookup(gs, addr, vni);
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
} else if (sa_family == AF_INET6) { } else if (geneve_get_sk_family(gs) == AF_INET6) {
struct ipv6hdr *ip6h;
struct in6_addr addr6;
ip6h = ipv6_hdr(skb); /* outer IPv6 header... */ ip6h = ipv6_hdr(skb); /* outer IPv6 header... */
if (gs->collect_md) { if (gs->collect_md) {
vni = zero_vni; vni = zero_vni;
addr6 = zero_addr6; addr6 = zero_addr6;
} else { } else {
vni = gnvh->vni; vni = geneve_hdr(skb)->vni;
addr6 = ip6h->saddr; addr6 = ip6h->saddr;
} }
geneve = geneve6_lookup(gs, addr6, vni); return geneve6_lookup(gs, addr6, vni);
#endif #endif
} }
if (!geneve) return NULL;
goto drop; }
/* geneve receive/decap routine */
static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
struct sk_buff *skb)
{
struct genevehdr *gnvh = geneve_hdr(skb);
struct metadata_dst *tun_dst = NULL;
struct pcpu_sw_netstats *stats;
int err = 0;
void *oiph;
if (ip_tunnel_collect_metadata() || gs->collect_md) { if (ip_tunnel_collect_metadata() || gs->collect_md) {
__be16 flags; __be16 flags;
@ -213,7 +220,7 @@ static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb)
(gnvh->oam ? TUNNEL_OAM : 0) | (gnvh->oam ? TUNNEL_OAM : 0) |
(gnvh->critical ? TUNNEL_CRIT_OPT : 0); (gnvh->critical ? TUNNEL_CRIT_OPT : 0);
tun_dst = udp_tun_rx_dst(skb, sa_family, flags, tun_dst = udp_tun_rx_dst(skb, geneve_get_sk_family(gs), flags,
vni_to_tunnel_id(gnvh->vni), vni_to_tunnel_id(gnvh->vni),
gnvh->opt_len * 4); gnvh->opt_len * 4);
if (!tun_dst) if (!tun_dst)
@ -230,7 +237,6 @@ static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb)
} }
skb_reset_mac_header(skb); skb_reset_mac_header(skb);
skb_scrub_packet(skb, !net_eq(geneve->net, dev_net(geneve->dev)));
skb->protocol = eth_type_trans(skb, geneve->dev); skb->protocol = eth_type_trans(skb, geneve->dev);
skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
@ -241,25 +247,27 @@ static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb)
if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr)) if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr))
goto drop; goto drop;
oiph = skb_network_header(skb);
skb_reset_network_header(skb); skb_reset_network_header(skb);
if (iph) if (geneve_get_sk_family(gs) == AF_INET)
err = IP_ECN_decapsulate(iph, skb); err = IP_ECN_decapsulate(oiph, skb);
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
if (ip6h) else
err = IP6_ECN_decapsulate(ip6h, skb); err = IP6_ECN_decapsulate(oiph, skb);
#endif #endif
if (unlikely(err)) { if (unlikely(err)) {
if (log_ecn_error) { if (log_ecn_error) {
if (iph) if (geneve_get_sk_family(gs) == AF_INET)
net_info_ratelimited("non-ECT from %pI4 " net_info_ratelimited("non-ECT from %pI4 "
"with TOS=%#x\n", "with TOS=%#x\n",
&iph->saddr, iph->tos); &((struct iphdr *)oiph)->saddr,
((struct iphdr *)oiph)->tos);
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
if (ip6h) else
net_info_ratelimited("non-ECT from %pI6\n", net_info_ratelimited("non-ECT from %pI6\n",
&ip6h->saddr); &((struct ipv6hdr *)oiph)->saddr);
#endif #endif
} }
if (err > 1) { if (err > 1) {
@ -321,6 +329,7 @@ static void geneve_uninit(struct net_device *dev)
static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb) static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
{ {
struct genevehdr *geneveh; struct genevehdr *geneveh;
struct geneve_dev *geneve;
struct geneve_sock *gs; struct geneve_sock *gs;
int opts_len; int opts_len;
@ -336,16 +345,21 @@ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
if (unlikely(geneveh->proto_type != htons(ETH_P_TEB))) if (unlikely(geneveh->proto_type != htons(ETH_P_TEB)))
goto error; goto error;
opts_len = geneveh->opt_len * 4;
if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len,
htons(ETH_P_TEB)))
goto drop;
gs = rcu_dereference_sk_user_data(sk); gs = rcu_dereference_sk_user_data(sk);
if (!gs) if (!gs)
goto drop; goto drop;
geneve_rx(gs, skb); geneve = geneve_lookup_skb(gs, skb);
if (!geneve)
goto drop;
opts_len = geneveh->opt_len * 4;
if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len,
htons(ETH_P_TEB),
!net_eq(geneve->net, dev_net(geneve->dev))))
goto drop;
geneve_rx(geneve, gs, skb);
return 0; return 0;
drop: drop:
@ -392,7 +406,7 @@ static void geneve_notify_add_rx_port(struct geneve_sock *gs)
struct net_device *dev; struct net_device *dev;
struct sock *sk = gs->sock->sk; struct sock *sk = gs->sock->sk;
struct net *net = sock_net(sk); struct net *net = sock_net(sk);
sa_family_t sa_family = sk->sk_family; sa_family_t sa_family = geneve_get_sk_family(gs);
__be16 port = inet_sk(sk)->inet_sport; __be16 port = inet_sk(sk)->inet_sport;
int err; int err;
@ -553,7 +567,7 @@ static void geneve_notify_del_rx_port(struct geneve_sock *gs)
struct net_device *dev; struct net_device *dev;
struct sock *sk = gs->sock->sk; struct sock *sk = gs->sock->sk;
struct net *net = sock_net(sk); struct net *net = sock_net(sk);
sa_family_t sa_family = sk->sk_family; sa_family_t sa_family = geneve_get_sk_family(gs);
__be16 port = inet_sk(sk)->inet_sport; __be16 port = inet_sk(sk)->inet_sport;
rcu_read_lock(); rcu_read_lock();
@ -596,7 +610,7 @@ static struct geneve_sock *geneve_find_sock(struct geneve_net *gn,
list_for_each_entry(gs, &gn->sock_list, list) { list_for_each_entry(gs, &gn->sock_list, list) {
if (inet_sk(gs->sock->sk)->inet_sport == dst_port && if (inet_sk(gs->sock->sk)->inet_sport == dst_port &&
inet_sk(gs->sock->sk)->sk.sk_family == family) { geneve_get_sk_family(gs) == family) {
return gs; return gs;
} }
} }

View File

@ -1187,24 +1187,17 @@ static void vxlan_parse_gbp_hdr(struct vxlanhdr *unparsed,
unparsed->vx_flags &= ~VXLAN_GBP_USED_BITS; unparsed->vx_flags &= ~VXLAN_GBP_USED_BITS;
} }
static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, static void vxlan_rcv(struct vxlan_dev *vxlan, struct vxlan_sock *vs,
struct vxlan_metadata *md, __be32 vni, struct sk_buff *skb, struct vxlan_metadata *md,
struct metadata_dst *tun_dst) struct metadata_dst *tun_dst)
{ {
struct iphdr *oip = NULL; struct iphdr *oip = NULL;
struct ipv6hdr *oip6 = NULL; struct ipv6hdr *oip6 = NULL;
struct vxlan_dev *vxlan;
struct pcpu_sw_netstats *stats; struct pcpu_sw_netstats *stats;
union vxlan_addr saddr; union vxlan_addr saddr;
int err = 0; int err = 0;
/* Is this VNI defined? */
vxlan = vxlan_vs_find_vni(vs, vni);
if (!vxlan)
goto drop;
skb_reset_mac_header(skb); skb_reset_mac_header(skb);
skb_scrub_packet(skb, !net_eq(vxlan->net, dev_net(vxlan->dev)));
skb->protocol = eth_type_trans(skb, vxlan->dev); skb->protocol = eth_type_trans(skb, vxlan->dev);
skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
@ -1281,6 +1274,7 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
{ {
struct metadata_dst *tun_dst = NULL; struct metadata_dst *tun_dst = NULL;
struct vxlan_dev *vxlan;
struct vxlan_sock *vs; struct vxlan_sock *vs;
struct vxlanhdr unparsed; struct vxlanhdr unparsed;
struct vxlan_metadata _md; struct vxlan_metadata _md;
@ -1302,13 +1296,18 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
unparsed.vx_flags &= ~VXLAN_HF_VNI; unparsed.vx_flags &= ~VXLAN_HF_VNI;
unparsed.vx_vni &= ~VXLAN_VNI_MASK; unparsed.vx_vni &= ~VXLAN_VNI_MASK;
if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB)))
goto drop;
vs = rcu_dereference_sk_user_data(sk); vs = rcu_dereference_sk_user_data(sk);
if (!vs) if (!vs)
goto drop; goto drop;
vxlan = vxlan_vs_find_vni(vs, vxlan_vni(vxlan_hdr(skb)->vx_vni));
if (!vxlan)
goto drop;
if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB),
!net_eq(vxlan->net, dev_net(vxlan->dev))))
goto drop;
if (vxlan_collect_metadata(vs)) { if (vxlan_collect_metadata(vs)) {
__be32 vni = vxlan_vni(vxlan_hdr(skb)->vx_vni); __be32 vni = vxlan_vni(vxlan_hdr(skb)->vx_vni);
@ -1344,7 +1343,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
goto drop; goto drop;
} }
vxlan_rcv(vs, skb, md, vxlan_vni(vxlan_hdr(skb)->vx_vni), tun_dst); vxlan_rcv(vxlan, vs, skb, md, tun_dst);
return 0; return 0;
drop: drop:

View File

@ -270,7 +270,8 @@ static inline u8 ip_tunnel_ecn_encap(u8 tos, const struct iphdr *iph,
return INET_ECN_encapsulate(tos, inner); return INET_ECN_encapsulate(tos, inner);
} }
int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto); int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto,
bool xnet);
void iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb, void iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
__be32 src, __be32 dst, u8 proto, __be32 src, __be32 dst, u8 proto,
u8 tos, u8 ttl, __be16 df, bool xnet); u8 tos, u8 ttl, __be16 df, bool xnet);

View File

@ -238,7 +238,7 @@ static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
return -EINVAL; return -EINVAL;
} }
} }
return iptunnel_pull_header(skb, hdr_len, tpi->proto); return iptunnel_pull_header(skb, hdr_len, tpi->proto, false);
} }
static void ipgre_err(struct sk_buff *skb, u32 info, static void ipgre_err(struct sk_buff *skb, u32 info,

View File

@ -86,7 +86,8 @@ void iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
} }
EXPORT_SYMBOL_GPL(iptunnel_xmit); EXPORT_SYMBOL_GPL(iptunnel_xmit);
int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto) int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto,
bool xnet)
{ {
if (unlikely(!pskb_may_pull(skb, hdr_len))) if (unlikely(!pskb_may_pull(skb, hdr_len)))
return -ENOMEM; return -ENOMEM;
@ -109,13 +110,10 @@ int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto)
skb->protocol = inner_proto; skb->protocol = inner_proto;
} }
nf_reset(skb);
secpath_reset(skb);
skb_clear_hash_if_not_l4(skb); skb_clear_hash_if_not_l4(skb);
skb_dst_drop(skb);
skb->vlan_tci = 0; skb->vlan_tci = 0;
skb_set_queue_mapping(skb, 0); skb_set_queue_mapping(skb, 0);
skb->pkt_type = PACKET_HOST; skb_scrub_packet(skb, xnet);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(iptunnel_pull_header); EXPORT_SYMBOL_GPL(iptunnel_pull_header);

View File

@ -195,7 +195,7 @@ static int ipip_rcv(struct sk_buff *skb)
if (tunnel) { if (tunnel) {
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
goto drop; goto drop;
if (iptunnel_pull_header(skb, 0, tpi.proto)) if (iptunnel_pull_header(skb, 0, tpi.proto, false))
goto drop; goto drop;
return ip_tunnel_rcv(tunnel, skb, &tpi, NULL, log_ecn_error); return ip_tunnel_rcv(tunnel, skb, &tpi, NULL, log_ecn_error);
} }

View File

@ -740,7 +740,7 @@ static int ipip_rcv(struct sk_buff *skb)
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
goto drop; goto drop;
if (iptunnel_pull_header(skb, 0, tpi.proto)) if (iptunnel_pull_header(skb, 0, tpi.proto, false))
goto drop; goto drop;
return ip_tunnel_rcv(tunnel, skb, &tpi, NULL, log_ecn_error); return ip_tunnel_rcv(tunnel, skb, &tpi, NULL, log_ecn_error);
} }