From ac4d3bcb46fa0acd0b63f79449432df28569f74f Mon Sep 17 00:00:00 2001 From: Ethan Jackson Date: Thu, 26 May 2011 14:28:11 -0700 Subject: [PATCH] netdev: New Function netdev_change_seq(). This new function will provide a much simpler replacement for netdev_monitor in the future. --- lib/netdev-dummy.c | 16 ++++++++++++++++ lib/netdev-linux.c | 26 +++++++++++++++++++++++--- lib/netdev-provider.h | 16 +++++++++++++++- lib/netdev-vport.c | 19 ++++++++++++++++++- lib/netdev.c | 13 +++++++++++++ lib/netdev.h | 2 ++ lib/rtnetlink-link.c | 4 ++-- 7 files changed, 89 insertions(+), 7 deletions(-) diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c index 4094f7577..ea1c5fa3a 100644 --- a/lib/netdev-dummy.c +++ b/lib/netdev-dummy.c @@ -40,6 +40,7 @@ struct netdev_dev_dummy { int mtu; struct netdev_stats stats; enum netdev_flags flags; + unsigned int change_seq; }; struct netdev_dummy { @@ -92,6 +93,7 @@ netdev_dummy_create(const struct netdev_class *class, const char *name, netdev_dev->hwaddr[5] = n; netdev_dev->mtu = 1500; netdev_dev->flags = 0; + netdev_dev->change_seq = 1; n++; @@ -250,6 +252,12 @@ netdev_dummy_poll_remove(struct netdev_notifier *notifier_) free(notifier); } + +static unsigned int +netdev_dummy_change_seq(const struct netdev *netdev) +{ + return netdev_dev_dummy_cast(netdev_get_dev(netdev))->change_seq; +} /* Helper functions. */ @@ -258,6 +266,8 @@ netdev_dummy_poll_notify(const struct netdev *netdev) { const char *name = netdev_get_name(netdev); struct list *list = shash_find_data(&netdev_dummy_notifiers, name); + struct netdev_dev_dummy *dev = + netdev_dev_dummy_cast(netdev_get_dev(netdev)); if (list) { struct netdev_dummy_notifier *notifier; @@ -267,6 +277,11 @@ netdev_dummy_poll_notify(const struct netdev *netdev) n->cb(n); } } + + dev->change_seq++; + if (!dev->change_seq) { + dev->change_seq++; + } } static const struct netdev_class dummy_class = { @@ -328,6 +343,7 @@ static const struct netdev_class dummy_class = { netdev_dummy_poll_add, netdev_dummy_poll_remove, + netdev_dummy_change_seq }; void diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index b5d303523..eda127603 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -346,6 +346,7 @@ struct netdev_dev_linux { struct shash_node *shash_node; unsigned int cache_valid; + unsigned int change_seq; bool miimon; /* Link status of last poll. */ long long int miimon_interval; /* Miimon Poll rate. Disabled if <= 0. */ @@ -483,6 +484,16 @@ netdev_linux_wait(void) netdev_linux_miimon_wait(); } +static void +netdev_dev_linux_changed(struct netdev_dev_linux *dev) +{ + dev->change_seq++; + if (!dev->change_seq) { + dev->change_seq++; + } + dev->cache_valid = 0; +} + static void netdev_linux_cache_cb(const struct rtnetlink_link_change *change, void *aux OVS_UNUSED) @@ -496,7 +507,7 @@ netdev_linux_cache_cb(const struct rtnetlink_link_change *change, if (is_netdev_linux_class(netdev_class)) { dev = netdev_dev_linux_cast(base_dev); - dev->cache_valid = 0; + netdev_dev_linux_changed(dev); } } } else { @@ -507,7 +518,7 @@ netdev_linux_cache_cb(const struct rtnetlink_link_change *change, netdev_dev_get_devices(&netdev_linux_class, &device_shash); SHASH_FOR_EACH (node, &device_shash) { dev = node->data; - dev->cache_valid = 0; + netdev_dev_linux_changed(dev); } shash_destroy(&device_shash); } @@ -537,6 +548,7 @@ netdev_linux_create(const struct netdev_class *class, cache_notifier_refcount++; netdev_dev = xzalloc(sizeof *netdev_dev); + netdev_dev->change_seq = 1; netdev_dev_init(&netdev_dev->netdev_dev, name, args, class); *netdev_devp = &netdev_dev->netdev_dev; @@ -1169,6 +1181,7 @@ netdev_linux_miimon_run(void) if (list) { poll_notify(list); } + netdev_dev_linux_changed(dev); } timer_set_duration(&dev->miimon_timer, dev->miimon_interval); @@ -2318,6 +2331,12 @@ netdev_linux_poll_remove(struct netdev_notifier *notifier_) } } +static unsigned int +netdev_linux_change_seq(const struct netdev *netdev) +{ + return netdev_dev_linux_cast(netdev_get_dev(netdev))->change_seq; +} + #define NETDEV_LINUX_CLASS(NAME, CREATE, ENUMERATE, SET_STATS) \ { \ NAME, \ @@ -2378,7 +2397,8 @@ netdev_linux_poll_remove(struct netdev_notifier *notifier_) netdev_linux_update_flags, \ \ netdev_linux_poll_add, \ - netdev_linux_poll_remove \ + netdev_linux_poll_remove, \ + netdev_linux_change_seq \ } const struct netdev_class netdev_linux_class = diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h index 23de420f4..8ed3bf37a 100644 --- a/lib/netdev-provider.h +++ b/lib/netdev-provider.h @@ -121,7 +121,10 @@ struct netdev_class { void (*run)(void); /* Arranges for poll_block() to wake up if the "run" member function needs - * to be called. May be null if nothing is needed here. */ + * to be called. Implementations are additionally required to wake + * whenever something changes in any of its netdevs which would cause their + * ->change_seq() function to change its result. May be null if nothing is + * needed here. */ void (*wait)(void); /* Attempts to create a network device named 'name' with initial 'args' in @@ -572,6 +575,17 @@ struct netdev_class { /* Cancels poll notification for 'notifier'. */ void (*poll_remove)(struct netdev_notifier *notifier); + + /* Returns a sequence number which indicates changes in one of 'netdev''s + * properties. The returned sequence number must be nonzero so that + * callers have a value which they may use as a reset when tracking + * 'netdev'. + * + * Minimally, the returned sequence number is required to change whenever + * 'netdev''s flags, features, ethernet address, or carrier changes. The + * returned sequence number is allowed to change even when 'netdev' doesn't + * change, although implementations should try to avoid this. */ + unsigned int (*change_seq)(const struct netdev *netdev); }; int netdev_register_provider(const struct netdev_class *); diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index 306732367..ec67aaaae 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -59,6 +59,7 @@ struct netdev_dev_vport { struct ofpbuf *options; int dp_ifindex; /* -1 if unknown. */ uint32_t port_no; /* UINT32_MAX if unknown. */ + unsigned int change_seq; }; struct netdev_vport { @@ -242,6 +243,7 @@ netdev_vport_create(const struct netdev_class *netdev_class, const char *name, dev->options = options; dev->dp_ifindex = dp_ifindex; dev->port_no = port_no; + dev->change_seq = 1; *netdev_devp = &dev->netdev_dev; route_table_register(); @@ -538,6 +540,12 @@ netdev_vport_poll_remove(struct netdev_notifier *notifier_) free(notifier); } +static unsigned int +netdev_vport_change_seq(const struct netdev *netdev) +{ + return netdev_dev_vport_cast(netdev_get_dev(netdev))->change_seq; +} + static void netdev_vport_run(void) { @@ -581,6 +589,9 @@ netdev_vport_poll_notify(const struct netdev *netdev) char *poll_name = make_poll_name(netdev); struct list *list = shash_find_data(&netdev_vport_notifiers, poll_name); + struct netdev_dev_vport *ndv; + + ndv = netdev_dev_vport_cast(netdev_get_dev(netdev)); if (list) { struct netdev_vport_notifier *notifier; @@ -591,6 +602,11 @@ netdev_vport_poll_notify(const struct netdev *netdev) } } + ndv->change_seq++; + if (!ndv->change_seq) { + ndv->change_seq++; + } + free(poll_name); } @@ -986,7 +1002,8 @@ unparse_patch_config(const char *name OVS_UNUSED, const char *type OVS_UNUSED, netdev_vport_update_flags, \ \ netdev_vport_poll_add, \ - netdev_vport_poll_remove, + netdev_vport_poll_remove, \ + netdev_vport_change_seq void netdev_vport_register(void) diff --git a/lib/netdev.c b/lib/netdev.c index 27ef0c350..d77f2f25e 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -1223,6 +1223,19 @@ netdev_dump_queue_stats(const struct netdev *netdev, : EOPNOTSUPP); } +/* Returns a sequence number which indicates changes in one of 'netdev''s + * properties. The returned sequence will be nonzero so that callers have a + * value which they may use as a reset when tracking 'netdev'. + * + * The returned sequence number will change whenever 'netdev''s flags, + * features, ethernet address, or carrier changes. It may change for other + * reasons as well, or no reason at all. */ +unsigned int +netdev_change_seq(const struct netdev *netdev) +{ + return netdev_get_dev(netdev)->netdev_class->change_seq(netdev); +} + /* If 'netdev' is a VLAN network device (e.g. one created with vconfig(8)), * sets '*vlan_vid' to the VLAN VID associated with that device and returns 0. * Otherwise returns a errno value (specifically ENOENT if 'netdev_name' is the diff --git a/lib/netdev.h b/lib/netdev.h index cc81e6cac..547d3e7eb 100644 --- a/lib/netdev.h +++ b/lib/netdev.h @@ -205,6 +205,8 @@ typedef void netdev_dump_queue_stats_cb(unsigned int queue_id, int netdev_dump_queue_stats(const struct netdev *, netdev_dump_queue_stats_cb *, void *aux); +unsigned int netdev_change_seq(const struct netdev *netdev); + /* Linux stuff. */ int netdev_get_vlan_vid(const struct netdev *, int *vlan_vid); diff --git a/lib/rtnetlink-link.c b/lib/rtnetlink-link.c index ad83a1d27..09ba954ed 100644 --- a/lib/rtnetlink-link.c +++ b/lib/rtnetlink-link.c @@ -76,8 +76,8 @@ rtnetlink_link_parse(struct ofpbuf *buf, * caller must not modify or free. * * This is probably not the function that you want. You should probably be - * using dpif_port_poll() or netdev_monitor_create(), which unlike this - * function are not Linux-specific. + * using dpif_port_poll() or netdev_change_seq(), which unlike this function + * are not Linux-specific. * * Returns 0 if successful, otherwise a positive errno value. */ int -- 2.43.0