Loading drivers/net/vxlan.c +54 −37 Original line number Diff line number Diff line Loading @@ -1082,11 +1082,8 @@ static void vxlan_sock_put(struct sk_buff *skb) } /* On transmit, associate with the tunnel socket */ static void vxlan_set_owner(struct net_device *dev, struct sk_buff *skb) static void vxlan_set_owner(struct sock *sk, struct sk_buff *skb) { struct vxlan_dev *vxlan = netdev_priv(dev); struct sock *sk = vxlan->vn_sock->sock->sk; skb_orphan(skb); sock_hold(sk); skb->sk = sk; Loading @@ -1098,9 +1095,9 @@ static void vxlan_set_owner(struct net_device *dev, struct sk_buff *skb) * better and maybe available from hardware * secondary choice is to use jhash on the Ethernet header */ static __be16 vxlan_src_port(const struct vxlan_dev *vxlan, struct sk_buff *skb) __be16 vxlan_src_port(__u16 port_min, __u16 port_max, struct sk_buff *skb) { unsigned int range = (vxlan->port_max - vxlan->port_min) + 1; unsigned int range = (port_max - port_min) + 1; u32 hash; hash = skb_get_rxhash(skb); Loading @@ -1108,8 +1105,9 @@ static __be16 vxlan_src_port(const struct vxlan_dev *vxlan, struct sk_buff *skb) hash = jhash(skb->data, 2 * ETH_ALEN, (__force u32) skb->protocol); return htons((((u64) hash * range) >> 32) + vxlan->port_min); return htons((((u64) hash * range) >> 32) + port_min); } EXPORT_SYMBOL_GPL(vxlan_src_port); static int handle_offloads(struct sk_buff *skb) { Loading @@ -1125,6 +1123,45 @@ static int handle_offloads(struct sk_buff *skb) return 0; } int vxlan_xmit_skb(struct net *net, struct vxlan_sock *vs, struct rtable *rt, struct sk_buff *skb, __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, __be16 src_port, __be16 dst_port, __be32 vni) { struct vxlanhdr *vxh; struct udphdr *uh; int err; if (!skb->encapsulation) { skb_reset_inner_headers(skb); skb->encapsulation = 1; } vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); vxh->vx_flags = htonl(VXLAN_FLAGS); vxh->vx_vni = vni; __skb_push(skb, sizeof(*uh)); skb_reset_transport_header(skb); uh = udp_hdr(skb); uh->dest = dst_port; uh->source = src_port; uh->len = htons(skb->len); uh->check = 0; vxlan_set_owner(vs->sock->sk, skb); err = handle_offloads(skb); if (err) return err; return iptunnel_xmit(net, rt, skb, src, dst, IPPROTO_UDP, tos, ttl, df); } EXPORT_SYMBOL_GPL(vxlan_xmit_skb); /* Bypass encapsulation if the destination is local */ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, struct vxlan_dev *dst_vxlan) Loading Loading @@ -1162,8 +1199,6 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, struct vxlan_dev *vxlan = netdev_priv(dev); struct rtable *rt; const struct iphdr *old_iph; struct vxlanhdr *vxh; struct udphdr *uh; struct flowi4 fl4; __be32 dst; __be16 src_port, dst_port; Loading @@ -1185,11 +1220,6 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, goto drop; } if (!skb->encapsulation) { skb_reset_inner_headers(skb); skb->encapsulation = 1; } /* Need space for new headers (invalidates iph ptr) */ if (skb_cow_head(skb, VXLAN_HEADROOM)) goto drop; Loading @@ -1204,7 +1234,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, if (tos == 1) tos = ip_tunnel_get_dsfield(old_iph, skb); src_port = vxlan_src_port(vxlan, skb); src_port = vxlan_src_port(vxlan->port_min, vxlan->port_max, skb); memset(&fl4, 0, sizeof(fl4)); fl4.flowi4_oif = rdst->remote_ifindex; Loading @@ -1221,9 +1251,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, if (rt->dst.dev == dev) { netdev_dbg(dev, "circular route to %pI4\n", &dst); ip_rt_put(rt); dev->stats.collisions++; goto tx_error; goto rt_tx_error; } /* Bypass encapsulation if the destination is local */ Loading @@ -1238,30 +1267,16 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, vxlan_encap_bypass(skb, vxlan, dst_vxlan); return; } vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); vxh->vx_flags = htonl(VXLAN_FLAGS); vxh->vx_vni = htonl(vni << 8); __skb_push(skb, sizeof(*uh)); skb_reset_transport_header(skb); uh = udp_hdr(skb); uh->dest = dst_port; uh->source = src_port; uh->len = htons(skb->len); uh->check = 0; vxlan_set_owner(dev, skb); if (handle_offloads(skb)) goto drop; tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); err = iptunnel_xmit(dev_net(dev), rt, skb, fl4.saddr, dst, IPPROTO_UDP, tos, ttl, df); err = vxlan_xmit_skb(dev_net(dev), vxlan->vn_sock, rt, skb, fl4.saddr, dst, tos, ttl, df, src_port, dst_port, htonl(vni << 8)); if (err < 0) goto rt_tx_error; iptunnel_xmit_stats(err, &dev->stats, dev->tstats); return; Loading @@ -1270,6 +1285,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, dev->stats.tx_dropped++; goto tx_free; rt_tx_error: ip_rt_put(rt); tx_error: dev->stats.tx_errors++; tx_free: Loading include/net/vxlan.h +8 −0 Original line number Diff line number Diff line Loading @@ -28,4 +28,12 @@ struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, bool no_share); void vxlan_sock_release(struct vxlan_sock *vs); int vxlan_xmit_skb(struct net *net, struct vxlan_sock *vs, struct rtable *rt, struct sk_buff *skb, __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, __be16 src_port, __be16 dst_port, __be32 vni); __be16 vxlan_src_port(__u16 port_min, __u16 port_max, struct sk_buff *skb); #endif Loading
drivers/net/vxlan.c +54 −37 Original line number Diff line number Diff line Loading @@ -1082,11 +1082,8 @@ static void vxlan_sock_put(struct sk_buff *skb) } /* On transmit, associate with the tunnel socket */ static void vxlan_set_owner(struct net_device *dev, struct sk_buff *skb) static void vxlan_set_owner(struct sock *sk, struct sk_buff *skb) { struct vxlan_dev *vxlan = netdev_priv(dev); struct sock *sk = vxlan->vn_sock->sock->sk; skb_orphan(skb); sock_hold(sk); skb->sk = sk; Loading @@ -1098,9 +1095,9 @@ static void vxlan_set_owner(struct net_device *dev, struct sk_buff *skb) * better and maybe available from hardware * secondary choice is to use jhash on the Ethernet header */ static __be16 vxlan_src_port(const struct vxlan_dev *vxlan, struct sk_buff *skb) __be16 vxlan_src_port(__u16 port_min, __u16 port_max, struct sk_buff *skb) { unsigned int range = (vxlan->port_max - vxlan->port_min) + 1; unsigned int range = (port_max - port_min) + 1; u32 hash; hash = skb_get_rxhash(skb); Loading @@ -1108,8 +1105,9 @@ static __be16 vxlan_src_port(const struct vxlan_dev *vxlan, struct sk_buff *skb) hash = jhash(skb->data, 2 * ETH_ALEN, (__force u32) skb->protocol); return htons((((u64) hash * range) >> 32) + vxlan->port_min); return htons((((u64) hash * range) >> 32) + port_min); } EXPORT_SYMBOL_GPL(vxlan_src_port); static int handle_offloads(struct sk_buff *skb) { Loading @@ -1125,6 +1123,45 @@ static int handle_offloads(struct sk_buff *skb) return 0; } int vxlan_xmit_skb(struct net *net, struct vxlan_sock *vs, struct rtable *rt, struct sk_buff *skb, __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, __be16 src_port, __be16 dst_port, __be32 vni) { struct vxlanhdr *vxh; struct udphdr *uh; int err; if (!skb->encapsulation) { skb_reset_inner_headers(skb); skb->encapsulation = 1; } vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); vxh->vx_flags = htonl(VXLAN_FLAGS); vxh->vx_vni = vni; __skb_push(skb, sizeof(*uh)); skb_reset_transport_header(skb); uh = udp_hdr(skb); uh->dest = dst_port; uh->source = src_port; uh->len = htons(skb->len); uh->check = 0; vxlan_set_owner(vs->sock->sk, skb); err = handle_offloads(skb); if (err) return err; return iptunnel_xmit(net, rt, skb, src, dst, IPPROTO_UDP, tos, ttl, df); } EXPORT_SYMBOL_GPL(vxlan_xmit_skb); /* Bypass encapsulation if the destination is local */ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, struct vxlan_dev *dst_vxlan) Loading Loading @@ -1162,8 +1199,6 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, struct vxlan_dev *vxlan = netdev_priv(dev); struct rtable *rt; const struct iphdr *old_iph; struct vxlanhdr *vxh; struct udphdr *uh; struct flowi4 fl4; __be32 dst; __be16 src_port, dst_port; Loading @@ -1185,11 +1220,6 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, goto drop; } if (!skb->encapsulation) { skb_reset_inner_headers(skb); skb->encapsulation = 1; } /* Need space for new headers (invalidates iph ptr) */ if (skb_cow_head(skb, VXLAN_HEADROOM)) goto drop; Loading @@ -1204,7 +1234,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, if (tos == 1) tos = ip_tunnel_get_dsfield(old_iph, skb); src_port = vxlan_src_port(vxlan, skb); src_port = vxlan_src_port(vxlan->port_min, vxlan->port_max, skb); memset(&fl4, 0, sizeof(fl4)); fl4.flowi4_oif = rdst->remote_ifindex; Loading @@ -1221,9 +1251,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, if (rt->dst.dev == dev) { netdev_dbg(dev, "circular route to %pI4\n", &dst); ip_rt_put(rt); dev->stats.collisions++; goto tx_error; goto rt_tx_error; } /* Bypass encapsulation if the destination is local */ Loading @@ -1238,30 +1267,16 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, vxlan_encap_bypass(skb, vxlan, dst_vxlan); return; } vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); vxh->vx_flags = htonl(VXLAN_FLAGS); vxh->vx_vni = htonl(vni << 8); __skb_push(skb, sizeof(*uh)); skb_reset_transport_header(skb); uh = udp_hdr(skb); uh->dest = dst_port; uh->source = src_port; uh->len = htons(skb->len); uh->check = 0; vxlan_set_owner(dev, skb); if (handle_offloads(skb)) goto drop; tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); err = iptunnel_xmit(dev_net(dev), rt, skb, fl4.saddr, dst, IPPROTO_UDP, tos, ttl, df); err = vxlan_xmit_skb(dev_net(dev), vxlan->vn_sock, rt, skb, fl4.saddr, dst, tos, ttl, df, src_port, dst_port, htonl(vni << 8)); if (err < 0) goto rt_tx_error; iptunnel_xmit_stats(err, &dev->stats, dev->tstats); return; Loading @@ -1270,6 +1285,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, dev->stats.tx_dropped++; goto tx_free; rt_tx_error: ip_rt_put(rt); tx_error: dev->stats.tx_errors++; tx_free: Loading
include/net/vxlan.h +8 −0 Original line number Diff line number Diff line Loading @@ -28,4 +28,12 @@ struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, bool no_share); void vxlan_sock_release(struct vxlan_sock *vs); int vxlan_xmit_skb(struct net *net, struct vxlan_sock *vs, struct rtable *rt, struct sk_buff *skb, __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, __be16 src_port, __be16 dst_port, __be32 vni); __be16 vxlan_src_port(__u16 port_min, __u16 port_max, struct sk_buff *skb); #endif