netdev linux devices uses mtu ioctl to get and set MTU for a device. By caching error code from ioctl we can reduce number of ioctl calls for device which is unregistered from system. netdev notification is used to update mtu which saves get-mtu-ioctl.
Signed-off-by: Pravin B Shelar <pshe...@nicira.com> --- lib/netdev-linux.c | 80 ++++++++++++++++++++++++++++++++------------------ lib/netdev.c | 4 +- lib/rtnetlink-link.c | 5 +++ lib/rtnetlink-link.h | 1 + 4 files changed, 59 insertions(+), 31 deletions(-) diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index f1f7beb..3067953 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -377,6 +377,8 @@ struct netdev_dev_linux { uint32_t kbits_burst; int vport_stats_error; /* Cached error code from vport_get_stats(). 0 or an errno value. */ + int netdev_mtu_error; /* Cached error code from SIOCGIFMTU or SIOCSIFMTU. */ + struct ethtool_drvinfo drvinfo; /* Cached from ETHTOOL_GDRVINFO. */ struct tc *tc; @@ -510,27 +512,31 @@ netdev_linux_get_drvinfo(struct netdev_dev_linux *netdev_dev) static void netdev_dev_linux_changed(struct netdev_dev_linux *dev, - unsigned int ifi_flags, - uint16_t change) + const struct rtnetlink_link_change *change) { dev->change_seq++; if (!dev->change_seq) { dev->change_seq++; } - if ((dev->ifi_flags ^ ifi_flags) & IFF_RUNNING) { + if ((dev->ifi_flags ^ change->ifi_flags) & IFF_RUNNING) { dev->carrier_resets++; } - dev->ifi_flags = ifi_flags; + dev->ifi_flags = change->ifi_flags; /* Always cache driver-info. */ dev->cache_valid &= VALID_DRVINFO; - if (change == RTM_NEWLINK) { + if (change->nlmsg_type == RTM_NEWLINK) { /* Required for internal devices. */ netdev_linux_get_drvinfo(dev); } + if (change->nlmsg_type != RTM_DELLINK) { + dev->mtu = change->mtu; + dev->netdev_mtu_error = 0; + dev->cache_valid |= VALID_MTU; + } } static void @@ -546,12 +552,15 @@ netdev_linux_cache_cb(const struct rtnetlink_link_change *change, if (is_netdev_linux_class(netdev_class)) { dev = netdev_dev_linux_cast(base_dev); - netdev_dev_linux_changed(dev, change->ifi_flags, change->nlmsg_type); + netdev_dev_linux_changed(dev, change); } } } else { struct shash device_shash; struct shash_node *node; + struct rtnetlink_link_change dev_change; + + memset(&dev_change, 0, sizeof(dev_change)); shash_init(&device_shash); netdev_dev_get_devices(&netdev_linux_class, &device_shash); @@ -561,7 +570,8 @@ netdev_linux_cache_cb(const struct rtnetlink_link_change *change, dev = node->data; get_flags(&dev->netdev_dev, &flags); - netdev_dev_linux_changed(dev, flags, 0); + dev_change.ifi_flags = flags; + netdev_dev_linux_changed(dev, &dev_change); } shash_destroy(&device_shash); } @@ -1055,20 +1065,25 @@ netdev_linux_get_mtu(const struct netdev *netdev_, int *mtup) { struct netdev_dev_linux *netdev_dev = netdev_dev_linux_cast(netdev_get_dev(netdev_)); - if (!(netdev_dev->cache_valid & VALID_MTU)) { - struct ifreq ifr; - int error; + struct ifreq ifr; + int error; - error = netdev_linux_do_ioctl(netdev_get_name(netdev_), &ifr, - SIOCGIFMTU, "SIOCGIFMTU"); - if (error) { - return error; - } - netdev_dev->mtu = ifr.ifr_mtu; - netdev_dev->cache_valid |= VALID_MTU; + if (netdev_dev->cache_valid & VALID_MTU) { + goto out; } - *mtup = netdev_dev->mtu; - return 0; + + error = netdev_linux_do_ioctl(netdev_get_name(netdev_), &ifr, + SIOCGIFMTU, "SIOCGIFMTU"); + + netdev_dev->netdev_mtu_error = error; + netdev_dev->cache_valid |= VALID_MTU; + netdev_dev->mtu = ifr.ifr_mtu; + +out: + if (!netdev_dev->netdev_mtu_error) { + *mtup = netdev_dev->mtu; + } + return netdev_dev->netdev_mtu_error; } /* Sets the maximum size of transmitted (MTU) for given device using linux @@ -1082,20 +1097,23 @@ netdev_linux_set_mtu(const struct netdev *netdev_, int mtu) struct ifreq ifr; int error; - if (netdev_dev->cache_valid & VALID_MTU && - netdev_dev->mtu == mtu) { - return 0; + if (netdev_dev->cache_valid & VALID_MTU) { + if (netdev_dev->netdev_mtu_error) { + goto out; + } + if (netdev_dev->mtu == mtu) { + goto out; + } } ifr.ifr_mtu = mtu; error = netdev_linux_do_ioctl(netdev_get_name(netdev_), &ifr, SIOCSIFMTU, "SIOCSIFMTU"); - if (error) { - return error; - } - - netdev_dev->mtu = ifr.ifr_mtu; + netdev_dev->netdev_mtu_error = error; netdev_dev->cache_valid |= VALID_MTU; - return 0; + netdev_dev->mtu = ifr.ifr_mtu; + +out: + return netdev_dev->netdev_mtu_error; } /* Returns the ifindex of 'netdev', if successful, as a positive number. @@ -1210,8 +1228,10 @@ netdev_linux_miimon_run(void) { struct shash device_shash; struct shash_node *node; + struct rtnetlink_link_change dev_change; shash_init(&device_shash); + memset(&dev_change, 0, sizeof(dev_change)); netdev_dev_get_devices(&netdev_linux_class, &device_shash); SHASH_FOR_EACH (node, &device_shash) { struct netdev_dev_linux *dev = node->data; @@ -1223,8 +1243,10 @@ netdev_linux_miimon_run(void) netdev_linux_get_miimon(dev->netdev_dev.name, &miimon); if (miimon != dev->miimon) { + dev->miimon = miimon; - netdev_dev_linux_changed(dev, dev->ifi_flags, 0); + dev_change.ifi_flags = dev->ifi_flags; + netdev_dev_linux_changed(dev, &dev_change); } timer_set_duration(&dev->miimon_timer, dev->miimon_interval); diff --git a/lib/netdev.c b/lib/netdev.c index 64dfda5..33ef39f 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -516,7 +516,7 @@ netdev_get_mtu(const struct netdev *netdev, int *mtup) if (error) { *mtup = 0; if (error != EOPNOTSUPP) { - VLOG_WARN_RL(&rl, "failed to retrieve MTU for network device %s: " + VLOG_DBG_RL(&rl, "failed to retrieve MTU for network device %s: " "%s", netdev_get_name(netdev), strerror(error)); } } @@ -537,7 +537,7 @@ netdev_set_mtu(const struct netdev *netdev, int mtu) error = class->set_mtu ? class->set_mtu(netdev, mtu) : EOPNOTSUPP; if (error && error != EOPNOTSUPP) { - VLOG_WARN_RL(&rl, "failed to set MTU for network device %s: %s", + VLOG_DBG_RL(&rl, "failed to set MTU for network device %s: %s", netdev_get_name(netdev), strerror(error)); } diff --git a/lib/rtnetlink-link.c b/lib/rtnetlink-link.c index 60b71be..d14f0e3 100644 --- a/lib/rtnetlink-link.c +++ b/lib/rtnetlink-link.c @@ -45,6 +45,7 @@ rtnetlink_link_parse(struct ofpbuf *buf, static const struct nl_policy policy[] = { [IFLA_IFNAME] = { .type = NL_A_STRING, .optional = false }, [IFLA_MASTER] = { .type = NL_A_U32, .optional = true }, + [IFLA_MTU] = { .type = NL_A_U32, .optional = true }, }; static struct nlattr *attrs[ARRAY_SIZE(policy)]; @@ -67,6 +68,10 @@ rtnetlink_link_parse(struct ofpbuf *buf, change->master_ifindex = (attrs[IFLA_MASTER] ? nl_attr_get_u32(attrs[IFLA_MASTER]) : 0); + change->mtu = (attrs[IFLA_MTU] + ? nl_attr_get_u32(attrs[IFLA_MTU]) + : 0); + } return parsed; diff --git a/lib/rtnetlink-link.h b/lib/rtnetlink-link.h index b6ddb21..cfdb24b 100644 --- a/lib/rtnetlink-link.h +++ b/lib/rtnetlink-link.h @@ -37,6 +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). */ + int mtu; /* Current MTU. */ unsigned int ifi_flags; /* Flags of network device. */ }; -- 1.7.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev