netdev-linux: Cache error code from mtu ioctl.
authorPravin B Shelar <pshelar@nicira.com>
Fri, 9 Mar 2012 20:57:48 +0000 (12:57 -0800)
committerPravin B Shelar <pshelar@nicira.com>
Fri, 9 Mar 2012 20:57:48 +0000 (12:57 -0800)
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 <pshelar@nicira.com>
lib/netdev-linux.c
lib/netdev.c
lib/rtnetlink-link.c
lib/rtnetlink-link.h

index 87c8832d22f6ddb0b841b937c27f78283996d97b..7c510acf4fa477a97d29a5ae8078f9897a90423d 100644 (file)
@@ -376,6 +376,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;
 
@@ -532,6 +534,13 @@ netdev_dev_linux_update(struct netdev_dev_linux *dev,
     if (change->nlmsg_type == RTM_NEWLINK) {
         /* Keep drv-info */
         netdev_dev_linux_changed(dev, change->ifi_flags, VALID_DRVINFO);
+
+        if (change->mtu) {
+            dev->mtu = change->mtu;
+            dev->cache_valid |= VALID_MTU;
+            dev->netdev_mtu_error = 0;
+        }
+
     } else {
         netdev_dev_linux_changed(dev, change->ifi_flags, 0);
     }
@@ -1046,14 +1055,16 @@ netdev_linux_get_mtu(const struct netdev *netdev_, int *mtup)
 
         error = netdev_linux_do_ioctl(netdev_get_name(netdev_), &ifr,
                                       SIOCGIFMTU, "SIOCGIFMTU");
-        if (error) {
-            return error;
-        }
+
+        netdev_dev->netdev_mtu_error = error;
         netdev_dev->mtu = ifr.ifr_mtu;
         netdev_dev->cache_valid |= VALID_MTU;
     }
-    *mtup = netdev_dev->mtu;
-    return 0;
+
+    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
@@ -1067,20 +1078,24 @@ 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) {
+            return netdev_dev->netdev_mtu_error;
+        }
+        if (netdev_dev->mtu == mtu) {
+            return 0;
+        }
+        netdev_dev->cache_valid &= ~VALID_MTU;
     }
     ifr.ifr_mtu = mtu;
     error = netdev_linux_do_ioctl(netdev_get_name(netdev_), &ifr,
                                   SIOCSIFMTU, "SIOCSIFMTU");
-    if (error) {
-        return error;
+    if (!error || error == ENODEV) {
+        netdev_dev->netdev_mtu_error = error;
+        netdev_dev->mtu = ifr.ifr_mtu;
+        netdev_dev->cache_valid |= VALID_MTU;
     }
-
-    netdev_dev->mtu = ifr.ifr_mtu;
-    netdev_dev->cache_valid |= VALID_MTU;
-    return 0;
+    return error;
 }
 
 /* Returns the ifindex of 'netdev', if successful, as a positive number.
index 185d3dfcec492ce23bf9e3f30f5aea976812b522..37a7d1c29d034c5f425c1c5df0bc224652732353 100644 (file)
@@ -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));
     }
 
index 60b71be868c5e35f1b4b62a91eedc82f11abefa4..d14f0e3c4c3c923bb7de57946619a3bf8b4368d9 100644 (file)
@@ -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;
index b6ddb2149eb136cc8a18417f4daf366a7c21bbc4..cfdb24ba9238f29d5267684b7c23cc285171a76c 100644 (file)
@@ -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. */
 };