From 776e53a8d90699f74f969dc51dfbff988728940b Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sat, 14 Mar 2009 18:01:41 -0700 Subject: [PATCH] brcompat: When adding or removing datapath ports, wait for them to appear/disappear. --- datapath/brcompat.c | 34 ++++++++++++++++++++---- datapath/linux-2.6/compat-2.6/compat26.h | 6 +++++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/datapath/brcompat.c b/datapath/brcompat.c index 02a15b82..10d8c8ce 100644 --- a/datapath/brcompat.c +++ b/datapath/brcompat.c @@ -1,10 +1,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include "compat.h" @@ -157,12 +159,11 @@ old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) struct net_device *port; int err; - port = dev_get_by_index(&init_net, args[1]); + port = __dev_get_by_index(&init_net, args[1]); if (!port) return -EINVAL; err = brc_send_port_add_del(dev, port, args[0] == BRCTL_ADD_IF); - dev_put(port); return err; } @@ -225,12 +226,11 @@ brc_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) case SIOCBRDELIF: { struct net_device *port; - port = dev_get_by_index(&init_net, rq->ifr_ifindex); + port = __dev_get_by_index(&init_net, rq->ifr_ifindex); if (!port) return -EINVAL; err = brc_send_port_add_del(dev, port, cmd == SIOCBRADDIF); - dev_put(port); break; } @@ -358,7 +358,9 @@ int brc_send_port_add_del(struct net_device *dev, struct net_device *port, struct dp_dev *dp_dev = netdev_priv(dev); struct datapath *dp = dp_dev->dp; struct sk_buff *skb; + int error; void *data; + int i; skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); if (skb == NULL) @@ -388,7 +390,29 @@ int brc_send_port_add_del(struct net_device *dev, struct net_device *port, NLA_PUT_STRING(skb, BRC_GENL_A_PORT_NAME, port->name); genlmsg_end(skb, data); - return genlmsg_multicast(skb, 0, brc_mc_group.id, GFP_KERNEL); + error = genlmsg_multicast(skb, 0, brc_mc_group.id, GFP_KERNEL); + if (error) + return error; + + for (i = 0; i < 100; i++) { + int dev_ifindex = dev->ifindex; + int port_ifindex = port->ifindex; + + rtnl_unlock(); + msleep(10); + rtnl_lock(); + + dev = __dev_get_by_index(&init_net, dev_ifindex); + port = __dev_get_by_index(&init_net, port_ifindex); + if (!dev || !port) + return ENODEV; + + if (add && port->br_port) + return port->br_port->dev ? 0 : -EBUSY; + else if (!add && !port->br_port) + return 0; + } + return -ETIMEDOUT; nla_put_failure: err: diff --git a/datapath/linux-2.6/compat-2.6/compat26.h b/datapath/linux-2.6/compat-2.6/compat26.h index 37f6a4f8..61448d63 100644 --- a/datapath/linux-2.6/compat-2.6/compat26.h +++ b/datapath/linux-2.6/compat-2.6/compat26.h @@ -17,6 +17,12 @@ #define dev_get_by_index(net, ifindex) \ dev_get_by_index((ifindex)) +#define __dev_get_by_name(net, name) \ + __dev_get_by_name((name)) + +#define __dev_get_by_index(net, ifindex) \ + __dev_get_by_index((ifindex)) + #endif /* linux kernel <= 2.6.23 */ -- 2.30.2