From 4b60911067a82fbdfa87b7c2824412da20287ed8 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Fri, 10 May 2013 08:55:25 -0700 Subject: [PATCH] netdev: Factor restoring flags into new "struct netdev_saved_flags". This gets rid of the only per-instance data in "struct netdev", which will make it possible to merge "struct netdev_dev" into "struct netdev" in a later commit. Ed Maste wrote the netdev-bsd changes in this commit. Signed-off-by: Ben Pfaff Co-authored-by: Ed Maste Signed-off-by: Ed Maste Tested-by: Ed Maste --- lib/dpif-netdev.c | 6 +- lib/netdev-bsd.c | 43 +++++----- lib/netdev-dummy.c | 5 +- lib/netdev-linux.c | 22 +++--- lib/netdev-provider.h | 14 ++-- lib/netdev-vport.c | 2 +- lib/netdev.c | 177 +++++++++++++++++++++++++----------------- lib/netdev.h | 28 ++++--- ofproto/ofproto.c | 4 +- utilities/ovs-dpctl.c | 4 +- vswitchd/bridge.c | 4 +- 11 files changed, 175 insertions(+), 134 deletions(-) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 632a1de56..40f59c379 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -106,6 +106,7 @@ struct dp_netdev_port { int port_no; /* Index into dp_netdev's 'ports'. */ struct list node; /* Element in dp_netdev's 'port_list'. */ struct netdev *netdev; + struct netdev_saved_flags *sf; char *type; /* Port type as requested by user. */ }; @@ -374,6 +375,7 @@ static int do_add_port(struct dp_netdev *dp, const char *devname, const char *type, uint32_t port_no) { + struct netdev_saved_flags *sf; struct dp_netdev_port *port; struct netdev *netdev; const char *open_type; @@ -400,7 +402,7 @@ do_add_port(struct dp_netdev *dp, const char *devname, const char *type, return error; } - error = netdev_turn_flags_on(netdev, NETDEV_PROMISC, false); + error = netdev_turn_flags_on(netdev, NETDEV_PROMISC, &sf); if (error) { netdev_close(netdev); return error; @@ -409,6 +411,7 @@ do_add_port(struct dp_netdev *dp, const char *devname, const char *type, port = xmalloc(sizeof *port); port->port_no = port_no; port->netdev = netdev; + port->sf = sf; port->type = xstrdup(type); error = netdev_get_mtu(netdev, &mtu); @@ -505,6 +508,7 @@ do_del_port(struct dp_netdev *dp, uint32_t port_no) dp->serial++; netdev_close(port->netdev); + netdev_restore_flags(port->sf); free(port->type); free(port); diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c index 7ab9d3e3c..8b384ba3d 100644 --- a/lib/netdev-bsd.c +++ b/lib/netdev-bsd.c @@ -133,11 +133,11 @@ static int cache_notifier_refcount; static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); -static int netdev_bsd_do_ioctl(const struct netdev *, struct ifreq *, - unsigned long cmd, const char *cmd_name); +static int netdev_bsd_do_ioctl(const char *, struct ifreq *, unsigned long cmd, + const char *cmd_name); static void destroy_tap(int fd, const char *name); -static int get_flags(const struct netdev *, int *flagsp); -static int set_flags(struct netdev *, int flags); +static int get_flags(const struct netdev_dev *, int *flagsp); +static int set_flags(const char *, int flags); static int do_set_addr(struct netdev *netdev, int ioctl_nr, const char *ioctl_name, struct in_addr addr); @@ -813,7 +813,8 @@ netdev_bsd_get_mtu(const struct netdev *netdev_, int *mtup) struct ifreq ifr; int error; - error = netdev_bsd_do_ioctl(netdev_, &ifr, SIOCGIFMTU, "SIOCGIFMTU"); + error = netdev_bsd_do_ioctl(netdev_get_name(netdev_), &ifr, SIOCGIFMTU, + "SIOCGIFMTU"); if (error) { return error; } @@ -1089,7 +1090,7 @@ netdev_bsd_get_in4(const struct netdev *netdev_, struct in_addr *in4, int error; ifr.ifr_addr.sa_family = AF_INET; - error = netdev_bsd_do_ioctl(netdev_, &ifr, + error = netdev_bsd_do_ioctl(netdev_get_name(netdev_), &ifr, SIOCGIFADDR, "SIOCGIFADDR"); if (error) { return error; @@ -1098,7 +1099,7 @@ netdev_bsd_get_in4(const struct netdev *netdev_, struct in_addr *in4, sin = (struct sockaddr_in *) &ifr.ifr_addr; netdev_dev->in4 = sin->sin_addr; netdev_dev->cache_valid |= VALID_IN4; - error = netdev_bsd_do_ioctl(netdev_, &ifr, + error = netdev_bsd_do_ioctl(netdev_get_name(netdev_), &ifr, SIOCGIFNETMASK, "SIOCGIFNETMASK"); if (error) { return error; @@ -1221,19 +1222,21 @@ iff_to_nd_flags(int iff) } static int -netdev_bsd_update_flags(struct netdev *netdev, enum netdev_flags off, +netdev_bsd_update_flags(struct netdev_dev *dev_, enum netdev_flags off, enum netdev_flags on, enum netdev_flags *old_flagsp) { + struct netdev_dev_bsd *netdev_dev; int old_flags, new_flags; int error; - error = get_flags(netdev, &old_flags); + netdev_dev = netdev_dev_bsd_cast(dev_); + error = get_flags(dev_, &old_flags); if (!error) { *old_flagsp = iff_to_nd_flags(old_flags); new_flags = (old_flags & ~nd_to_iff_flags(off)) | nd_to_iff_flags(on); if (new_flags != old_flags) { - error = set_flags(netdev, new_flags); - netdev_dev_bsd_changed(netdev_dev_bsd_cast(netdev_get_dev(netdev))); + error = set_flags(netdev_dev_get_name(dev_), new_flags); + netdev_dev_bsd_changed(netdev_dev); } } return error; @@ -1381,12 +1384,12 @@ destroy_tap(int fd, const char *name) } static int -get_flags(const struct netdev *netdev, int *flags) +get_flags(const struct netdev_dev *dev, int *flags) { struct ifreq ifr; int error; - error = netdev_bsd_do_ioctl(netdev, &ifr, SIOCGIFFLAGS, "SIOCGIFFLAGS"); + error = netdev_bsd_do_ioctl(dev->name, &ifr, SIOCGIFFLAGS, "SIOCGIFFLAGS"); *flags = 0xFFFF0000 & (ifr.ifr_flagshigh << 16); *flags |= 0x0000FFFF & ifr.ifr_flags; @@ -1395,14 +1398,14 @@ get_flags(const struct netdev *netdev, int *flags) } static int -set_flags(struct netdev *netdev, int flags) +set_flags(const char *name, int flags) { struct ifreq ifr; ifr.ifr_flags = 0x0000FFFF & flags; ifr.ifr_flagshigh = (0xFFFF0000 & flags) >> 16; - return netdev_bsd_do_ioctl(netdev, &ifr, SIOCSIFFLAGS, "SIOCSIFFLAGS"); + return netdev_bsd_do_ioctl(name, &ifr, SIOCSIFFLAGS, "SIOCSIFFLAGS"); } static int @@ -1474,13 +1477,13 @@ set_etheraddr(const char *netdev_name, int hwaddr_family, } static int -netdev_bsd_do_ioctl(const struct netdev *netdev, struct ifreq *ifr, - unsigned long cmd, const char *cmd_name) +netdev_bsd_do_ioctl(const char *name, struct ifreq *ifr, unsigned long cmd, + const char *cmd_name) { - strncpy(ifr->ifr_name, netdev_get_name(netdev), sizeof ifr->ifr_name); + strncpy(ifr->ifr_name, name, sizeof ifr->ifr_name); if (ioctl(af_inet_sock, cmd, ifr) == -1) { - VLOG_DBG_RL(&rl, "%s: ioctl(%s) failed: %s", - netdev_get_name(netdev), cmd_name, strerror(errno)); + VLOG_DBG_RL(&rl, "%s: ioctl(%s) failed: %s", name, cmd_name, + strerror(errno)); return errno; } return 0; diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c index bdb3ea12e..de04f9a1d 100644 --- a/lib/netdev-dummy.c +++ b/lib/netdev-dummy.c @@ -316,12 +316,11 @@ netdev_dummy_get_ifindex(const struct netdev *netdev) } static int -netdev_dummy_update_flags(struct netdev *netdev, +netdev_dummy_update_flags(struct netdev_dev *dev_, enum netdev_flags off, enum netdev_flags on, enum netdev_flags *old_flagsp) { - struct netdev_dev_dummy *dev = - netdev_dev_dummy_cast(netdev_get_dev(netdev)); + struct netdev_dev_dummy *dev = netdev_dev_dummy_cast(dev_); return netdev_dev_dummy_update_flags(dev, off, on, old_flagsp); } diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 722b88be2..30cd0f639 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -422,7 +422,7 @@ static int netdev_linux_do_ioctl(const char *name, struct ifreq *, int cmd, static int netdev_linux_get_ipv4(const struct netdev *, struct in_addr *, int cmd, const char *cmd_name); static int get_flags(const struct netdev_dev *, unsigned int *flags); -static int set_flags(struct netdev *, unsigned int flags); +static int set_flags(const char *, unsigned int flags); static int do_get_ifindex(const char *netdev_name); static int get_ifindex(const struct netdev *, int *ifindexp); static int do_set_addr(struct netdev *netdev, @@ -1004,8 +1004,8 @@ netdev_linux_set_etheraddr(struct netdev *netdev_, { struct netdev_dev_linux *netdev_dev = netdev_dev_linux_cast(netdev_get_dev(netdev_)); + struct netdev_saved_flags *sf = NULL; int error; - bool up_again = false; if (netdev_dev->cache_valid & VALID_ETHERADDR) { if (netdev_dev->ether_addr_error) { @@ -1022,8 +1022,7 @@ netdev_linux_set_etheraddr(struct netdev *netdev_, enum netdev_flags flags; if (!netdev_get_flags(netdev_, &flags) && (flags & NETDEV_UP)) { - netdev_turn_flags_off(netdev_, NETDEV_UP, false); - up_again = true; + netdev_turn_flags_off(netdev_, NETDEV_UP, &sf); } } error = set_etheraddr(netdev_get_name(netdev_), mac); @@ -1035,9 +1034,7 @@ netdev_linux_set_etheraddr(struct netdev *netdev_, } } - if (up_again) { - netdev_turn_flags_on(netdev_, NETDEV_UP, false); - } + netdev_restore_flags(sf); return error; } @@ -2450,19 +2447,19 @@ iff_to_nd_flags(int iff) } static int -netdev_linux_update_flags(struct netdev *netdev, enum netdev_flags off, +netdev_linux_update_flags(struct netdev_dev *dev_, enum netdev_flags off, enum netdev_flags on, enum netdev_flags *old_flagsp) { struct netdev_dev_linux *netdev_dev; int old_flags, new_flags; int error = 0; - netdev_dev = netdev_dev_linux_cast(netdev_get_dev(netdev)); + netdev_dev = netdev_dev_linux_cast(dev_); old_flags = netdev_dev->ifi_flags; *old_flagsp = iff_to_nd_flags(old_flags); new_flags = (old_flags & ~nd_to_iff_flags(off)) | nd_to_iff_flags(on); if (new_flags != old_flags) { - error = set_flags(netdev, new_flags); + error = set_flags(netdev_dev_get_name(dev_), new_flags); get_flags(&netdev_dev->netdev_dev, &netdev_dev->ifi_flags); } return error; @@ -4481,13 +4478,12 @@ get_flags(const struct netdev_dev *dev, unsigned int *flags) } static int -set_flags(struct netdev *netdev, unsigned int flags) +set_flags(const char *name, unsigned int flags) { struct ifreq ifr; ifr.ifr_flags = flags; - return netdev_linux_do_ioctl(netdev_get_name(netdev), &ifr, SIOCSIFFLAGS, - "SIOCSIFFLAGS"); + return netdev_linux_do_ioctl(name, &ifr, SIOCSIFFLAGS, "SIOCSIFFLAGS"); } static int diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h index 9db950cf7..00799b110 100644 --- a/lib/netdev-provider.h +++ b/lib/netdev-provider.h @@ -38,6 +38,7 @@ struct netdev_dev { this device. */ int ref_cnt; /* Times this devices was opened. */ struct shash_node *node; /* Pointer to element in global map. */ + struct list saved_flags_list; /* Contains "struct netdev_saved_flags". */ }; void netdev_dev_init(struct netdev_dev *, const char *name, @@ -63,9 +64,6 @@ static inline void netdev_dev_assert_class(const struct netdev_dev *netdev_dev, struct netdev { struct netdev_dev *netdev_dev; /* Parent netdev_dev. */ struct list node; /* Element in global list. */ - - enum netdev_flags save_flags; /* Initial device flags. */ - enum netdev_flags changed_flags; /* Flags that we changed. */ }; void netdev_init(struct netdev *, struct netdev_dev *); @@ -572,14 +570,14 @@ struct netdev_class { int (*arp_lookup)(const struct netdev *netdev, ovs_be32 ip, uint8_t mac[6]); - /* Retrieves the current set of flags on 'netdev' into '*old_flags'. - * Then, turns off the flags that are set to 1 in 'off' and turns on the - * flags that are set to 1 in 'on'. (No bit will be set to 1 in both 'off' - * and 'on'; that is, off & on == 0.) + /* Retrieves the current set of flags on 'dev' into '*old_flags'. Then, + * turns off the flags that are set to 1 in 'off' and turns on the flags + * that are set to 1 in 'on'. (No bit will be set to 1 in both 'off' and + * 'on'; that is, off & on == 0.) * * This function may be invoked from a signal handler. Therefore, it * should not do anything that is not signal-safe (such as logging). */ - int (*update_flags)(struct netdev *netdev, enum netdev_flags off, + int (*update_flags)(struct netdev_dev *dev, enum netdev_flags off, enum netdev_flags on, enum netdev_flags *old_flags); /* Returns a sequence number which indicates changes in one of 'netdev''s diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index 1bcb34b07..07117314d 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -234,7 +234,7 @@ tunnel_get_status(const struct netdev *netdev, struct smap *smap) } static int -netdev_vport_update_flags(struct netdev *netdev OVS_UNUSED, +netdev_vport_update_flags(struct netdev_dev *netdev_dev OVS_UNUSED, enum netdev_flags off, enum netdev_flags on OVS_UNUSED, enum netdev_flags *old_flagsp) { diff --git a/lib/netdev.c b/lib/netdev.c index 434e2572e..415cdb4ae 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -48,6 +48,13 @@ COVERAGE_DEFINE(netdev_sent); COVERAGE_DEFINE(netdev_add_router); COVERAGE_DEFINE(netdev_get_stats); +struct netdev_saved_flags { + struct netdev_dev *dev; + struct list node; /* In struct netdev_dev's saved_flags_list. */ + enum netdev_flags saved_flags; + enum netdev_flags saved_values; +}; + static struct shash netdev_classes = SHASH_INITIALIZER(&netdev_classes); /* All created network devices. */ @@ -60,8 +67,7 @@ static struct list netdev_list = LIST_INITIALIZER(&netdev_list); * additional log messages. */ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); -static void close_all_netdevs(void *aux OVS_UNUSED); -static int restore_flags(struct netdev *netdev); +static void restore_all_flags(void *aux OVS_UNUSED); void update_device_args(struct netdev_dev *, const struct shash *args); static void @@ -72,7 +78,7 @@ netdev_initialize(void) if (!inited) { inited = true; - fatal_signal_add_hook(close_all_netdevs, NULL, NULL, true); + fatal_signal_add_hook(restore_all_flags, NULL, NULL, true); netdev_vport_patch_register(); #ifdef LINUX_DATAPATH @@ -302,21 +308,24 @@ netdev_get_tunnel_config(const struct netdev *netdev) } } +static void +netdev_dev_unref(struct netdev_dev *dev) +{ + ovs_assert(dev->ref_cnt); + if (!--dev->ref_cnt) { + netdev_dev_uninit(dev, true); + } +} + /* Closes and destroys 'netdev'. */ void netdev_close(struct netdev *netdev) { if (netdev) { - struct netdev_dev *netdev_dev = netdev_get_dev(netdev); + struct netdev_dev *dev = netdev_get_dev(netdev); - ovs_assert(netdev_dev->ref_cnt); - netdev_dev->ref_cnt--; netdev_uninit(netdev, true); - - /* If the reference count for the netdev device is zero, destroy it. */ - if (!netdev_dev->ref_cnt) { - netdev_dev_uninit(netdev_dev, true); - } + netdev_dev_unref(dev); } } @@ -791,37 +800,44 @@ netdev_get_in6(const struct netdev *netdev, struct in6_addr *in6) } /* On 'netdev', turns off the flags in 'off' and then turns on the flags in - * 'on'. If 'permanent' is true, the changes will persist; otherwise, they - * will be reverted when 'netdev' is closed or the program exits. Returns 0 if - * successful, otherwise a positive errno value. */ + * 'on'. Returns 0 if successful, otherwise a positive errno value. */ static int do_update_flags(struct netdev *netdev, enum netdev_flags off, enum netdev_flags on, enum netdev_flags *old_flagsp, - bool permanent) + struct netdev_saved_flags **sfp) { + struct netdev_dev *dev = netdev_get_dev(netdev); + struct netdev_saved_flags *sf = NULL; enum netdev_flags old_flags; int error; - error = netdev_get_dev(netdev)->netdev_class->update_flags(netdev, - off & ~on, on, &old_flags); + error = dev->netdev_class->update_flags(dev, off & ~on, on, &old_flags); if (error) { VLOG_WARN_RL(&rl, "failed to %s flags for network device %s: %s", off || on ? "set" : "get", netdev_get_name(netdev), strerror(error)); old_flags = 0; - } else if ((off || on) && !permanent) { + } else if ((off || on) && sfp) { enum netdev_flags new_flags = (old_flags & ~off) | on; enum netdev_flags changed_flags = old_flags ^ new_flags; if (changed_flags) { - if (!netdev->changed_flags) { - netdev->save_flags = old_flags; - } - netdev->changed_flags |= changed_flags; + *sfp = sf = xmalloc(sizeof *sf); + sf->dev = dev; + list_push_front(&dev->saved_flags_list, &sf->node); + sf->saved_flags = changed_flags; + sf->saved_values = changed_flags & new_flags; + + dev->ref_cnt++; } } + if (old_flagsp) { *old_flagsp = old_flags; } + if (sfp) { + *sfp = sf; + } + return error; } @@ -832,40 +848,63 @@ int netdev_get_flags(const struct netdev *netdev_, enum netdev_flags *flagsp) { struct netdev *netdev = CONST_CAST(struct netdev *, netdev_); - return do_update_flags(netdev, 0, 0, flagsp, false); + return do_update_flags(netdev, 0, 0, flagsp, NULL); } /* Sets the flags for 'netdev' to 'flags'. - * If 'permanent' is true, the changes will persist; otherwise, they - * will be reverted when 'netdev' is closed or the program exits. * Returns 0 if successful, otherwise a positive errno value. */ int netdev_set_flags(struct netdev *netdev, enum netdev_flags flags, - bool permanent) + struct netdev_saved_flags **sfp) { - return do_update_flags(netdev, -1, flags, NULL, permanent); + return do_update_flags(netdev, -1, flags, NULL, sfp); } -/* Turns on the specified 'flags' on 'netdev'. - * If 'permanent' is true, the changes will persist; otherwise, they - * will be reverted when 'netdev' is closed or the program exits. - * Returns 0 if successful, otherwise a positive errno value. */ +/* Turns on the specified 'flags' on 'netdev': + * + * - On success, returns 0. If 'sfp' is nonnull, sets '*sfp' to a newly + * allocated 'struct netdev_saved_flags *' that may be passed to + * netdev_restore_flags() to restore the original values of 'flags' on + * 'netdev' (this will happen automatically at program termination if + * netdev_restore_flags() is never called) , or to NULL if no flags were + * actually changed. + * + * - On failure, returns a positive errno value. If 'sfp' is nonnull, sets + * '*sfp' to NULL. */ int netdev_turn_flags_on(struct netdev *netdev, enum netdev_flags flags, - bool permanent) + struct netdev_saved_flags **sfp) { - return do_update_flags(netdev, 0, flags, NULL, permanent); + return do_update_flags(netdev, 0, flags, NULL, sfp); } -/* Turns off the specified 'flags' on 'netdev'. - * If 'permanent' is true, the changes will persist; otherwise, they - * will be reverted when 'netdev' is closed or the program exits. - * Returns 0 if successful, otherwise a positive errno value. */ +/* Turns off the specified 'flags' on 'netdev'. See netdev_turn_flags_on() for + * details of the interface. */ int netdev_turn_flags_off(struct netdev *netdev, enum netdev_flags flags, - bool permanent) + struct netdev_saved_flags **sfp) +{ + return do_update_flags(netdev, flags, 0, NULL, sfp); +} + +/* Restores the flags that were saved in 'sf', and destroys 'sf'. + * Does nothing if 'sf' is NULL. */ +void +netdev_restore_flags(struct netdev_saved_flags *sf) { - return do_update_flags(netdev, flags, 0, NULL, permanent); + if (sf) { + struct netdev_dev *dev = sf->dev; + enum netdev_flags old_flags; + + dev->netdev_class->update_flags(dev, + sf->saved_flags & sf->saved_values, + sf->saved_flags & ~sf->saved_values, + &old_flags); + list_remove(&sf->node); + free(sf); + + netdev_dev_unref(dev); + } } /* Looks up the ARP table entry for 'ip' on 'netdev'. If one exists and can be @@ -1293,6 +1332,7 @@ netdev_dev_init(struct netdev_dev *netdev_dev, const char *name, netdev_dev->netdev_class = netdev_class; netdev_dev->name = xstrdup(name); netdev_dev->node = shash_add(&netdev_dev_shash, name, netdev_dev); + list_init(&netdev_dev->saved_flags_list); } /* Undoes the results of initialization. @@ -1308,6 +1348,7 @@ netdev_dev_uninit(struct netdev_dev *netdev_dev, bool destroy) char *name = netdev_dev->name; ovs_assert(!netdev_dev->ref_cnt); + ovs_assert(list_is_empty(&netdev_dev->saved_flags_list)); shash_delete(&netdev_dev_shash, netdev_dev->node); @@ -1390,20 +1431,12 @@ netdev_init(struct netdev *netdev, struct netdev_dev *netdev_dev) void netdev_uninit(struct netdev *netdev, bool close) { - /* Restore flags that we changed, if any. */ - int error = restore_flags(netdev); list_remove(&netdev->node); - if (error) { - VLOG_WARN("failed to restore network device flags on %s: %s", - netdev_get_name(netdev), strerror(error)); - } - if (close) { netdev_get_dev(netdev)->netdev_class->close(netdev); } } - /* Returns the class type of 'netdev'. * * The caller must not free the returned value. */ @@ -1413,7 +1446,6 @@ netdev_get_type(const struct netdev *netdev) return netdev_get_dev(netdev)->netdev_class->type; } - const char * netdev_get_type_from_name(const char *name) { @@ -1427,31 +1459,32 @@ netdev_get_dev(const struct netdev *netdev) return netdev->netdev_dev; } -/* Restore the network device flags on 'netdev' to those that were active - * before we changed them. Returns 0 if successful, otherwise a positive - * errno value. - * - * To avoid reentry, the caller must ensure that fatal signals are blocked. */ -static int -restore_flags(struct netdev *netdev) -{ - if (netdev->changed_flags) { - enum netdev_flags restore = netdev->save_flags & netdev->changed_flags; - enum netdev_flags old_flags; - return netdev_get_dev(netdev)->netdev_class->update_flags(netdev, - netdev->changed_flags & ~restore, - restore, &old_flags); - } - return 0; -} - -/* Close all netdevs on shutdown so they can do any needed cleanup such as - * destroying devices, restoring flags, etc. */ +/* Restores all flags that have been saved with netdev_save_flags() and not yet + * restored with netdev_restore_flags(). */ static void -close_all_netdevs(void *aux OVS_UNUSED) +restore_all_flags(void *aux OVS_UNUSED) { - struct netdev *netdev, *next; - LIST_FOR_EACH_SAFE(netdev, next, node, &netdev_list) { - netdev_close(netdev); + struct shash_node *node; + + SHASH_FOR_EACH (node, &netdev_dev_shash) { + struct netdev_dev *dev = node->data; + const struct netdev_saved_flags *sf; + enum netdev_flags saved_values; + enum netdev_flags saved_flags; + + saved_values = saved_flags = 0; + LIST_FOR_EACH (sf, node, &dev->saved_flags_list) { + saved_flags |= sf->saved_flags; + saved_values &= ~sf->saved_flags; + saved_values |= sf->saved_flags & sf->saved_values; + } + if (saved_flags) { + enum netdev_flags old_flags; + + dev->netdev_class->update_flags(dev, + saved_flags & saved_values, + saved_flags & ~saved_values, + &old_flags); + } } } diff --git a/lib/netdev.h b/lib/netdev.h index 8e87ae49b..86924aaad 100644 --- a/lib/netdev.h +++ b/lib/netdev.h @@ -33,18 +33,13 @@ extern "C" { * The PORTING file at the top of the source tree has more information in the * "Writing a netdev Provider" section. */ +struct netdev_saved_flags; struct ofpbuf; struct in_addr; struct in6_addr; struct smap; struct sset; -enum netdev_flags { - NETDEV_UP = 0x0001, /* Device enabled? */ - NETDEV_PROMISC = 0x0002, /* Promiscuous mode? */ - NETDEV_LOOPBACK = 0x0004 /* This is a loopback device. */ -}; - /* Network device statistics. * * Values of unsupported statistics are set to all-1-bits (UINT64_MAX). */ @@ -180,6 +175,23 @@ uint64_t netdev_features_to_bps(enum netdev_features features, bool netdev_features_is_full_duplex(enum netdev_features features); int netdev_set_advertisements(struct netdev *, enum netdev_features advertise); +/* Flags. */ +enum netdev_flags { + NETDEV_UP = 0x0001, /* Device enabled? */ + NETDEV_PROMISC = 0x0002, /* Promiscuous mode? */ + NETDEV_LOOPBACK = 0x0004 /* This is a loopback device. */ +}; + +int netdev_get_flags(const struct netdev *, enum netdev_flags *); +int netdev_set_flags(struct netdev *, enum netdev_flags, + struct netdev_saved_flags **); +int netdev_turn_flags_on(struct netdev *, enum netdev_flags, + struct netdev_saved_flags **); +int netdev_turn_flags_off(struct netdev *, enum netdev_flags, + struct netdev_saved_flags **); + +void netdev_restore_flags(struct netdev_saved_flags *); + /* TCP/IP stack interface. */ int netdev_get_in4(const struct netdev *, struct in_addr *address, struct in_addr *netmask); @@ -192,10 +204,6 @@ int netdev_get_next_hop(const struct netdev *, const struct in_addr *host, int netdev_get_status(const struct netdev *, struct smap *); int netdev_arp_lookup(const struct netdev *, ovs_be32 ip, uint8_t mac[6]); -int netdev_get_flags(const struct netdev *, enum netdev_flags *); -int netdev_set_flags(struct netdev *, enum netdev_flags, bool permanent); -int netdev_turn_flags_on(struct netdev *, enum netdev_flags, bool permanent); -int netdev_turn_flags_off(struct netdev *, enum netdev_flags, bool permanent); struct netdev *netdev_find_dev_by_in4(const struct in_addr *); /* Statistics. */ diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 262493e66..28df181b9 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -2398,9 +2398,9 @@ update_port_config(struct ofport *port, toggle = (config ^ port->pp.config) & mask; if (toggle & OFPUTIL_PC_PORT_DOWN) { if (config & OFPUTIL_PC_PORT_DOWN) { - netdev_turn_flags_off(port->netdev, NETDEV_UP, true); + netdev_turn_flags_off(port->netdev, NETDEV_UP, NULL); } else { - netdev_turn_flags_on(port->netdev, NETDEV_UP, true); + netdev_turn_flags_on(port->netdev, NETDEV_UP, NULL); } toggle &= ~OFPUTIL_PC_PORT_DOWN; } diff --git a/utilities/ovs-dpctl.c b/utilities/ovs-dpctl.c index 2f9574f00..54505e85a 100644 --- a/utilities/ovs-dpctl.c +++ b/utilities/ovs-dpctl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc. + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -214,7 +214,7 @@ static int if_up(const char *netdev_name) retval = netdev_open(netdev_name, "system", &netdev); if (!retval) { - retval = netdev_turn_flags_on(netdev, NETDEV_UP, true); + retval = netdev_turn_flags_on(netdev, NETDEV_UP, NULL); netdev_close(netdev); } return retval; diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index d1dfdc217..cf26e8761 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -1449,7 +1449,7 @@ iface_do_create(const struct bridge *br, if ((port_cfg->vlan_mode && !strcmp(port_cfg->vlan_mode, "splinter")) || iface_is_internal(iface_cfg, br->cfg)) { - netdev_turn_flags_on(netdev, NETDEV_UP, true); + netdev_turn_flags_on(netdev, NETDEV_UP, NULL); } *netdevp = netdev; @@ -2892,7 +2892,7 @@ bridge_configure_local_iface_netdev(struct bridge *br, /* Bring up the local interface. */ netdev = local_iface->netdev; - netdev_turn_flags_on(netdev, NETDEV_UP, true); + netdev_turn_flags_on(netdev, NETDEV_UP, NULL); /* Configure the IP address and netmask. */ if (!c->local_netmask -- 2.43.0