summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
authorMahesh Bandewar <maheshb@google.com>2017-01-03 23:47:16 +0300
committerDavid S. Miller <davem@davemloft.net>2017-01-04 21:30:42 +0300
commit009146d117b9b816193fce0f1ed75f015a398721 (patch)
treeecc9af780e7e623bd46314e4e39e7d8b8ff19960 /drivers/net
parenta896eee3349e4e7f35a83f3b1a93c2e048d976b9 (diff)
downloadlinux-009146d117b9b816193fce0f1ed75f015a398721.tar.xz
ipvlan: assign unique dev-id for each slave device.
IPvlan setup uses one mac-address (of master). The IPv6 link-local addresses are derived using the mac-address on the link. Lack of dev-ids makes these link-local addresses same for all slaves including that of master device. dev-ids are necessary to add differentiation when L2 address is shared. Signed-off-by: Mahesh Bandewar <maheshb@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ipvlan/ipvlan.h1
-rw-r--r--drivers/net/ipvlan/ipvlan_main.c17
2 files changed, 17 insertions, 1 deletions
diff --git a/drivers/net/ipvlan/ipvlan.h b/drivers/net/ipvlan/ipvlan.h
index dbfbb33ac66c..0a9068fdee0f 100644
--- a/drivers/net/ipvlan/ipvlan.h
+++ b/drivers/net/ipvlan/ipvlan.h
@@ -97,6 +97,7 @@ struct ipvl_port {
struct work_struct wq;
struct sk_buff_head backlog;
int count;
+ struct ida ida;
};
struct ipvl_skb_cb {
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c
index 975f9ddb9908..ce7ca6a5aa8a 100644
--- a/drivers/net/ipvlan/ipvlan_main.c
+++ b/drivers/net/ipvlan/ipvlan_main.c
@@ -119,6 +119,7 @@ static int ipvlan_port_create(struct net_device *dev)
skb_queue_head_init(&port->backlog);
INIT_WORK(&port->wq, ipvlan_process_multicast);
+ ida_init(&port->ida);
err = netdev_rx_handler_register(dev, ipvlan_handle_frame, port);
if (err)
@@ -150,6 +151,7 @@ static void ipvlan_port_destroy(struct net_device *dev)
dev_put(skb->dev);
kfree_skb(skb);
}
+ ida_destroy(&port->ida);
kfree(port);
}
@@ -533,6 +535,16 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev,
ipvlan_adjust_mtu(ipvlan, phy_dev);
INIT_LIST_HEAD(&ipvlan->addrs);
+ /* Since L2 address is shared among all IPvlan slaves including
+ * master, use unique 16 bit dev-ids to diffentiate among them.
+ * Assign IDs between 0x1 and 0xFFFE (used by the master) to each
+ * slave link [see addrconf_ifid_eui48()].
+ */
+ err = ida_simple_get(&port->ida, 1, 0xFFFE, GFP_KERNEL);
+ if (err < 0)
+ goto destroy_ipvlan_port;
+ dev->dev_id = err;
+
/* TODO Probably put random address here to be presented to the
* world but keep using the physical-dev address for the outgoing
* packets.
@@ -543,7 +555,7 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev,
err = register_netdevice(dev);
if (err < 0)
- goto destroy_ipvlan_port;
+ goto remove_ida;
err = netdev_upper_dev_link(phy_dev, dev);
if (err) {
@@ -562,6 +574,8 @@ unlink_netdev:
netdev_upper_dev_unlink(phy_dev, dev);
unregister_netdev:
unregister_netdevice(dev);
+remove_ida:
+ ida_simple_remove(&port->ida, dev->dev_id);
destroy_ipvlan_port:
if (create)
ipvlan_port_destroy(phy_dev);
@@ -579,6 +593,7 @@ static void ipvlan_link_delete(struct net_device *dev, struct list_head *head)
kfree_rcu(addr, rcu);
}
+ ida_simple_remove(&ipvlan->port->ida, dev->dev_id);
list_del_rcu(&ipvlan->pnode);
unregister_netdevice_queue(dev, head);
netdev_upper_dev_unlink(ipvlan->phy_dev, dev);