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
}
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,
__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);
}
/* geneve receive/decap routine */
static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb)
static struct geneve_dev *geneve_lookup_skb(struct geneve_sock *gs,
struct sk_buff *skb)
{
struct genevehdr *gnvh = geneve_hdr(skb);
struct metadata_dst *tun_dst = NULL;
struct geneve_dev *geneve = NULL;
struct pcpu_sw_netstats *stats;
struct iphdr *iph = NULL;
u8 *vni;
__be32 addr;
static u8 zero_vni[3];
u8 *vni;
int err = 0;
sa_family_t sa_family;
#if IS_ENABLED(CONFIG_IPV6)
struct ipv6hdr *ip6h = NULL;
struct in6_addr addr6;
static struct in6_addr zero_addr6;
#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... */
if (gs->collect_md) {
vni = zero_vni;
addr = 0;
} else {
vni = gnvh->vni;
vni = geneve_hdr(skb)->vni;
addr = iph->saddr;
}
geneve = geneve_lookup(gs, addr, vni);
return geneve_lookup(gs, addr, vni);
#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... */
if (gs->collect_md) {
vni = zero_vni;
addr6 = zero_addr6;
} else {
vni = gnvh->vni;
vni = geneve_hdr(skb)->vni;
addr6 = ip6h->saddr;
}
geneve = geneve6_lookup(gs, addr6, vni);
return geneve6_lookup(gs, addr6, vni);
#endif
}
if (!geneve)
goto drop;
return NULL;
}
/* 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) {
__be16 flags;
@ -213,7 +220,7 @@ static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb)
(gnvh->oam ? TUNNEL_OAM : 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),
gnvh->opt_len * 4);
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_scrub_packet(skb, !net_eq(geneve->net, dev_net(geneve->dev)));
skb->protocol = eth_type_trans(skb, geneve->dev);
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))
goto drop;
oiph = skb_network_header(skb);
skb_reset_network_header(skb);
if (iph)
err = IP_ECN_decapsulate(iph, skb);
if (geneve_get_sk_family(gs) == AF_INET)
err = IP_ECN_decapsulate(oiph, skb);
#if IS_ENABLED(CONFIG_IPV6)
if (ip6h)
err = IP6_ECN_decapsulate(ip6h, skb);
else
err = IP6_ECN_decapsulate(oiph, skb);
#endif
if (unlikely(err)) {
if (log_ecn_error) {
if (iph)
if (geneve_get_sk_family(gs) == AF_INET)
net_info_ratelimited("non-ECT from %pI4 "
"with TOS=%#x\n",
&iph->saddr, iph->tos);
&((struct iphdr *)oiph)->saddr,
((struct iphdr *)oiph)->tos);
#if IS_ENABLED(CONFIG_IPV6)
if (ip6h)
else
net_info_ratelimited("non-ECT from %pI6\n",
&ip6h->saddr);
&((struct ipv6hdr *)oiph)->saddr);
#endif
}
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)
{
struct genevehdr *geneveh;
struct geneve_dev *geneve;
struct geneve_sock *gs;
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)))
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);
if (!gs)
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;
drop:
@ -392,7 +406,7 @@ static void geneve_notify_add_rx_port(struct geneve_sock *gs)
struct net_device *dev;
struct sock *sk = gs->sock->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;
int err;
@ -553,7 +567,7 @@ static void geneve_notify_del_rx_port(struct geneve_sock *gs)
struct net_device *dev;
struct sock *sk = gs->sock->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;
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) {
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;
}
}

View File

@ -1187,24 +1187,17 @@ static void vxlan_parse_gbp_hdr(struct vxlanhdr *unparsed,
unparsed->vx_flags &= ~VXLAN_GBP_USED_BITS;
}
static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
struct vxlan_metadata *md, __be32 vni,
static void vxlan_rcv(struct vxlan_dev *vxlan, struct vxlan_sock *vs,
struct sk_buff *skb, struct vxlan_metadata *md,
struct metadata_dst *tun_dst)
{
struct iphdr *oip = NULL;
struct ipv6hdr *oip6 = NULL;
struct vxlan_dev *vxlan;
struct pcpu_sw_netstats *stats;
union vxlan_addr saddr;
int err = 0;
/* Is this VNI defined? */
vxlan = vxlan_vs_find_vni(vs, vni);
if (!vxlan)
goto drop;
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_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)
{
struct metadata_dst *tun_dst = NULL;
struct vxlan_dev *vxlan;
struct vxlan_sock *vs;
struct vxlanhdr unparsed;
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_vni &= ~VXLAN_VNI_MASK;
if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB)))
goto drop;
vs = rcu_dereference_sk_user_data(sk);
if (!vs)
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)) {
__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;
}
vxlan_rcv(vs, skb, md, vxlan_vni(vxlan_hdr(skb)->vx_vni), tun_dst);
vxlan_rcv(vxlan, vs, skb, md, tun_dst);
return 0;
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);
}
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,
__be32 src, __be32 dst, u8 proto,
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 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,

View File

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

View File

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