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