On Wed, Oct 19, 2016 at 02:17:03PM +0200, Jiri Benc wrote:
> On Tue, 18 Oct 2016 22:33:31 -0400, Jarod Wilson wrote:
> > --- a/drivers/net/vxlan.c
> > +++ b/drivers/net/vxlan.c
> > @@ -2367,43 +2367,31 @@ static void vxlan_set_multicast_list(struct 
> > net_device *dev)
> >  {
> >  }
> >  
> > -static int __vxlan_change_mtu(struct net_device *dev,
> > -                         struct net_device *lowerdev,
> > -                         struct vxlan_rdst *dst, int new_mtu, bool strict)
> > +static int vxlan_change_mtu(struct net_device *dev, int new_mtu)
> >  {
> > -   int max_mtu = IP_MAX_MTU;
> > -
> > -   if (lowerdev)
> > -           max_mtu = lowerdev->mtu;
> > +   struct vxlan_dev *vxlan = netdev_priv(dev);
> > +   struct vxlan_rdst *dst = &vxlan->default_dst;
> > +   struct net_device *lowerdev = __dev_get_by_index(vxlan->net,
> > +                                                    dst->remote_ifindex);
> > +   bool use_ipv6 = false;
> >  
> >     if (dst->remote_ip.sa.sa_family == AF_INET6)
> > -           max_mtu -= VXLAN6_HEADROOM;
> > -   else
> > -           max_mtu -= VXLAN_HEADROOM;
> > -
> > -   if (new_mtu < 68)
> > -           return -EINVAL;
> > +           use_ipv6 = true;
> >  
> > -   if (new_mtu > max_mtu) {
> > -           if (strict)
> > +   /* We re-check this, because users *could* alter the mtu of the
> > +    * lower device after we've initialized dev->max_mtu.
> > +    */
> > +   if (lowerdev) {
> > +           dev->max_mtu = lowerdev->mtu -
> > +                          (use_ipv6 ? VXLAN6_HEADROOM : VXLAN_HEADROOM);
> > +           if (new_mtu > dev->max_mtu)
> >                     return -EINVAL;
> > -
> > -           new_mtu = max_mtu;
> >     }
> >  
> >     dev->mtu = new_mtu;
> >     return 0;
> >  }
> 
> Sorry for the silly question, how does the min_mtu and max_mtu stuff
> works? I noticed your patches but haven't looked in depth into them.
> 
> When the ndo_change_mtu callback is defined, is the dev->min_mtu and
> dev->max_mtu checked first and if the desired mtu is not within range,
> ndo_change_mtu is not called?
> 
> Or does ndo_change_mtu override the checks?

The former. If the new value is outside min/max, ndo_change_mtu doesn't
get called, which is exactly the chicken and egg problem I introduced by
setting max_mtu to 1500 in ether_setup before having all drivers that call
ether_setup set a more appropriate max_mtu first. :\

> In either case, the code does not look correct. In the first case,
> increasing of lowerdev MTU wouldn't allow increasing of vxlan MTU
> without deleting and recreating the vxlan interface. In the second
> case, you're missing check against the min_mtu.

Okay, this sounds like a similar case to bridge that Sabrina pointed out.
Looks like virtual devices will need to just set no max_mtu directly (or
IP_MAX_MTU), and do dynamic checks in their ndo_change_mtu if they need to
compare against underlying devices on the fly.

...
> > @@ -2847,9 +2842,14 @@ static int vxlan_dev_configure(struct net *src_net, 
> > struct net_device *dev,
> >     }
> >  
> >     if (conf->mtu) {
> > -           err = __vxlan_change_mtu(dev, lowerdev, dst, conf->mtu, false);
> > -           if (err)
> > -                   return err;
> > +           if (lowerdev)
> > +                   dev->max_mtu = lowerdev->mtu;
> > +           dev->max_mtu -= (use_ipv6 ? VXLAN6_HEADROOM : VXLAN_HEADROOM);
> > +
> > +           dev->mtu = conf->mtu;
> > +
> > +           if (conf->mtu > dev->max_mtu)
> > +                   dev->mtu = dev->max_mtu;
> >     }
> 
> You removed the check for min_mtu but it's needed here. The conf->mtu
> value comes from the user space and can be anything.

Hm. Not sure why I did that... Will put it back now...

-- 
Jarod Wilson
ja...@redhat.com

Reply via email to