]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - drivers/net/ipvlan/ipvlan_main.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[mirror_ubuntu-jammy-kernel.git] / drivers / net / ipvlan / ipvlan_main.c
index 19bdde60680c29a1e58a3192a5367e0a18eba6c4..bbeb1623e2d57ad5d0542b7a79474bbb823b0d18 100644 (file)
@@ -9,73 +9,10 @@
 
 #include "ipvlan.h"
 
-static unsigned int ipvlan_netid __read_mostly;
-
-struct ipvlan_netns {
-       unsigned int ipvl_nf_hook_refcnt;
-};
-
-static const struct nf_hook_ops ipvl_nfops[] = {
-       {
-               .hook     = ipvlan_nf_input,
-               .pf       = NFPROTO_IPV4,
-               .hooknum  = NF_INET_LOCAL_IN,
-               .priority = INT_MAX,
-       },
-#if IS_ENABLED(CONFIG_IPV6)
-       {
-               .hook     = ipvlan_nf_input,
-               .pf       = NFPROTO_IPV6,
-               .hooknum  = NF_INET_LOCAL_IN,
-               .priority = INT_MAX,
-       },
-#endif
-};
-
-static const struct l3mdev_ops ipvl_l3mdev_ops = {
-       .l3mdev_l3_rcv = ipvlan_l3_rcv,
-};
-
-static void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev)
-{
-       ipvlan->dev->mtu = dev->mtu;
-}
-
-static int ipvlan_register_nf_hook(struct net *net)
-{
-       struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid);
-       int err = 0;
-
-       if (!vnet->ipvl_nf_hook_refcnt) {
-               err = nf_register_net_hooks(net, ipvl_nfops,
-                                           ARRAY_SIZE(ipvl_nfops));
-               if (!err)
-                       vnet->ipvl_nf_hook_refcnt = 1;
-       } else {
-               vnet->ipvl_nf_hook_refcnt++;
-       }
-
-       return err;
-}
-
-static void ipvlan_unregister_nf_hook(struct net *net)
-{
-       struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid);
-
-       if (WARN_ON(!vnet->ipvl_nf_hook_refcnt))
-               return;
-
-       vnet->ipvl_nf_hook_refcnt--;
-       if (!vnet->ipvl_nf_hook_refcnt)
-               nf_unregister_net_hooks(net, ipvl_nfops,
-                                       ARRAY_SIZE(ipvl_nfops));
-}
-
 static int ipvlan_set_port_mode(struct ipvl_port *port, u16 nval,
                                struct netlink_ext_ack *extack)
 {
        struct ipvl_dev *ipvlan;
-       struct net_device *mdev = port->dev;
        unsigned int flags;
        int err;
 
@@ -97,17 +34,12 @@ static int ipvlan_set_port_mode(struct ipvl_port *port, u16 nval,
                }
                if (nval == IPVLAN_MODE_L3S) {
                        /* New mode is L3S */
-                       err = ipvlan_register_nf_hook(read_pnet(&port->pnet));
-                       if (!err) {
-                               mdev->l3mdev_ops = &ipvl_l3mdev_ops;
-                               mdev->priv_flags |= IFF_L3MDEV_MASTER;
-                       } else
+                       err = ipvlan_l3s_register(port);
+                       if (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;
+                       ipvlan_l3s_unregister(port);
                }
                port->mode = nval;
        }
@@ -166,11 +98,8 @@ static void ipvlan_port_destroy(struct net_device *dev)
        struct ipvl_port *port = ipvlan_port_get_rtnl(dev);
        struct sk_buff *skb;
 
-       if (port->mode == IPVLAN_MODE_L3S) {
-               dev->priv_flags &= ~IFF_L3MDEV_MASTER;
-               ipvlan_unregister_nf_hook(dev_net(dev));
-               dev->l3mdev_ops = NULL;
-       }
+       if (port->mode == IPVLAN_MODE_L3S)
+               ipvlan_l3s_unregister(port);
        netdev_rx_handler_unregister(dev);
        cancel_work_sync(&port->wq);
        while ((skb = __skb_dequeue(&port->backlog)) != NULL) {
@@ -446,6 +375,11 @@ static const struct header_ops ipvlan_header_ops = {
        .cache_update   = eth_header_cache_update,
 };
 
+static void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev)
+{
+       ipvlan->dev->mtu = dev->mtu;
+}
+
 static bool netif_is_ipvlan(const struct net_device *dev)
 {
        /* both ipvlan and ipvtap devices use the same netdev_ops */
@@ -499,6 +433,8 @@ static int ipvlan_nl_changelink(struct net_device *dev,
 
        if (!data)
                return 0;
+       if (!ns_capable(dev_net(ipvlan->phy_dev)->user_ns, CAP_NET_ADMIN))
+               return -EPERM;
 
        if (data[IFLA_IPVLAN_MODE]) {
                u16 nmode = nla_get_u16(data[IFLA_IPVLAN_MODE]);
@@ -601,6 +537,8 @@ int ipvlan_link_new(struct net *src_net, struct net_device *dev,
                struct ipvl_dev *tmp = netdev_priv(phy_dev);
 
                phy_dev = tmp->phy_dev;
+               if (!ns_capable(dev_net(phy_dev)->user_ns, CAP_NET_ADMIN))
+                       return -EPERM;
        } else if (!netif_is_ipvlan_port(phy_dev)) {
                /* Exit early if the underlying link is invalid or busy */
                if (phy_dev->type != ARPHRD_ETHER ||
@@ -781,7 +719,6 @@ static int ipvlan_device_event(struct notifier_block *unused,
 
        case NETDEV_REGISTER: {
                struct net *oldnet, *newnet = dev_net(dev);
-               struct ipvlan_netns *old_vnet;
 
                oldnet = read_pnet(&port->pnet);
                if (net_eq(newnet, oldnet))
@@ -789,12 +726,7 @@ static int ipvlan_device_event(struct notifier_block *unused,
 
                write_pnet(&port->pnet, newnet);
 
-               old_vnet = net_generic(oldnet, ipvlan_netid);
-               if (!old_vnet->ipvl_nf_hook_refcnt)
-                       break;
-
-               ipvlan_register_nf_hook(newnet);
-               ipvlan_unregister_nf_hook(oldnet);
+               ipvlan_migrate_l3s_hook(oldnet, newnet);
                break;
        }
        case NETDEV_UNREGISTER:
@@ -1068,23 +1000,6 @@ static struct notifier_block ipvlan_addr6_vtor_notifier_block __read_mostly = {
 };
 #endif
 
-static void ipvlan_ns_exit(struct net *net)
-{
-       struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid);
-
-       if (WARN_ON_ONCE(vnet->ipvl_nf_hook_refcnt)) {
-               vnet->ipvl_nf_hook_refcnt = 0;
-               nf_unregister_net_hooks(net, ipvl_nfops,
-                                       ARRAY_SIZE(ipvl_nfops));
-       }
-}
-
-static struct pernet_operations ipvlan_net_ops = {
-       .id = &ipvlan_netid,
-       .size = sizeof(struct ipvlan_netns),
-       .exit = ipvlan_ns_exit,
-};
-
 static int __init ipvlan_init_module(void)
 {
        int err;
@@ -1099,13 +1014,13 @@ static int __init ipvlan_init_module(void)
        register_inetaddr_notifier(&ipvlan_addr4_notifier_block);
        register_inetaddr_validator_notifier(&ipvlan_addr4_vtor_notifier_block);
 
-       err = register_pernet_subsys(&ipvlan_net_ops);
+       err = ipvlan_l3s_init();
        if (err < 0)
                goto error;
 
        err = ipvlan_link_register(&ipvlan_link_ops);
        if (err < 0) {
-               unregister_pernet_subsys(&ipvlan_net_ops);
+               ipvlan_l3s_cleanup();
                goto error;
        }
 
@@ -1126,7 +1041,7 @@ error:
 static void __exit ipvlan_cleanup_module(void)
 {
        rtnl_link_unregister(&ipvlan_link_ops);
-       unregister_pernet_subsys(&ipvlan_net_ops);
+       ipvlan_l3s_cleanup();
        unregister_netdevice_notifier(&ipvlan_notifier_block);
        unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block);
        unregister_inetaddr_validator_notifier(