[<prev] [next>] [day] [month] [year] [list]
Message-Id: <1357612313-1847-1-git-send-email-pshelar@nicira.com>
Date: Mon, 7 Jan 2013 18:31:53 -0800
From: Pravin B Shelar <pshelar@...ira.com>
To: dev@...nvswitch.org, netdev@...r.kernel.org
Cc: jesse@...ira.com, shemminger@...tta.com,
Pravin Shelar <pshelar@...ira.com>
Subject: [PATCH 5/5] IP_TUNNEL: follow state of lower device
From: Pravin Shelar <pshelar@...ira.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 <shemminger@...tta.com>
Signed-off-by: Pravin B Shelar <pshelar@...ira.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
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists