[PATCH] veth: replace iflink by a dedicated symlink in sysfs
From: Vincent Bernat <hidden>
Date: 2015-08-19 06:53:07
Subsystem:
networking drivers, the rest · Maintainers:
Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
While the documentation doesn't say exactly what kind of relationship iflink should represent, until a45253, only lower devices were advertised this way. While veth cannot have a lower device, using iflink to advertise the peer may create infinite loops in programs using iflink to discover device topology. Instead of advertising the peer link with iflink, a symbolic link "peer" is added to each peer. Signed-off-by: Vincent Bernat <redacted> --- drivers/net/veth.c | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-)
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index c8186ffda1a3..47f165bc3107 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c@@ -105,6 +105,17 @@ static const struct ethtool_ops veth_ethtool_ops = { .get_ethtool_stats = veth_get_ethtool_stats, }; +static int veth_peer_sysfs_add(struct net_device *dev, + struct net_device *peer_dev) +{ + return sysfs_create_link(&(dev->dev.kobj), &(peer_dev->dev.kobj), + "peer"); +} +static void veth_peer_sysfs_del(struct net_device *dev) +{ + sysfs_remove_link(&(dev->dev.kobj), "peer"); +} + static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) { struct veth_priv *priv = netdev_priv(dev);
@@ -263,20 +274,6 @@ static void veth_poll_controller(struct net_device *dev) } #endif /* CONFIG_NET_POLL_CONTROLLER */ -static int veth_get_iflink(const struct net_device *dev) -{ - struct veth_priv *priv = netdev_priv(dev); - struct net_device *peer; - int iflink; - - rcu_read_lock(); - peer = rcu_dereference(priv->peer); - iflink = peer ? peer->ifindex : 0; - rcu_read_unlock(); - - return iflink; -} - static const struct net_device_ops veth_netdev_ops = { .ndo_init = veth_dev_init, .ndo_open = veth_open,
@@ -289,7 +286,6 @@ static const struct net_device_ops veth_netdev_ops = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = veth_poll_controller, #endif - .ndo_get_iflink = veth_get_iflink, }; #define VETH_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \
@@ -436,6 +432,13 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, netif_carrier_off(dev); + err = veth_peer_sysfs_add(dev, peer); + if (err < 0) + goto err_configure_dev; + err = veth_peer_sysfs_add(peer, dev); + if (err < 0) + goto err_configure_dev; + /* * tie the deviced together */
@@ -447,9 +450,13 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, rcu_assign_pointer(priv->peer, dev); return 0; +err_configure_dev: + veth_peer_sysfs_del(dev); + veth_peer_sysfs_del(peer); err_register_dev: /* nothing to do */ err_configure_peer: + veth_peer_sysfs_del(dev); unregister_netdevice(peer); return err;
@@ -466,6 +473,9 @@ static void veth_dellink(struct net_device *dev, struct list_head *head) priv = netdev_priv(dev); peer = rtnl_dereference(priv->peer); + veth_peer_sysfs_del(dev); + if (peer) veth_peer_sysfs_del(dev); + /* Note : dellink() is called from default_device_exit_batch(), * before a rcu_synchronize() point. The devices are guaranteed * not being freed before one RCU grace period.
--
2.5.0