From c37d4da4f0fd0190ea8fef97399df6d27ebf6ee2 Mon Sep 17 00:00:00 2001 From: Ethan Jackson Date: Mon, 13 Feb 2012 18:07:44 -0800 Subject: [PATCH] netdev-linux: Cache flags using netlink. Before this patch, every request for a 'netdev_dev''s flags required an ioctl call. This occurred every time netdev_get_carrier() was called, which theoretically was very often if there were a large number of devices. We were already using netlink to keep track of the IFF_RUNNING flag. This patch generalizes the code to keep track of all flags using the same netlink code. Signed-off-by: Ethan Jackson --- lib/netdev-linux.c | 35 ++++++++++++++++------------------- lib/rtnetlink-link.c | 2 +- lib/rtnetlink-link.h | 2 +- 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 2585e576b..16e1c35ef 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -368,7 +368,7 @@ struct netdev_dev_linux { struct in_addr address, netmask; struct in6_addr in6; int mtu; - bool carrier; + int ifi_flags; long long int carrier_resets; uint32_t kbits_rate; /* Policing data. */ uint32_t kbits_burst; @@ -506,10 +506,10 @@ netdev_linux_cache_cb(const struct rtnetlink_link_change *change, if (is_netdev_linux_class(netdev_class)) { dev = netdev_dev_linux_cast(base_dev); - if (dev->carrier != change->running) { - dev->carrier = change->running; + if ((dev->ifi_flags ^ change->ifi_flags) & IFF_RUNNING) { dev->carrier_resets++; } + dev->ifi_flags = change->ifi_flags; netdev_dev_linux_changed(dev); } @@ -521,17 +521,15 @@ netdev_linux_cache_cb(const struct rtnetlink_link_change *change, shash_init(&device_shash); netdev_dev_get_devices(&netdev_linux_class, &device_shash); SHASH_FOR_EACH (node, &device_shash) { - bool carrier; int flags; dev = node->data; get_flags(&dev->netdev_dev, &flags); - carrier = (flags & IFF_RUNNING) != 0; - if (dev->carrier != carrier) { - dev->carrier = carrier; + if ((dev->ifi_flags ^ flags) & IFF_RUNNING) { dev->carrier_resets++; } + dev->ifi_flags = flags; netdev_dev_linux_changed(dev); } @@ -575,7 +573,6 @@ netdev_linux_create(const struct netdev_class *class, const char *name, { struct netdev_dev_linux *netdev_dev; int error; - int flags; error = cache_notifier_ref(); if (error) { @@ -585,8 +582,7 @@ netdev_linux_create(const struct netdev_class *class, const char *name, netdev_dev = xzalloc(sizeof *netdev_dev); netdev_dev->change_seq = 1; netdev_dev_init(&netdev_dev->netdev_dev, name, class); - get_flags(&netdev_dev->netdev_dev, &flags); - netdev_dev->carrier = (flags & IFF_RUNNING) != 0; + get_flags(&netdev_dev->netdev_dev, &netdev_dev->ifi_flags); *netdev_devp = &netdev_dev->netdev_dev; return 0; @@ -1069,7 +1065,7 @@ netdev_linux_get_carrier(const struct netdev *netdev_, bool *carrier) if (netdev_dev->miimon_interval > 0) { *carrier = netdev_dev->miimon; } else { - *carrier = netdev_dev->carrier; + *carrier = (netdev_dev->ifi_flags & IFF_RUNNING) != 0; } return 0; @@ -2216,16 +2212,17 @@ static int netdev_linux_update_flags(struct netdev *netdev, 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; + int error = 0; - error = get_flags(netdev_get_dev(netdev), &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 = netdev_dev_linux_cast(netdev_get_dev(netdev)); + 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); + get_flags(&netdev_dev->netdev_dev, &netdev_dev->ifi_flags); } return error; } diff --git a/lib/rtnetlink-link.c b/lib/rtnetlink-link.c index 7d26d8668..60b71be86 100644 --- a/lib/rtnetlink-link.c +++ b/lib/rtnetlink-link.c @@ -63,7 +63,7 @@ rtnetlink_link_parse(struct ofpbuf *buf, change->nlmsg_type = nlmsg->nlmsg_type; change->ifi_index = ifinfo->ifi_index; change->ifname = nl_attr_get_string(attrs[IFLA_IFNAME]); - change->running = ifinfo->ifi_flags & IFF_RUNNING; + change->ifi_flags = ifinfo->ifi_flags; change->master_ifindex = (attrs[IFLA_MASTER] ? nl_attr_get_u32(attrs[IFLA_MASTER]) : 0); diff --git a/lib/rtnetlink-link.h b/lib/rtnetlink-link.h index 24a772863..b6ddb2149 100644 --- a/lib/rtnetlink-link.h +++ b/lib/rtnetlink-link.h @@ -37,7 +37,7 @@ struct rtnetlink_link_change { /* Extracted from Netlink attributes. */ const char *ifname; /* Name of network device. */ int master_ifindex; /* Ifindex of datapath master (0 if none). */ - bool running; /* Carrier of network device. */ + unsigned int ifi_flags; /* Flags of network device. */ }; /* Function called to report that a netdev has changed. 'change' describes the -- 2.43.0