diff options
Diffstat (limited to 'drivers/net/ipvlan/ipvlan_main.c')
| -rw-r--r-- | drivers/net/ipvlan/ipvlan_main.c | 40 | 
1 files changed, 31 insertions, 9 deletions
| diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index 4377c26f714d..4a949569ec4c 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -75,10 +75,23 @@ static int ipvlan_set_port_mode(struct ipvl_port *port, u16 nval)  {  	struct ipvl_dev *ipvlan;  	struct net_device *mdev = port->dev; -	int err = 0; +	unsigned int flags; +	int err;  	ASSERT_RTNL();  	if (port->mode != nval) { +		list_for_each_entry(ipvlan, &port->ipvlans, pnode) { +			flags = ipvlan->dev->flags; +			if (nval == IPVLAN_MODE_L3 || nval == IPVLAN_MODE_L3S) { +				err = dev_change_flags(ipvlan->dev, +						       flags | IFF_NOARP); +			} else { +				err = dev_change_flags(ipvlan->dev, +						       flags & ~IFF_NOARP); +			} +			if (unlikely(err)) +				goto fail; +		}  		if (nval == IPVLAN_MODE_L3S) {  			/* New mode is L3S */  			err = ipvlan_register_nf_hook(read_pnet(&port->pnet)); @@ -86,21 +99,28 @@ static int ipvlan_set_port_mode(struct ipvl_port *port, u16 nval)  				mdev->l3mdev_ops = &ipvl_l3mdev_ops;  				mdev->priv_flags |= IFF_L3MDEV_MASTER;  			} else -				return err; +				goto fail;  		} else if (port->mode == IPVLAN_MODE_L3S) {  			/* Old mode was L3S */  			mdev->priv_flags &= ~IFF_L3MDEV_MASTER;  			ipvlan_unregister_nf_hook(read_pnet(&port->pnet));  			mdev->l3mdev_ops = NULL;  		} -		list_for_each_entry(ipvlan, &port->ipvlans, pnode) { -			if (nval == IPVLAN_MODE_L3 || nval == IPVLAN_MODE_L3S) -				ipvlan->dev->flags |= IFF_NOARP; -			else -				ipvlan->dev->flags &= ~IFF_NOARP; -		}  		port->mode = nval;  	} +	return 0; + +fail: +	/* Undo the flags changes that have been done so far. */ +	list_for_each_entry_continue_reverse(ipvlan, &port->ipvlans, pnode) { +		flags = ipvlan->dev->flags; +		if (port->mode == IPVLAN_MODE_L3 || +		    port->mode == IPVLAN_MODE_L3S) +			dev_change_flags(ipvlan->dev, flags | IFF_NOARP); +		else +			dev_change_flags(ipvlan->dev, flags & ~IFF_NOARP); +	} +  	return err;  } @@ -594,7 +614,8 @@ int ipvlan_link_new(struct net *src_net, struct net_device *dev,  	ipvlan->phy_dev = phy_dev;  	ipvlan->dev = dev;  	ipvlan->sfeatures = IPVLAN_FEATURES; -	ipvlan_adjust_mtu(ipvlan, phy_dev); +	if (!tb[IFLA_MTU]) +		ipvlan_adjust_mtu(ipvlan, phy_dev);  	INIT_LIST_HEAD(&ipvlan->addrs);  	spin_lock_init(&ipvlan->addrs_lock); @@ -693,6 +714,7 @@ void ipvlan_link_setup(struct net_device *dev)  {  	ether_setup(dev); +	dev->max_mtu = ETH_MAX_MTU;  	dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);  	dev->priv_flags |= IFF_UNICAST_FLT | IFF_NO_QUEUE;  	dev->netdev_ops = &ipvlan_netdev_ops; |