diff options
Diffstat (limited to 'drivers/net/ipvlan')
-rw-r--r-- | drivers/net/ipvlan/ipvlan.h | 3 | ||||
-rw-r--r-- | drivers/net/ipvlan/ipvlan_main.c | 78 | ||||
-rw-r--r-- | drivers/net/ipvlan/ipvtap.c | 9 |
3 files changed, 81 insertions, 9 deletions
diff --git a/drivers/net/ipvlan/ipvlan.h b/drivers/net/ipvlan/ipvlan.h index 7919369c0a72..ba8173a0b62e 100644 --- a/drivers/net/ipvlan/ipvlan.h +++ b/drivers/net/ipvlan/ipvlan.h @@ -140,7 +140,8 @@ unsigned int ipvlan_nf_input(void *priv, struct sk_buff *skb, void ipvlan_count_rx(const struct ipvl_dev *ipvlan, unsigned int len, bool success, bool mcast); int ipvlan_link_new(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]); + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack); void ipvlan_link_delete(struct net_device *dev, struct list_head *head); void ipvlan_link_setup(struct net_device *dev); int ipvlan_link_register(struct rtnl_link_ops *ops); diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index 7c7680c8f0e3..f37e3c1fd4e7 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -455,7 +455,8 @@ static const struct ethtool_ops ipvlan_ethtool_ops = { }; static int ipvlan_nl_changelink(struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { struct ipvl_dev *ipvlan = netdev_priv(dev); struct ipvl_port *port = ipvlan_port_get_rtnl(ipvlan->phy_dev); @@ -476,7 +477,8 @@ static size_t ipvlan_nl_getsize(const struct net_device *dev) ); } -static int ipvlan_nl_validate(struct nlattr *tb[], struct nlattr *data[]) +static int ipvlan_nl_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { if (data && data[IFLA_IPVLAN_MODE]) { u16 mode = nla_get_u16(data[IFLA_IPVLAN_MODE]); @@ -508,7 +510,8 @@ err: } int ipvlan_link_new(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { struct ipvl_dev *ipvlan = netdev_priv(dev); struct ipvl_port *port; @@ -824,6 +827,33 @@ static int ipvlan_addr6_event(struct notifier_block *unused, return NOTIFY_OK; } +static int ipvlan_addr6_validator_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct in6_validator_info *i6vi = (struct in6_validator_info *)ptr; + struct net_device *dev = (struct net_device *)i6vi->i6vi_dev->dev; + struct ipvl_dev *ipvlan = netdev_priv(dev); + + /* FIXME IPv6 autoconf calls us from bh without RTNL */ + if (in_softirq()) + return NOTIFY_DONE; + + if (!netif_is_ipvlan(dev)) + return NOTIFY_DONE; + + if (!ipvlan || !ipvlan->port) + return NOTIFY_DONE; + + switch (event) { + case NETDEV_UP: + if (ipvlan_addr_busy(ipvlan->port, &i6vi->i6vi_addr, true)) + return notifier_from_errno(-EADDRINUSE); + break; + } + + return NOTIFY_OK; +} + static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr) { if (ipvlan_addr_busy(ipvlan->port, ip4_addr, false)) { @@ -871,10 +901,37 @@ static int ipvlan_addr4_event(struct notifier_block *unused, return NOTIFY_OK; } +static int ipvlan_addr4_validator_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct in_validator_info *ivi = (struct in_validator_info *)ptr; + struct net_device *dev = (struct net_device *)ivi->ivi_dev->dev; + struct ipvl_dev *ipvlan = netdev_priv(dev); + + if (!netif_is_ipvlan(dev)) + return NOTIFY_DONE; + + if (!ipvlan || !ipvlan->port) + return NOTIFY_DONE; + + switch (event) { + case NETDEV_UP: + if (ipvlan_addr_busy(ipvlan->port, &ivi->ivi_addr, false)) + return notifier_from_errno(-EADDRINUSE); + break; + } + + return NOTIFY_OK; +} + static struct notifier_block ipvlan_addr4_notifier_block __read_mostly = { .notifier_call = ipvlan_addr4_event, }; +static struct notifier_block ipvlan_addr4_vtor_notifier_block __read_mostly = { + .notifier_call = ipvlan_addr4_validator_event, +}; + static struct notifier_block ipvlan_notifier_block __read_mostly = { .notifier_call = ipvlan_device_event, }; @@ -883,6 +940,10 @@ static struct notifier_block ipvlan_addr6_notifier_block __read_mostly = { .notifier_call = ipvlan_addr6_event, }; +static struct notifier_block ipvlan_addr6_vtor_notifier_block __read_mostly = { + .notifier_call = ipvlan_addr6_validator_event, +}; + static void ipvlan_ns_exit(struct net *net) { struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid); @@ -907,7 +968,10 @@ static int __init ipvlan_init_module(void) ipvlan_init_secret(); register_netdevice_notifier(&ipvlan_notifier_block); register_inet6addr_notifier(&ipvlan_addr6_notifier_block); + register_inet6addr_validator_notifier( + &ipvlan_addr6_vtor_notifier_block); register_inetaddr_notifier(&ipvlan_addr4_notifier_block); + register_inetaddr_validator_notifier(&ipvlan_addr4_vtor_notifier_block); err = register_pernet_subsys(&ipvlan_net_ops); if (err < 0) @@ -922,7 +986,11 @@ static int __init ipvlan_init_module(void) return 0; error: unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block); + unregister_inetaddr_validator_notifier( + &ipvlan_addr4_vtor_notifier_block); unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block); + unregister_inet6addr_validator_notifier( + &ipvlan_addr6_vtor_notifier_block); unregister_netdevice_notifier(&ipvlan_notifier_block); return err; } @@ -933,7 +1001,11 @@ static void __exit ipvlan_cleanup_module(void) unregister_pernet_subsys(&ipvlan_net_ops); unregister_netdevice_notifier(&ipvlan_notifier_block); unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block); + unregister_inetaddr_validator_notifier( + &ipvlan_addr4_vtor_notifier_block); unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block); + unregister_inet6addr_validator_notifier( + &ipvlan_addr6_vtor_notifier_block); } module_init(ipvlan_init_module); diff --git a/drivers/net/ipvlan/ipvtap.c b/drivers/net/ipvlan/ipvtap.c index 2b713b63b62c..22f133ea8d7b 100644 --- a/drivers/net/ipvlan/ipvtap.c +++ b/drivers/net/ipvlan/ipvtap.c @@ -73,10 +73,9 @@ static void ipvtap_update_features(struct tap_dev *tap, netdev_update_features(vlan->dev); } -static int ipvtap_newlink(struct net *src_net, - struct net_device *dev, - struct nlattr *tb[], - struct nlattr *data[]) +static int ipvtap_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { struct ipvtap_dev *vlantap = netdev_priv(dev); int err; @@ -98,7 +97,7 @@ static int ipvtap_newlink(struct net *src_net, /* Don't put anything that may fail after macvlan_common_newlink * because we can't undo what it does. */ - err = ipvlan_link_new(src_net, dev, tb, data); + err = ipvlan_link_new(src_net, dev, tb, data, extack); if (err) { netdev_rx_handler_unregister(dev); return err; |