There is no need to have vport interface for MTU as linux net-dev-ioctl
can be used to get/set MTU for linux device.
Following patch removes kernel vport interface for MTU and fixes
netdev->get_mtu by linux net-dev ioctl. netdev->set_mtu is also added so
that MTU set can be done from OVS userspace.

Signed-off-by: Pravin B Shelar <pshe...@nicira.com>
---
 datapath/datapath.c                     |   57 -------------------------------
 datapath/datapath.h                     |    2 -
 datapath/dp_notify.c                    |    5 ---
 datapath/vport-internal_dev.c           |   23 ------------
 datapath/vport-internal_dev.h           |    2 -
 datapath/vport-netdev.c                 |   14 -------
 datapath/vport-netdev.h                 |    2 -
 datapath/vport.c                        |   46 -------------------------
 datapath/vport.h                        |    9 -----
 include/openvswitch/datapath-protocol.h |    4 --
 lib/dpif-linux.c                        |   10 -----
 lib/dpif-linux.h                        |    1 -
 lib/netdev-dummy.c                      |   11 ++++++
 lib/netdev-linux.c                      |   38 +++++++++++++++++----
 lib/netdev-provider.h                   |    8 ++++-
 lib/netdev-vport.c                      |   20 +++++-----
 lib/netdev.c                            |   29 ++++++++++++---
 lib/netdev.h                            |    1 +
 vswitchd/bridge.c                       |    2 +-
 19 files changed, 84 insertions(+), 200 deletions(-)

diff --git a/datapath/datapath.c b/datapath/datapath.c
index b92c198..aa33f63 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -130,7 +130,6 @@ static inline size_t br_nlmsg_size(void)
               + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
               + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
               + nla_total_size(4) /* IFLA_MASTER */
-              + nla_total_size(4) /* IFLA_MTU */
               + nla_total_size(4) /* IFLA_LINK */
               + nla_total_size(1); /* IFLA_OPERSTATE */
 }
@@ -163,7 +162,6 @@ static int dp_fill_ifinfo(struct sk_buff *skb,
        NLA_PUT_STRING(skb, IFLA_IFNAME, vport_get_name(port));
        NLA_PUT_U32(skb, IFLA_MASTER,
                vport_get_ifindex(get_vport_protected(dp, OVSP_LOCAL)));
-       NLA_PUT_U32(skb, IFLA_MTU, vport_get_mtu(port));
 #ifdef IFLA_OPERSTATE
        NLA_PUT_U8(skb, IFLA_OPERSTATE,
                   vport_is_running(port)
@@ -765,52 +763,6 @@ static void get_dp_stats(struct datapath *dp, struct 
ovs_dp_stats *stats)
        }
 }
 
-/* MTU of the dp pseudo-device: ETH_DATA_LEN or the minimum of the ports.
- * Called with RTNL lock.
- */
-int dp_min_mtu(const struct datapath *dp)
-{
-       struct vport *p;
-       int mtu = 0;
-
-       ASSERT_RTNL();
-
-       list_for_each_entry (p, &dp->port_list, node) {
-               int dev_mtu;
-
-               /* Skip any internal ports, since that's what we're trying to
-                * set. */
-               if (is_internal_vport(p))
-                       continue;
-
-               dev_mtu = vport_get_mtu(p);
-               if (!dev_mtu)
-                       continue;
-               if (!mtu || dev_mtu < mtu)
-                       mtu = dev_mtu;
-       }
-
-       return mtu ? mtu : ETH_DATA_LEN;
-}
-
-/* Sets the MTU of all datapath devices to the minimum of the ports
- * Called with RTNL lock.
- */
-void set_internal_devs_mtu(const struct datapath *dp)
-{
-       struct vport *p;
-       int mtu;
-
-       ASSERT_RTNL();
-
-       mtu = dp_min_mtu(dp);
-
-       list_for_each_entry (p, &dp->port_list, node) {
-               if (is_internal_vport(p))
-                       vport_set_mtu(p, mtu);
-       }
-}
-
 static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = {
        [OVS_FLOW_ATTR_KEY] = { .type = NLA_NESTED },
        [OVS_FLOW_ATTR_ACTIONS] = { .type = NLA_NESTED },
@@ -1585,7 +1537,6 @@ static const struct nla_policy 
vport_policy[OVS_VPORT_ATTR_MAX + 1] = {
        [OVS_VPORT_ATTR_STATS] = { .minlen = sizeof(struct rtnl_link_stats64) },
        [OVS_VPORT_ATTR_ADDRESS] = { .minlen = ETH_ALEN },
 #endif
-       [OVS_VPORT_ATTR_MTU] = { .type = NLA_U32 },
        [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED },
 };
 
@@ -1608,7 +1559,6 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, 
struct sk_buff *skb,
        struct ovs_header *ovs_header;
        struct nlattr *nla;
        int ifindex;
-       int mtu;
        int err;
 
        ovs_header = genlmsg_put(skb, pid, seq, &dp_vport_genl_family,
@@ -1630,10 +1580,6 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, 
struct sk_buff *skb,
 
        NLA_PUT(skb, OVS_VPORT_ATTR_ADDRESS, ETH_ALEN, vport_get_addr(vport));
 
-       mtu = vport_get_mtu(vport);
-       if (mtu)
-               NLA_PUT_U32(skb, OVS_VPORT_ATTR_MTU, mtu);
-
        err = vport_get_options(vport, skb);
        if (err == -EMSGSIZE)
                goto error;
@@ -1713,8 +1659,6 @@ static int change_vport(struct vport *vport, struct 
nlattr *a[OVS_VPORT_ATTR_MAX
                err = vport_set_stats(vport, nla_data(a[OVS_VPORT_ATTR_STATS]));
        if (!err && a[OVS_VPORT_ATTR_ADDRESS])
                err = vport_set_addr(vport, 
nla_data(a[OVS_VPORT_ATTR_ADDRESS]));
-       if (!err && a[OVS_VPORT_ATTR_MTU])
-               err = vport_set_mtu(vport, nla_get_u32(a[OVS_VPORT_ATTR_MTU]));
        return err;
 }
 
@@ -1777,7 +1721,6 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct 
genl_info *info)
        if (IS_ERR(vport))
                goto exit_unlock;
 
-       set_internal_devs_mtu(dp);
        dp_sysfs_add_if(vport);
 
        err = change_vport(vport, a);
diff --git a/datapath/datapath.h b/datapath/datapath.h
index 93be155..2e8305f 100644
--- a/datapath/datapath.h
+++ b/datapath/datapath.h
@@ -150,8 +150,6 @@ extern int (*dp_ioctl_hook)(struct net_device *dev, struct 
ifreq *rq, int cmd);
 void dp_process_received_packet(struct vport *, struct sk_buff *);
 int dp_detach_port(struct vport *);
 int dp_upcall(struct datapath *, struct sk_buff *, const struct dp_upcall_info 
*);
-int dp_min_mtu(const struct datapath *dp);
-void set_internal_devs_mtu(const struct datapath *dp);
 
 struct datapath *get_dp(int dp_idx);
 const char *dp_name(const struct datapath *dp);
diff --git a/datapath/dp_notify.c b/datapath/dp_notify.c
index 7b3b219..942d628 100644
--- a/datapath/dp_notify.c
+++ b/datapath/dp_notify.c
@@ -59,11 +59,6 @@ static int dp_device_event(struct notifier_block *unused, 
unsigned long event,
                        dp_sysfs_add_if(vport);
                }
                break;
-
-       case NETDEV_CHANGEMTU:
-               if (!is_internal_dev(dev))
-                       set_internal_devs_mtu(dp);
-               break;
        }
        return NOTIFY_DONE;
 }
diff --git a/datapath/vport-internal_dev.c b/datapath/vport-internal_dev.c
index f777637..492bef7 100644
--- a/datapath/vport-internal_dev.c
+++ b/datapath/vport-internal_dev.c
@@ -115,20 +115,6 @@ static const struct ethtool_ops internal_dev_ethtool_ops = 
{
        .set_tso        = ethtool_op_set_tso,
 };
 
-static int internal_dev_change_mtu(struct net_device *netdev, int new_mtu)
-{
-       struct vport *vport = internal_dev_get_vport(netdev);
-
-       if (new_mtu < 68)
-               return -EINVAL;
-
-       if (new_mtu > dp_min_mtu(vport->dp))
-               return -EINVAL;
-
-       netdev->mtu = new_mtu;
-       return 0;
-}
-
 static int internal_dev_do_ioctl(struct net_device *dev, struct ifreq *ifr, 
int cmd)
 {
        if (dp_ioctl_hook)
@@ -152,7 +138,6 @@ static const struct net_device_ops internal_dev_netdev_ops 
= {
        .ndo_start_xmit = internal_dev_xmit,
        .ndo_set_mac_address = internal_dev_mac_addr,
        .ndo_do_ioctl = internal_dev_do_ioctl,
-       .ndo_change_mtu = internal_dev_change_mtu,
        .ndo_get_stats = internal_dev_sys_stats,
 };
 #endif
@@ -170,7 +155,6 @@ static void do_setup(struct net_device *netdev)
        netdev->open = internal_dev_open;
        netdev->stop = internal_dev_stop;
        netdev->set_mac_address = internal_dev_mac_addr;
-       netdev->change_mtu = internal_dev_change_mtu;
 #endif
 
        netdev->destructor = internal_dev_destructor;
@@ -276,7 +260,6 @@ const struct vport_ops internal_vport_ops = {
        .flags          = VPORT_F_REQUIRED | VPORT_F_GEN_STATS | VPORT_F_FLOW,
        .create         = internal_dev_create,
        .destroy        = internal_dev_destroy,
-       .set_mtu        = netdev_set_mtu,
        .set_addr       = netdev_set_addr,
        .get_name       = netdev_get_name,
        .get_addr       = netdev_get_addr,
@@ -285,7 +268,6 @@ const struct vport_ops internal_vport_ops = {
        .is_running     = netdev_is_running,
        .get_operstate  = netdev_get_operstate,
        .get_ifindex    = netdev_get_ifindex,
-       .get_mtu        = netdev_get_mtu,
        .send           = internal_dev_recv,
 };
 
@@ -298,11 +280,6 @@ int is_internal_dev(const struct net_device *netdev)
 #endif
 }
 
-int is_internal_vport(const struct vport *vport)
-{
-       return vport->ops == &internal_vport_ops;
-}
-
 struct vport *internal_dev_get_vport(struct net_device *netdev)
 {
        if (!is_internal_dev(netdev))
diff --git a/datapath/vport-internal_dev.h b/datapath/vport-internal_dev.h
index 7c76520..e8dadc0 100644
--- a/datapath/vport-internal_dev.h
+++ b/datapath/vport-internal_dev.h
@@ -12,8 +12,6 @@
 #include "datapath.h"
 #include "vport.h"
 
-int is_internal_vport(const struct vport *);
-
 int is_internal_dev(const struct net_device *);
 struct vport *internal_dev_get_vport(struct net_device *);
 
diff --git a/datapath/vport-netdev.c b/datapath/vport-netdev.c
index dbc8db2..ca20ce5 100644
--- a/datapath/vport-netdev.c
+++ b/datapath/vport-netdev.c
@@ -191,12 +191,6 @@ static int netdev_destroy(struct vport *vport)
        return 0;
 }
 
-int netdev_set_mtu(struct vport *vport, int mtu)
-{
-       struct netdev_vport *netdev_vport = netdev_vport_priv(vport);
-       return dev_set_mtu(netdev_vport->dev, mtu);
-}
-
 int netdev_set_addr(struct vport *vport, const unsigned char *addr)
 {
        struct netdev_vport *netdev_vport = netdev_vport_priv(vport);
@@ -257,12 +251,6 @@ int netdev_get_ifindex(const struct vport *vport)
        return netdev_vport->dev->ifindex;
 }
 
-int netdev_get_mtu(const struct vport *vport)
-{
-       const struct netdev_vport *netdev_vport = netdev_vport_priv(vport);
-       return netdev_vport->dev->mtu;
-}
-
 /* Must be called with rcu_read_lock. */
 static void netdev_port_receive(struct vport *vport, struct sk_buff *skb)
 {
@@ -428,7 +416,6 @@ const struct vport_ops netdev_vport_ops = {
        .exit           = netdev_exit,
        .create         = netdev_create,
        .destroy        = netdev_destroy,
-       .set_mtu        = netdev_set_mtu,
        .set_addr       = netdev_set_addr,
        .get_name       = netdev_get_name,
        .get_addr       = netdev_get_addr,
@@ -438,7 +425,6 @@ const struct vport_ops netdev_vport_ops = {
        .is_running     = netdev_is_running,
        .get_operstate  = netdev_get_operstate,
        .get_ifindex    = netdev_get_ifindex,
-       .get_mtu        = netdev_get_mtu,
        .send           = netdev_send,
 };
 
diff --git a/datapath/vport-netdev.h b/datapath/vport-netdev.h
index 3f64767..e521b2d 100644
--- a/datapath/vport-netdev.h
+++ b/datapath/vport-netdev.h
@@ -25,7 +25,6 @@ netdev_vport_priv(const struct vport *vport)
        return vport_priv(vport);
 }
 
-int netdev_set_mtu(struct vport *, int mtu);
 int netdev_set_addr(struct vport *, const unsigned char *addr);
 const char *netdev_get_name(const struct vport *);
 const unsigned char *netdev_get_addr(const struct vport *);
@@ -36,6 +35,5 @@ unsigned netdev_get_dev_flags(const struct vport *);
 int netdev_is_running(const struct vport *);
 unsigned char netdev_get_operstate(const struct vport *);
 int netdev_get_ifindex(const struct vport *);
-int netdev_get_mtu(const struct vport *);
 
 #endif /* vport_netdev.h */
diff --git a/datapath/vport.c b/datapath/vport.c
index bf6297e..791c0f5 100644
--- a/datapath/vport.c
+++ b/datapath/vport.c
@@ -285,36 +285,6 @@ int vport_del(struct vport *vport)
 }
 
 /**
- *     vport_set_mtu - set device MTU (for kernel callers)
- *
- * @vport: vport on which to set MTU.
- * @mtu: New MTU.
- *
- * Sets the MTU of the given device.  Some devices may not support setting the
- * MTU, in which case the result will always be -EOPNOTSUPP.  RTNL lock must
- * be held.
- */
-int vport_set_mtu(struct vport *vport, int mtu)
-{
-       ASSERT_RTNL();
-
-       if (mtu < 68)
-               return -EINVAL;
-
-       if (vport->ops->set_mtu) {
-               int ret;
-
-               ret = vport->ops->set_mtu(vport, mtu);
-
-               if (!ret && !is_internal_vport(vport))
-                       set_internal_devs_mtu(vport->dp);
-
-               return ret;
-       } else
-               return -EOPNOTSUPP;
-}
-
-/**
  *     vport_set_addr - set device Ethernet address (for kernel callers)
  *
  * @vport: vport on which to set Ethernet address.
@@ -577,22 +547,6 @@ int vport_get_ifindex(const struct vport *vport)
 }
 
 /**
- *     vport_get_mtu - retrieve device MTU
- *
- * @vport: vport from which to retrieve MTU
- *
- * Retrieves the MTU of the given device.  Returns 0 if @vport does not have an
- * MTU (as e.g. some tunnels do not).  Either RTNL lock or rcu_read_lock must
- * be held.
- */
-int vport_get_mtu(const struct vport *vport)
-{
-       if (!vport->ops->get_mtu)
-               return 0;
-       return vport->ops->get_mtu(vport);
-}
-
-/**
  *     vport_get_options - retrieve device options
  *
  * @vport: vport from which to retrieve the options.
diff --git a/datapath/vport.h b/datapath/vport.h
index 0a6d831..e4b6c62 100644
--- a/datapath/vport.h
+++ b/datapath/vport.h
@@ -30,7 +30,6 @@ int vport_del(struct vport *);
 
 struct vport *vport_locate(const char *name);
 
-int vport_set_mtu(struct vport *, int mtu);
 int vport_set_addr(struct vport *, const unsigned char *);
 int vport_set_stats(struct vport *, struct rtnl_link_stats64 *);
 
@@ -47,8 +46,6 @@ unsigned char vport_get_operstate(const struct vport *);
 
 int vport_get_ifindex(const struct vport *);
 
-int vport_get_mtu(const struct vport *);
-
 int vport_set_options(struct vport *, struct nlattr *options);
 int vport_get_options(const struct vport *, struct sk_buff *);
 
@@ -156,7 +153,6 @@ struct vport_parms {
  * @get_options: Appends vport-specific attributes for the configuration of an
  * existing vport to a &struct sk_buff.  May be %NULL for a vport that does not
  * have any configuration.
- * @set_mtu: Set the device's MTU.  May be null if not supported.
  * @set_addr: Set the device's MAC address.  May be null if not supported.
  * @get_name: Get the device's name.
  * @get_addr: Get the device's MAC address.
@@ -171,8 +167,6 @@ struct vport_parms {
  * @get_operstate: Get the device's operating state.
  * @get_ifindex: Get the system interface index associated with the device.
  * May be null if the device does not have an ifindex.
- * @get_mtu: Get the device's MTU.  May be %NULL if the device does not have an
- * MTU (as e.g. some tunnels do not).
  * @send: Send a packet on the device.  Returns the length of the packet sent.
  */
 struct vport_ops {
@@ -190,7 +184,6 @@ struct vport_ops {
        int (*set_options)(struct vport *, struct nlattr *);
        int (*get_options)(const struct vport *, struct sk_buff *);
 
-       int (*set_mtu)(struct vport *, int mtu);
        int (*set_addr)(struct vport *, const unsigned char *);
 
        /* Called with rcu_read_lock or RTNL lock. */
@@ -206,8 +199,6 @@ struct vport_ops {
 
        int (*get_ifindex)(const struct vport *);
 
-       int (*get_mtu)(const struct vport *);
-
        int (*send)(struct vport *, struct sk_buff *);
 };
 
diff --git a/include/openvswitch/datapath-protocol.h 
b/include/openvswitch/datapath-protocol.h
index 97a7c04..adc39d1 100644
--- a/include/openvswitch/datapath-protocol.h
+++ b/include/openvswitch/datapath-protocol.h
@@ -222,8 +222,6 @@ enum ovs_vport_cmd {
  * @OVS_VPORT_ATTR_STATS: A &struct rtnl_link_stats64 giving statistics for
  * packets sent or received through the vport.
  * @OVS_VPORT_ATTR_ADDRESS: A 6-byte Ethernet address for the vport.
- * @OVS_VPORT_ATTR_MTU: MTU for the vport.  Omitted if the vport does not have
- * an MTU as, e.g., some tunnels do not.
  * @OVS_VPORT_ATTR_IFINDEX: ifindex of the underlying network device, if any.
  *
  * These attributes follow the &struct ovs_header within the Generic Netlink
@@ -238,7 +236,6 @@ enum ovs_vport_cmd {
  * optional; if not specified a free port number is automatically selected.
  * Whether %OVS_VPORT_ATTR_OPTIONS is required or optional depends on the type
  * of vport.  %OVS_VPORT_ATTR_STATS, %OVS_VPORT_ATTR_ADDRESS, and
- * %OVS_VPORT_ATTR_MTU are optional, and other attributes are ignored.
  *
  * For other requests, if %OVS_VPORT_ATTR_NAME is specified then it is used to
  * look up the vport to operate on; otherwise dp_idx from the &struct
@@ -251,7 +248,6 @@ enum ovs_vport_attr {
        OVS_VPORT_ATTR_NAME,    /* string name, up to IFNAMSIZ bytes long */
        OVS_VPORT_ATTR_STATS,   /* struct rtnl_link_stats64 */
        OVS_VPORT_ATTR_ADDRESS, /* hardware address */
-       OVS_VPORT_ATTR_MTU,     /* 32-bit maximum transmission unit */
        OVS_VPORT_ATTR_OPTIONS, /* nested attributes, varies by vport type */
        OVS_VPORT_ATTR_IFINDEX, /* 32-bit ifindex of backing netdev */
        __OVS_VPORT_ATTR_MAX
diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c
index 8d655f3..9533e14 100644
--- a/lib/dpif-linux.c
+++ b/lib/dpif-linux.c
@@ -1238,7 +1238,6 @@ dpif_linux_vport_from_ofpbuf(struct dpif_linux_vport 
*vport,
                                      .min_len = ETH_ADDR_LEN,
                                      .max_len = ETH_ADDR_LEN,
                                      .optional = true },
-        [OVS_VPORT_ATTR_MTU] = { .type = NL_A_U32, .optional = true },
         [OVS_VPORT_ATTR_OPTIONS] = { .type = NL_A_NESTED, .optional = true },
         [OVS_VPORT_ATTR_IFINDEX] = { .type = NL_A_U32, .optional = true },
     };
@@ -1273,11 +1272,6 @@ dpif_linux_vport_from_ofpbuf(struct dpif_linux_vport 
*vport,
     if (a[OVS_VPORT_ATTR_ADDRESS]) {
         vport->address = nl_attr_get(a[OVS_VPORT_ATTR_ADDRESS]);
     }
-    if (a[OVS_VPORT_ATTR_MTU]) {
-        vport->mtu = nl_attr_get_u32(a[OVS_VPORT_ATTR_MTU]);
-    } else {
-        vport->mtu = INT_MAX;
-    }
     if (a[OVS_VPORT_ATTR_OPTIONS]) {
         vport->options = nl_attr_get(a[OVS_VPORT_ATTR_OPTIONS]);
         vport->options_len = nl_attr_get_size(a[OVS_VPORT_ATTR_OPTIONS]);
@@ -1324,10 +1318,6 @@ dpif_linux_vport_to_ofpbuf(const struct dpif_linux_vport 
*vport,
                           vport->address, ETH_ADDR_LEN);
     }
 
-    if (vport->mtu && vport->mtu != INT_MAX) {
-        nl_msg_put_u32(buf, OVS_VPORT_ATTR_MTU, vport->mtu);
-    }
-
     if (vport->options) {
         nl_msg_put_nested(buf, OVS_VPORT_ATTR_OPTIONS,
                           vport->options, vport->options_len);
diff --git a/lib/dpif-linux.h b/lib/dpif-linux.h
index 3a2c816..c673bee 100644
--- a/lib/dpif-linux.h
+++ b/lib/dpif-linux.h
@@ -36,7 +36,6 @@ struct dpif_linux_vport {
     const char *name;                      /* OVS_VPORT_ATTR_NAME. */
     const struct rtnl_link_stats64 *stats; /* OVS_VPORT_ATTR_STATS. */
     const uint8_t *address;                /* OVS_VPORT_ATTR_ADDRESS. */
-    int mtu;                               /* OVS_VPORT_ATTR_MTU. */
     const struct nlattr *options;          /* OVS_VPORT_ATTR_OPTIONS. */
     size_t options_len;
     int ifindex;                           /* OVS_VPORT_ATTR_IFINDEX. */
diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c
index 4fb1151..c2c5311 100644
--- a/lib/netdev-dummy.c
+++ b/lib/netdev-dummy.c
@@ -172,6 +172,16 @@ netdev_dummy_get_mtu(const struct netdev *netdev, int 
*mtup)
 }
 
 static int
+netdev_dummy_set_mtu(const struct netdev *netdev, int mtu)
+{
+    struct netdev_dev_dummy *dev =
+        netdev_dev_dummy_cast(netdev_get_dev(netdev));
+
+    dev->mtu = mtu;
+    return 0;
+}
+
+static int
 netdev_dummy_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
 {
     const struct netdev_dev_dummy *dev =
@@ -259,6 +269,7 @@ static const struct netdev_class dummy_class = {
     netdev_dummy_set_etheraddr,
     netdev_dummy_get_etheraddr,
     netdev_dummy_get_mtu,
+    netdev_dummy_set_mtu,
     NULL,                       /* get_ifindex */
     NULL,                       /* get_carrier */
     NULL,                       /* get_miimon */
diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index 6d44581..fc61d45 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -1000,6 +1000,29 @@ netdev_linux_get_mtu(const struct netdev *netdev_, int 
*mtup)
     return 0;
 }
 
+/* Sets the maximum size of transmitted (MTU) for given device using linux
+ * networking ioctl interface.
+ */
+static int
+netdev_linux_set_mtu(const struct netdev *netdev_, int mtu)
+{
+    struct netdev_dev_linux *netdev_dev =
+                                netdev_dev_linux_cast(netdev_get_dev(netdev_));
+    struct ifreq ifr;
+    int error;
+
+    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->cache_valid |= VALID_MTU;
+    return 0;
+}
+
 /* Returns the ifindex of 'netdev', if successful, as a positive number.
  * On failure, returns a negative errno value. */
 static int
@@ -2269,6 +2292,7 @@ netdev_linux_change_seq(const struct netdev *netdev)
     netdev_linux_set_etheraddr,                                 \
     netdev_linux_get_etheraddr,                                 \
     netdev_linux_get_mtu,                                       \
+    netdev_linux_set_mtu,                                       \
     netdev_linux_get_ifindex,                                   \
     netdev_linux_get_carrier,                                   \
     netdev_linux_set_miimon_interval,                           \
@@ -2412,11 +2436,11 @@ htb_setup_class__(struct netdev *netdev, unsigned int 
handle,
     int error;
     int mtu;
 
-    netdev_get_mtu(netdev, &mtu);
-    if (mtu == INT_MAX) {
+    error = netdev_get_mtu(netdev, &mtu);
+    if (error) {
         VLOG_WARN_RL(&rl, "cannot set up HTB on device %s that lacks MTU",
                      netdev_get_name(netdev));
-        return EINVAL;
+        return error;
     }
 
     memset(&opt, 0, sizeof opt);
@@ -2535,13 +2559,13 @@ htb_parse_class_details__(struct netdev *netdev,
     const char *max_rate_s = shash_find_data(details, "max-rate");
     const char *burst_s = shash_find_data(details, "burst");
     const char *priority_s = shash_find_data(details, "priority");
-    int mtu;
+    int mtu, error;
 
-    netdev_get_mtu(netdev, &mtu);
-    if (mtu == INT_MAX) {
+    error = netdev_get_mtu(netdev, &mtu);
+    if (error) {
         VLOG_WARN_RL(&rl, "cannot parse HTB class on device %s that lacks MTU",
                      netdev_get_name(netdev));
-        return EINVAL;
+        return error;
     }
 
     /* HTB requires at least an mtu sized min-rate to send any traffic even
diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h
index 5214be3..d38dd5f 100644
--- a/lib/netdev-provider.h
+++ b/lib/netdev-provider.h
@@ -248,9 +248,15 @@ struct netdev_class {
      * bytes for Ethernet devices.
      *
      * If 'netdev' does not have an MTU (e.g. as some tunnels do not), then
-     * this function should set '*mtup' to INT_MAX. */
+     * this function should return ENOTSUP. */
     int (*get_mtu)(const struct netdev *netdev, int *mtup);
 
+    /* Sets 'netdev''s MTU to 'mtu'.
+     *
+     * If 'netdev' does not have an MTU (e.g. as some tunnels do not), then
+     * this function should return ENOTSUP. */
+    int (*set_mtu)(const struct netdev *netdev, int mtu);
+
     /* Returns the ifindex of 'netdev', if successful, as a positive number.
      * On failure, returns a negative errno value.
      *
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index 15bf8bd..3bdb022 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -362,18 +362,17 @@ netdev_vport_get_etheraddr(const struct netdev *netdev,
 }
 
 static int
-netdev_vport_get_mtu(const struct netdev *netdev, int *mtup)
+netdev_vport_get_mtu(const struct netdev *netdev OVS_UNUSED,
+                     int *mtup OVS_UNUSED)
 {
-    struct dpif_linux_vport reply;
-    struct ofpbuf *buf;
-    int error;
+    return ENOTSUP;
+}
 
-    error = dpif_linux_vport_get(netdev_get_name(netdev), &reply, &buf);
-    if (!error) {
-        *mtup = reply.mtu;
-        ofpbuf_delete(buf);
-    }
-    return error;
+static int
+netdev_vport_set_mtu(const struct netdev *netdev OVS_UNUSED,
+                     int mtu OVS_UNUSED)
+{
+    return ENOTSUP;
 }
 
 int
@@ -876,6 +875,7 @@ unparse_patch_config(const char *name OVS_UNUSED, const 
char *type OVS_UNUSED,
     netdev_vport_set_etheraddr,                             \
     netdev_vport_get_etheraddr,                             \
     netdev_vport_get_mtu,                                   \
+    netdev_vport_set_mtu,                                   \
     NULL,                       /* get_ifindex */           \
     NULL,                       /* get_carrier */           \
     NULL,                       /* get_miimon */            \
diff --git a/lib/netdev.c b/lib/netdev.c
index 12ac81d..4295f6b 100644
--- a/lib/netdev.c
+++ b/lib/netdev.c
@@ -510,19 +510,36 @@ netdev_get_name(const struct netdev *netdev)
  * (and received) packets, in bytes, not including the hardware header; thus,
  * this is typically 1500 bytes for Ethernet devices.
  *
- * If successful, returns 0 and stores the MTU size in '*mtup'.  Stores INT_MAX
- * in '*mtup' if 'netdev' does not have an MTU (as e.g. some tunnels do not).On
- * failure, returns a positive errno value and stores ETH_PAYLOAD_MAX (1500) in
- * '*mtup'. */
+ * If successful, returns 0 and stores the MTU size in '*mtup'.  returns
+ * ENOTSUP if 'netdev' does not have an MTU (as e.g. some tunnels do not). On
+ * other failure, returns a positive errno value. */
 int
 netdev_get_mtu(const struct netdev *netdev, int *mtup)
 {
     int error = netdev_get_dev(netdev)->netdev_class->get_mtu(netdev, mtup);
-    if (error) {
+    if (error && error != ENOTSUP) {
+        VLOG_WARN_RL(&rl, "failed to retrieve MTU for network device %s: %s",
+                     netdev_get_name(netdev), strerror(error));
+    }
+    return error;
+}
+
+/* Sets the MTU of 'netdev'.  The MTU is the maximum size of transmitted
+ * (and received) packets, in bytes.
+ *
+ * If successful, returns 0. returns  ENOTSUP if 'netdev' does not have an
+ * MTU (as e.g. some tunnels do not). On other failure, returns a positive
+ * errno value. */
+int
+netdev_set_mtu(const struct netdev *netdev, int mtu)
+{
+    int error = netdev_get_dev(netdev)->netdev_class->set_mtu(netdev, mtu);
+
+    if (error && error != ENOTSUP) {
         VLOG_WARN_RL(&rl, "failed to retrieve MTU for network device %s: %s",
                      netdev_get_name(netdev), strerror(error));
-        *mtup = ETH_PAYLOAD_MAX;
     }
+
     return error;
 }
 
diff --git a/lib/netdev.h b/lib/netdev.h
index 13d2ee7..2644708 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -100,6 +100,7 @@ int netdev_get_config(const struct netdev *, struct shash 
*);
 const char *netdev_get_name(const struct netdev *);
 const char *netdev_get_type(const struct netdev *);
 int netdev_get_mtu(const struct netdev *, int *mtup);
+int netdev_set_mtu(const struct netdev *, int mtu);
 int netdev_get_ifindex(const struct netdev *);
 
 /* Packet send and receive. */
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 2bfd926..5d342e3 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -1245,7 +1245,7 @@ iface_refresh_status(struct iface *iface)
                                     iface_get_carrier(iface) ? "up" : "down");
 
     error = netdev_get_mtu(iface->netdev, &mtu);
-    if (!error && mtu != INT_MAX) {
+    if (!error) {
         mtu_64 = mtu;
         ovsrec_interface_set_mtu(iface->cfg, &mtu_64, 1);
     }
-- 
1.7.1

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to