diff options
Diffstat (limited to 'drivers/net/ipvlan/ipvlan_main.c')
| -rw-r--r-- | drivers/net/ipvlan/ipvlan_main.c | 19 | 
1 files changed, 14 insertions, 5 deletions
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index f442eb366863..dfbc4ef6d507 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -497,6 +497,7 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev,  	struct net_device *phy_dev;  	int err;  	u16 mode = IPVLAN_MODE_L3; +	bool create = false;  	if (!tb[IFLA_LINK])  		return -EINVAL; @@ -513,6 +514,7 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev,  		err = ipvlan_port_create(phy_dev);  		if (err < 0)  			return err; +		create = true;  	}  	if (data && data[IFLA_IPVLAN_MODE]) @@ -536,22 +538,29 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev,  	err = register_netdevice(dev);  	if (err < 0) -		return err; +		goto destroy_ipvlan_port;  	err = netdev_upper_dev_link(phy_dev, dev);  	if (err) { -		unregister_netdevice(dev); -		return err; +		goto unregister_netdev;  	}  	err = ipvlan_set_port_mode(port, mode);  	if (err) { -		unregister_netdevice(dev); -		return err; +		goto unlink_netdev;  	}  	list_add_tail_rcu(&ipvlan->pnode, &port->ipvlans);  	netif_stacked_transfer_operstate(phy_dev, dev);  	return 0; + +unlink_netdev: +	netdev_upper_dev_unlink(phy_dev, dev); +unregister_netdev: +	unregister_netdevice(dev); +destroy_ipvlan_port: +	if (create) +		ipvlan_port_destroy(phy_dev); +	return err;  }  static void ipvlan_link_delete(struct net_device *dev, struct list_head *head)  | 
