lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20141227095950.20a062d2@urahara>
Date:	Sat, 27 Dec 2014 09:59:50 -0800
From:	Stephen Hemminger <shemming@...cade.com>
To:	David Miller <davem@...emloft.net>
CC:	<netdev@...r.kernel.org>
Subject: [PATCH net] tunnel: support propagating lower device state

This patch allows propagating the carrier state from lower device
to the upper tunnel device. This is similar to how stacked transfer
works for VLAN devices.

Signed-off-by: Stephen Hemminger <stephen@...workplumber.org>

---
 include/net/ip_tunnels.h |    2 
 net/ipv4/ip_tunnel.c     |  123 +++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 122 insertions(+), 3 deletions(-)

--- a/include/net/ip_tunnels.h	2014-12-27 09:51:00.584435221 -0800
+++ b/include/net/ip_tunnels.h	2014-12-27 09:51:00.580435199 -0800
@@ -54,6 +54,7 @@ struct ip_tunnel_dst {
 struct ip_tunnel {
 	struct ip_tunnel __rcu	*next;
 	struct hlist_node hash_node;
+	struct hlist_node link_node;
 	struct net_device	*dev;
 	struct net		*net;	/* netns for packet i/o */
 
@@ -115,6 +116,7 @@ struct tnl_ptk_info {
 struct ip_tunnel_net {
 	struct net_device *fb_tunnel_dev;
 	struct hlist_head tunnels[IP_TNL_HASH_SIZE];
+	struct hlist_head *lower_dev;
 };
 
 struct ip_tunnel_encap_ops {
--- a/net/ipv4/ip_tunnel.c	2014-12-27 09:51:00.584435221 -0800
+++ b/net/ipv4/ip_tunnel.c	2014-12-27 09:57:57.250907676 -0800
@@ -63,6 +63,11 @@
 #include <net/ip6_route.h>
 #endif
 
+static int tunnels_net_id;
+struct tunnels_net {
+	struct hlist_head link_map[IP_TNL_HASH_SIZE];
+};
+
 static unsigned int ip_tunnel_hash(__be32 key, __be32 remote)
 {
 	return hash_32((__force u32)key ^ (__force u32)remote,
@@ -267,8 +272,61 @@ static void ip_tunnel_add(struct ip_tunn
 static void ip_tunnel_del(struct ip_tunnel *t)
 {
 	hlist_del_init_rcu(&t->hash_node);
+	hlist_del_init(&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);
+
+	hlist_add_head(&t->link_node, &tn->link_map[hash]);
+}
+
+static int ip_tunnel_notify(struct notifier_block *unused,
+			    unsigned long event, void *ptr)
+{
+	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+	struct tunnels_net *tn = net_generic(dev_net(dev), tunnels_net_id);
+	int hash = hash_32(dev->ifindex, IP_TNL_HASH_BITS);
+	struct hlist_head *head = &tn->link_map[hash];
+	struct ip_tunnel *t;
+
+	hlist_for_each_entry(t, head, link_node) {
+		unsigned int flags = t->dev->flags;
+
+		if (dev->ifindex != t->dev->iflink)
+			continue;
+
+		switch (event) {
+		case NETDEV_CHANGE:
+			break;
+
+		case NETDEV_DOWN:
+			if (!(flags & IFF_UP))
+				break;
+			dev_change_flags(t->dev, flags & ~IFF_UP);
+			break;
+
+		case NETDEV_UP:
+			if (flags & IFF_UP)
+				break;
+			dev_change_flags(t->dev, flags | IFF_UP);
+			break;
+
+		default:
+			continue;
+		}
+		netif_stacked_transfer_operstate(dev, t->dev);
+	}
+
+	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)
@@ -330,6 +388,7 @@ static struct net_device *__ip_tunnel_cr
 	if (err)
 		goto failed_free;
 
+	linkwatch_fire_event(dev); /* _MUST_ call rfc2863_policy() */
 	return dev;
 
 failed_free:
@@ -388,8 +447,12 @@ static int ip_tunnel_bind_dev(struct net
 	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);
@@ -982,8 +1045,17 @@ int ip_tunnel_init_net(struct net *net,
 	for (i = 0; i < IP_TNL_HASH_SIZE; i++)
 		INIT_HLIST_HEAD(&itn->tunnels[i]);
 
+	itn->lower_dev = kcalloc(NETDEV_HASHENTRIES, sizeof(struct hlist_head),
+				 GFP_KERNEL);
+	if (!itn->lower_dev) {
+		kfree(itn->tunnels);
+		return -ENOMEM;
+	}
+
 	if (!ops) {
 		itn->fb_tunnel_dev = NULL;
+		kfree(itn->tunnels);
+		kfree(itn->lower_dev);
 		return 0;
 	}
 
@@ -1003,7 +1075,12 @@ int ip_tunnel_init_net(struct net *net,
 	}
 	rtnl_unlock();
 
-	return PTR_ERR_OR_ZERO(itn->fb_tunnel_dev);
+	if (IS_ERR(itn->fb_tunnel_dev)) {
+		kfree(itn->tunnels);
+		return PTR_ERR(itn->fb_tunnel_dev);
+	}
+	return 0;
+
 }
 EXPORT_SYMBOL_GPL(ip_tunnel_init_net);
 
@@ -1072,7 +1149,7 @@ int ip_tunnel_newlink(struct net_device
 		dev->mtu = mtu;
 
 	ip_tunnel_add(itn, nt);
-
+	linkwatch_fire_event(dev);
 out:
 	return err;
 }
@@ -1173,4 +1250,44 @@ void ip_tunnel_setup(struct net_device *
 }
 EXPORT_SYMBOL_GPL(ip_tunnel_setup);
 
+static int __net_init tunnels_init_net(struct net *net)
+{
+	struct tunnels_net *tn = net_generic(net, tunnels_net_id);
+	unsigned i;
+
+	for (i = 0; i < IP_TNL_HASH_SIZE; i++)
+		INIT_HLIST_HEAD(&tn->link_map[i]);
+
+	return 0;
+}
+
+static struct pernet_operations tunnels_net_ops = {
+	.init = tunnels_init_net,
+	.id   = &tunnels_net_id,
+	.size = sizeof(struct tunnels_net),
+};
+
+static int __init ip_tunnel_mod_init(void)
+{
+	int err;
+
+	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;
+}
+
+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");
--
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

Powered by Openwall GNU/*/Linux Powered by OpenVZ