This is used by openvswitch for building vxlan packet.

Signed-off-by: Pravin B Shelar <[email protected]>
---
 drivers/net/vxlan.c |   72 +++++++++++++++++++++++++++++++-------------------
 include/net/vxlan.h |    3 ++
 2 files changed, 48 insertions(+), 27 deletions(-)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index a17a7cb..11c1f69 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -909,10 +909,17 @@ static void vxlan_set_owner(const struct vxlan_port 
*port, struct sk_buff *skb)
 
 static int handle_offloads(struct sk_buff *skb)
 {
+       if (!skb->encapsulation) {
+               skb_reset_inner_headers(skb);
+               skb->encapsulation = 1;
+       }
+
        if (skb_is_gso(skb)) {
                int err = skb_unclone(skb, GFP_ATOMIC);
-               if (unlikely(err))
+               if (unlikely(err)) {
+                       kfree_skb(skb);
                        return err;
+               }
 
                skb_shinfo(skb)->gso_type |= (SKB_GSO_UDP_TUNNEL | SKB_GSO_UDP);
        } else if (skb->ip_summed != CHECKSUM_PARTIAL)
@@ -921,6 +928,38 @@ static int handle_offloads(struct sk_buff *skb)
        return 0;
 }
 
+struct sk_buff *vxlan_build_header(const struct vxlan_port *port,
+                                  __u16 src_port, struct sk_buff *skb,
+                                  __be32 vni)
+{
+       struct vxlanhdr *vxh;
+       struct udphdr *uh;
+       int err;
+
+       err = handle_offloads(skb);
+       if (err)
+               return NULL;
+
+       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 = port->portno;
+       uh->source = htons(src_port);
+
+       uh->len = htons(skb->len);
+       uh->check = 0;
+
+       vxlan_set_owner(port, skb);
+
+       return skb;
+}
+EXPORT_SYMBOL_GPL(vxlan_build_header);
+
 static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
                                  struct vxlan_rdst *rdst, bool did_rsc)
 {
@@ -929,8 +968,6 @@ static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, 
struct net_device *dev,
        struct rtable *rt;
        const struct iphdr *old_iph;
        struct iphdr *iph;
-       struct vxlanhdr *vxh;
-       struct udphdr *uh;
        struct flowi4 fl4;
        unsigned int pkt_len = skb->len;
        __be32 dst;
@@ -966,11 +1003,6 @@ static netdev_tx_t 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;
@@ -985,7 +1017,6 @@ static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, 
struct net_device *dev,
        if (tos == 1)
                tos = ip_tunnel_get_dsfield(old_iph, skb);
 
-       src_port = tunnel_src_port(vxlan->port_max, vxlan->port_min, skb);
 
        memset(&fl4, 0, sizeof(fl4));
        fl4.flowi4_oif = rdst->remote_ifindex;
@@ -1013,19 +1044,11 @@ static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, 
struct net_device *dev,
        skb_dst_drop(skb);
        skb_dst_set(skb, &rt->dst);
 
-       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 = htons(dst_port);
-       uh->source = htons(src_port);
-
-       uh->len = htons(skb->len);
-       uh->check = 0;
+       src_port = tunnel_src_port(vxlan->port_max, vxlan->port_min, skb);
+       skb = vxlan_build_header(&vn->port, src_port,
+                                skb, htonl(vni << 8));
+       if (!skb)
+               goto drop;
 
        __skb_push(skb, sizeof(*iph));
        skb_reset_network_header(skb);
@@ -1042,11 +1065,6 @@ static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, 
struct net_device *dev,
 
        nf_reset(skb);
 
-       vxlan_set_owner(&vn->port, skb);
-
-       if (handle_offloads(skb))
-               goto drop;
-
        iptunnel_xmit(skb, dev);
        return NETDEV_TX_OK;
 
diff --git a/include/net/vxlan.h b/include/net/vxlan.h
index dae9619..237ccff 100644
--- a/include/net/vxlan.h
+++ b/include/net/vxlan.h
@@ -12,6 +12,9 @@ struct vxlan_port {
        __be16 portno;
 };
 
+struct sk_buff *vxlan_build_header(const struct vxlan_port *port,
+                                  __u16 src_port,
+                                  struct sk_buff *skb, __be32 vni);
 int vxlan_add_handler(struct net *net, struct vxlan_port *);
 void vxlan_del_handler(struct net *net, const struct vxlan_port *port);
 #endif
-- 
1.7.1

_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev

Reply via email to