From: Pravin Shelar <pshe...@nicira.com>

I reference patch posted for IPGRE:
http://permalink.gmane.org/gmane.linux.network/226946

--8<--------------------------cut here-------------------------->8--

IP tunnels like other layered devices should propogate
carrier and state from lower device to tunnel.
Following patch would propogate link status to IPIP and
GRE devices.

Suggested-by: Stephen Hemminger <shemmin...@vyatta.com>
Signed-off-by: Pravin B Shelar <pshe...@nicira.com>
---
 include/net/ip_tunnel.h |    1 +
 net/ipv4/ip_tunnel.c    |  112 ++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 111 insertions(+), 2 deletions(-)

diff --git a/include/net/ip_tunnel.h b/include/net/ip_tunnel.h
index 7328871..5490a7d 100644
--- a/include/net/ip_tunnel.h
+++ b/include/net/ip_tunnel.h
@@ -21,6 +21,7 @@ struct ip_tunnel_6rd_parm {
 struct ip_tunnel {
        struct ip_tunnel __rcu  *next;
        struct hlist_node hash_node;
+       struct hlist_node link_node;
        struct net_device       *dev;
 
        int                     err_count;      /* Number of arrived ICMP 
errors */
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index 5e0e46e..f47345c 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -51,6 +51,11 @@
 #include <net/ip6_route.h>
 #endif
 
+struct tunnels_net {
+       struct hlist_head *link_map;
+};
+static int tunnels_net_id;
+
 static unsigned int ip_tunnel_hash(struct ip_tunnel_net *itn,
                                   __be32 key, __be32 remote)
 {
@@ -235,8 +240,58 @@ static void ip_tunnel_add(struct ip_tunnel_net *itn, 
struct ip_tunnel *t)
 static void ip_tunnel_del(struct ip_tunnel_net *itn, struct ip_tunnel *t)
 {
        hlist_del_init_rcu(&t->hash_node);
+       hlist_del_init_rcu(&t->link_node);
+}
+
+static void ip_tunnel_add_link(struct net *net, struct ip_tunnel *t, int 
iflink)
+{
+       struct tunnels_net *tn = net_generic(net, tunnels_net_id);
+       int hash = hash_32(iflink, IP_TNL_HASH_BITS);
+       struct hlist_head *head = &tn->link_map[hash];
+
+       hlist_add_head_rcu(&t->link_node, head);
+}
+
+static int ip_tunnel_notify(struct notifier_block *unused,
+               unsigned long event, void *ptr)
+{
+       struct net_device *rootdev = ptr;
+       struct tunnels_net *tn = net_generic(dev_net(rootdev), tunnels_net_id);
+       int hash = hash_32(rootdev->iflink, IP_TNL_HASH_BITS);
+       struct hlist_head *head = &tn->link_map[hash];
+       struct hlist_node *node, *n;
+       struct ip_tunnel *t;
+
+       hlist_for_each_entry_safe(t, node, n, head, link_node) {
+               int flags;
+
+               if (rootdev->ifindex != t->dev->iflink)
+                       continue;
+               switch (event) {
+               case NETDEV_DOWN:
+                       flags = t->dev->flags;
+                       if (!(flags & IFF_UP))
+                               break;
+                       dev_change_flags(t->dev, flags & ~IFF_UP);
+                       netif_stacked_transfer_operstate(rootdev, t->dev);
+                       break;
+               case NETDEV_UP:
+                       flags = t->dev->flags;
+                       if (flags & IFF_UP)
+                               break;
+                       dev_change_flags(t->dev, flags | IFF_UP);
+                       netif_stacked_transfer_operstate(rootdev, t->dev);
+                       break;
+               }
+
+       }
+       return NOTIFY_DONE;
 }
 
+static struct notifier_block ip_tunnel_notifier = {
+       .notifier_call = ip_tunnel_notify,
+};
+
 static struct ip_tunnel *ip_tunnel_find(struct ip_tunnel_net *itn,
                                 struct ip_tunnel_parm *parms,
                                 int type)
@@ -356,8 +411,12 @@ static int ip_tunnel_bind_dev(struct net_device *dev)
        if (tdev) {
                hlen = tdev->hard_header_len + tdev->needed_headroom;
                mtu = tdev->mtu;
+               netif_stacked_transfer_operstate(tdev, dev);
+               ip_tunnel_add_link(dev_net(dev), tunnel, tdev->ifindex);
+               dev->iflink = tdev->ifindex;
+       } else {
+               dev->iflink = tunnel->parms.link;
        }
-       dev->iflink = tunnel->parms.link;
 
        dev->needed_headroom = t_hlen + hlen;
        mtu -= (dev->hard_header_len + t_hlen);
@@ -935,7 +994,7 @@ int ip_tunnel_newlink(struct net *src_net, struct 
net_device *dev,
                dev->mtu = mtu;
 
        ip_tunnel_add(itn, nt);
-
+       linkwatch_fire_event(dev);
 out:
        return err;
 }
@@ -1060,4 +1119,53 @@ void ip_tunnel_setup(struct net_device *dev, int net_id)
 }
 EXPORT_SYMBOL(ip_tunnel_setup);
 
+static int __net_init tunnels_init_net(struct net *net)
+{
+       struct tunnels_net *tn = net_generic(net, tunnels_net_id);
+
+       tn->link_map = kzalloc(IP_TNL_HASH_SIZE * sizeof(struct hlist_head), 
GFP_KERNEL);
+       if (!tn->link_map)
+               return -ENOMEM;
+       return 0;
+}
+
+static void __net_exit tunnels_exit_net(struct net *net)
+{
+       struct tunnels_net *tn = net_generic(net, tunnels_net_id);
+       kfree(tn->link_map);
+}
+
+static struct pernet_operations tunnels_net_ops = {
+       .init = tunnels_init_net,
+       .exit = tunnels_exit_net,
+       .id   = &tunnels_net_id,
+       .size = sizeof(struct tunnels_net),
+};
+
+static int __init ip_tunnel_mod_init(void)
+{
+       int err;
+
+       pr_info("IP_Tunnel init\n");
+       err = register_pernet_device(&tunnels_net_ops);
+       if (err < 0)
+               return err;
+
+       err = register_netdevice_notifier(&ip_tunnel_notifier);
+       if (err < 0) {
+               unregister_pernet_device(&tunnels_net_ops);
+               return err;
+       }
+
+       return 0;
+}
+
+static void __exit ip_tunnel_mod_fini(void)
+{
+       unregister_netdevice_notifier(&ip_tunnel_notifier);
+       unregister_pernet_device(&tunnels_net_ops);
+}
+
+module_init(ip_tunnel_mod_init);
+module_exit(ip_tunnel_mod_fini);
 MODULE_LICENSE("GPL");
-- 
1.7.1

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

Reply via email to