IP Tunnel protocol handler allows multiple modules register for
same protocol, e.g. linux vxlan devices and Open vSwitch both
can register for VXLAN device.

Signed-off-by: Pravin B Shelar <pshe...@nicira.com>
---
 drivers/net/vxlan.c |   68 +++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 53 insertions(+), 15 deletions(-)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index d2449f3..be2064b 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -497,11 +497,12 @@ static int vxlan_leave_group(struct net_device *dev)
 /* Callback from net/ipv4/udp.c to receive packets */
 static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 {
-       struct iphdr *oip;
        struct vxlanhdr *vxh;
-       struct vxlan_dev *vxlan;
-       struct pcpu_tstats *stats;
-       int err;
+       struct inet_sock *inet = inet_sk(sk);
+       struct tnl_ptk_info tpi;
+       struct ipt_protocol *proto;
+       struct hlist_node *n;
+       struct hlist_head *head;
 
        /* pop off outer UDP header */
        __skb_pull(skb, sizeof(struct udphdr));
@@ -520,14 +521,40 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct 
sk_buff *skb)
        }
 
        __skb_pull(skb, sizeof(struct vxlanhdr));
+       tpi.key = vxh->vx_vni;
+
+       head = ipt_hash_bucket(IPT_VXLAN, inet->inet_num);
+       hlist_for_each_entry_rcu(proto, n, head, node) {
+               int ret;
+
+               if (proto->type != IPT_VXLAN || proto->portno != inet->inet_num)
+                       continue;
+               ret = proto->handler(skb, &tpi);
+               if (ret <= 0)
+                       return ret;
 
-       /* Is this VNI defined? */
-       vxlan = vxlan_find_vni(sock_net(sk), vxh->vx_vni);
-       if (!vxlan) {
-               netdev_dbg(skb->dev, "unknown vni %d\n", ntohl(vxh->vx_vni) >> 
8);
-               goto drop;
        }
 
+error:
+       /* Put UDP header back */
+       __skb_push(skb, sizeof(struct udphdr));
+       return 1;
+}
+
+/* Callback from net/ipv4/udp.c to receive packets */
+static int vxlan_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi)
+{
+       struct vxlan_dev *vxlan;
+       struct net *net = dev_net(skb->dev);
+       struct iphdr *oip;
+       struct pcpu_tstats *stats;
+       int err;
+
+       /* Is this VNI defined? */
+       vxlan = vxlan_find_vni(net, tpi->key);
+       if (!vxlan)
+               return 1;
+
        if (!pskb_may_pull(skb, ETH_HLEN)) {
                vxlan->tunnel.dev->stats.rx_length_errors++;
                vxlan->tunnel.dev->stats.rx_errors++;
@@ -571,11 +598,6 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct 
sk_buff *skb)
        netif_rx(skb);
 
        return 0;
-error:
-       /* Put UDP header back */
-       __skb_push(skb, sizeof(struct udphdr));
-
-       return 1;
 drop:
        /* Consume bad packet */
        kfree_skb(skb);
@@ -1014,7 +1036,6 @@ static int vxlan_newlink(struct net *net, struct 
net_device *dev,
 
        vni = nla_get_u32(data[IFLA_VXLAN_ID]);
        vxlan->tunnel.parms.i_key = htonl(vni << 8);
-
        if (vxlan_find_vni(net, vxlan->tunnel.parms.i_key)) {
                pr_info("duplicate VNI %u\n", vni);
                return -EEXIST;
@@ -1209,6 +1230,12 @@ static struct pernet_operations vxlan_net_ops = {
        .size = sizeof(struct vxlan_net),
 };
 
+static struct ipt_protocol vxlan_protocol = {
+       .handler        = vxlan_rcv,
+       .priority       = 0,
+       .type           = IPT_VXLAN,
+};
+
 static int __init vxlan_init_module(void)
 {
        int rc;
@@ -1223,8 +1250,16 @@ static int __init vxlan_init_module(void)
        if (rc)
                goto out2;
 
+       vxlan_protocol.portno = vxlan_port;
+       rtnl_lock();
+       rc = ipt_add_protocol(&vxlan_protocol);
+       rtnl_unlock();
+       if (rc)
+               goto out3;
        return 0;
 
+out3:
+       rtnl_link_unregister(&vxlan_link_ops);
 out2:
        unregister_pernet_device(&vxlan_net_ops);
 out1:
@@ -1234,6 +1269,9 @@ module_init(vxlan_init_module);
 
 static void __exit vxlan_cleanup_module(void)
 {
+       rtnl_lock();
+       ipt_del_protocol(&vxlan_protocol);
+       rtnl_unlock();
        rtnl_link_unregister(&vxlan_link_ops);
        unregister_pernet_device(&vxlan_net_ops);
 }
-- 
1.7.10

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to