.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* Copyright (c) 2014 Mahesh Bandewar <maheshb@google.com> |
---|
2 | | - * |
---|
3 | | - * This program is free software; you can redistribute it and/or |
---|
4 | | - * modify it under the terms of the GNU General Public License as |
---|
5 | | - * published by the Free Software Foundation; either version 2 of |
---|
6 | | - * the License, or (at your option) any later version. |
---|
7 | | - * |
---|
8 | 3 | */ |
---|
9 | 4 | |
---|
10 | 5 | #include "ipvlan.h" |
---|
11 | 6 | |
---|
12 | | -static unsigned int ipvlan_netid __read_mostly; |
---|
13 | | - |
---|
14 | | -struct ipvlan_netns { |
---|
15 | | - unsigned int ipvl_nf_hook_refcnt; |
---|
16 | | -}; |
---|
17 | | - |
---|
18 | | -static const struct nf_hook_ops ipvl_nfops[] = { |
---|
19 | | - { |
---|
20 | | - .hook = ipvlan_nf_input, |
---|
21 | | - .pf = NFPROTO_IPV4, |
---|
22 | | - .hooknum = NF_INET_LOCAL_IN, |
---|
23 | | - .priority = INT_MAX, |
---|
24 | | - }, |
---|
25 | | -#if IS_ENABLED(CONFIG_IPV6) |
---|
26 | | - { |
---|
27 | | - .hook = ipvlan_nf_input, |
---|
28 | | - .pf = NFPROTO_IPV6, |
---|
29 | | - .hooknum = NF_INET_LOCAL_IN, |
---|
30 | | - .priority = INT_MAX, |
---|
31 | | - }, |
---|
32 | | -#endif |
---|
33 | | -}; |
---|
34 | | - |
---|
35 | | -static const struct l3mdev_ops ipvl_l3mdev_ops = { |
---|
36 | | - .l3mdev_l3_rcv = ipvlan_l3_rcv, |
---|
37 | | -}; |
---|
38 | | - |
---|
39 | | -static void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev) |
---|
40 | | -{ |
---|
41 | | - ipvlan->dev->mtu = dev->mtu; |
---|
42 | | -} |
---|
43 | | - |
---|
44 | | -static int ipvlan_register_nf_hook(struct net *net) |
---|
45 | | -{ |
---|
46 | | - struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid); |
---|
47 | | - int err = 0; |
---|
48 | | - |
---|
49 | | - if (!vnet->ipvl_nf_hook_refcnt) { |
---|
50 | | - err = nf_register_net_hooks(net, ipvl_nfops, |
---|
51 | | - ARRAY_SIZE(ipvl_nfops)); |
---|
52 | | - if (!err) |
---|
53 | | - vnet->ipvl_nf_hook_refcnt = 1; |
---|
54 | | - } else { |
---|
55 | | - vnet->ipvl_nf_hook_refcnt++; |
---|
56 | | - } |
---|
57 | | - |
---|
58 | | - return err; |
---|
59 | | -} |
---|
60 | | - |
---|
61 | | -static void ipvlan_unregister_nf_hook(struct net *net) |
---|
62 | | -{ |
---|
63 | | - struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid); |
---|
64 | | - |
---|
65 | | - if (WARN_ON(!vnet->ipvl_nf_hook_refcnt)) |
---|
66 | | - return; |
---|
67 | | - |
---|
68 | | - vnet->ipvl_nf_hook_refcnt--; |
---|
69 | | - if (!vnet->ipvl_nf_hook_refcnt) |
---|
70 | | - nf_unregister_net_hooks(net, ipvl_nfops, |
---|
71 | | - ARRAY_SIZE(ipvl_nfops)); |
---|
72 | | -} |
---|
73 | | - |
---|
74 | | -static int ipvlan_set_port_mode(struct ipvl_port *port, u16 nval) |
---|
| 7 | +static int ipvlan_set_port_mode(struct ipvl_port *port, u16 nval, |
---|
| 8 | + struct netlink_ext_ack *extack) |
---|
75 | 9 | { |
---|
76 | 10 | struct ipvl_dev *ipvlan; |
---|
77 | | - struct net_device *mdev = port->dev; |
---|
78 | 11 | unsigned int flags; |
---|
79 | 12 | int err; |
---|
80 | 13 | |
---|
.. | .. |
---|
84 | 17 | flags = ipvlan->dev->flags; |
---|
85 | 18 | if (nval == IPVLAN_MODE_L3 || nval == IPVLAN_MODE_L3S) { |
---|
86 | 19 | err = dev_change_flags(ipvlan->dev, |
---|
87 | | - flags | IFF_NOARP); |
---|
| 20 | + flags | IFF_NOARP, |
---|
| 21 | + extack); |
---|
88 | 22 | } else { |
---|
89 | 23 | err = dev_change_flags(ipvlan->dev, |
---|
90 | | - flags & ~IFF_NOARP); |
---|
| 24 | + flags & ~IFF_NOARP, |
---|
| 25 | + extack); |
---|
91 | 26 | } |
---|
92 | 27 | if (unlikely(err)) |
---|
93 | 28 | goto fail; |
---|
94 | 29 | } |
---|
95 | 30 | if (nval == IPVLAN_MODE_L3S) { |
---|
96 | 31 | /* New mode is L3S */ |
---|
97 | | - err = ipvlan_register_nf_hook(read_pnet(&port->pnet)); |
---|
98 | | - if (!err) { |
---|
99 | | - mdev->l3mdev_ops = &ipvl_l3mdev_ops; |
---|
100 | | - mdev->priv_flags |= IFF_L3MDEV_RX_HANDLER; |
---|
101 | | - } else |
---|
| 32 | + err = ipvlan_l3s_register(port); |
---|
| 33 | + if (err) |
---|
102 | 34 | goto fail; |
---|
103 | 35 | } else if (port->mode == IPVLAN_MODE_L3S) { |
---|
104 | 36 | /* Old mode was L3S */ |
---|
105 | | - mdev->priv_flags &= ~IFF_L3MDEV_RX_HANDLER; |
---|
106 | | - ipvlan_unregister_nf_hook(read_pnet(&port->pnet)); |
---|
107 | | - mdev->l3mdev_ops = NULL; |
---|
| 37 | + ipvlan_l3s_unregister(port); |
---|
108 | 38 | } |
---|
109 | 39 | port->mode = nval; |
---|
110 | 40 | } |
---|
.. | .. |
---|
116 | 46 | flags = ipvlan->dev->flags; |
---|
117 | 47 | if (port->mode == IPVLAN_MODE_L3 || |
---|
118 | 48 | port->mode == IPVLAN_MODE_L3S) |
---|
119 | | - dev_change_flags(ipvlan->dev, flags | IFF_NOARP); |
---|
| 49 | + dev_change_flags(ipvlan->dev, flags | IFF_NOARP, |
---|
| 50 | + NULL); |
---|
120 | 51 | else |
---|
121 | | - dev_change_flags(ipvlan->dev, flags & ~IFF_NOARP); |
---|
| 52 | + dev_change_flags(ipvlan->dev, flags & ~IFF_NOARP, |
---|
| 53 | + NULL); |
---|
122 | 54 | } |
---|
123 | 55 | |
---|
124 | 56 | return err; |
---|
.. | .. |
---|
161 | 93 | struct ipvl_port *port = ipvlan_port_get_rtnl(dev); |
---|
162 | 94 | struct sk_buff *skb; |
---|
163 | 95 | |
---|
164 | | - if (port->mode == IPVLAN_MODE_L3S) { |
---|
165 | | - dev->priv_flags &= ~IFF_L3MDEV_RX_HANDLER; |
---|
166 | | - ipvlan_unregister_nf_hook(dev_net(dev)); |
---|
167 | | - dev->l3mdev_ops = NULL; |
---|
168 | | - } |
---|
| 96 | + if (port->mode == IPVLAN_MODE_L3S) |
---|
| 97 | + ipvlan_l3s_unregister(port); |
---|
169 | 98 | netdev_rx_handler_unregister(dev); |
---|
170 | 99 | cancel_work_sync(&port->wq); |
---|
171 | 100 | while ((skb = __skb_dequeue(&port->backlog)) != NULL) { |
---|
.. | .. |
---|
186 | 115 | |
---|
187 | 116 | #define IPVLAN_FEATURES \ |
---|
188 | 117 | (NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \ |
---|
189 | | - NETIF_F_GSO | NETIF_F_TSO | NETIF_F_GSO_ROBUST | \ |
---|
190 | | - NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO | NETIF_F_RXCSUM | \ |
---|
| 118 | + NETIF_F_GSO | NETIF_F_ALL_TSO | NETIF_F_GSO_ROBUST | \ |
---|
| 119 | + NETIF_F_GRO | NETIF_F_RXCSUM | \ |
---|
191 | 120 | NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_STAG_FILTER) |
---|
192 | 121 | |
---|
193 | 122 | /* NETIF_F_GSO_ENCAP_ALL NETIF_F_GSO_SOFTWARE Newly added */ |
---|
.. | .. |
---|
208 | 137 | dev->features |= IPVLAN_ALWAYS_ON; |
---|
209 | 138 | dev->vlan_features = phy_dev->vlan_features & IPVLAN_FEATURES; |
---|
210 | 139 | dev->vlan_features |= IPVLAN_ALWAYS_ON_OFLOADS; |
---|
| 140 | + dev->hw_enc_features |= dev->features; |
---|
211 | 141 | dev->gso_max_size = phy_dev->gso_max_size; |
---|
212 | 142 | dev->gso_max_segs = phy_dev->gso_max_segs; |
---|
213 | 143 | dev->hard_header_len = phy_dev->hard_header_len; |
---|
.. | .. |
---|
456 | 386 | .cache_update = eth_header_cache_update, |
---|
457 | 387 | }; |
---|
458 | 388 | |
---|
| 389 | +static void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev) |
---|
| 390 | +{ |
---|
| 391 | + ipvlan->dev->mtu = dev->mtu; |
---|
| 392 | +} |
---|
| 393 | + |
---|
459 | 394 | static bool netif_is_ipvlan(const struct net_device *dev) |
---|
460 | 395 | { |
---|
461 | 396 | /* both ipvlan and ipvtap devices use the same netdev_ops */ |
---|
.. | .. |
---|
515 | 450 | if (data[IFLA_IPVLAN_MODE]) { |
---|
516 | 451 | u16 nmode = nla_get_u16(data[IFLA_IPVLAN_MODE]); |
---|
517 | 452 | |
---|
518 | | - err = ipvlan_set_port_mode(port, nmode); |
---|
| 453 | + err = ipvlan_set_port_mode(port, nmode, extack); |
---|
519 | 454 | } |
---|
520 | 455 | |
---|
521 | 456 | if (!err && data[IFLA_IPVLAN_FLAGS]) { |
---|
.. | .. |
---|
552 | 487 | if (data[IFLA_IPVLAN_MODE]) { |
---|
553 | 488 | u16 mode = nla_get_u16(data[IFLA_IPVLAN_MODE]); |
---|
554 | 489 | |
---|
555 | | - if (mode < IPVLAN_MODE_L2 || mode >= IPVLAN_MODE_MAX) |
---|
| 490 | + if (mode >= IPVLAN_MODE_MAX) |
---|
556 | 491 | return -EINVAL; |
---|
557 | 492 | } |
---|
558 | 493 | if (data[IFLA_IPVLAN_FLAGS]) { |
---|
.. | .. |
---|
691 | 626 | if (data && data[IFLA_IPVLAN_MODE]) |
---|
692 | 627 | mode = nla_get_u16(data[IFLA_IPVLAN_MODE]); |
---|
693 | 628 | |
---|
694 | | - err = ipvlan_set_port_mode(port, mode); |
---|
| 629 | + err = ipvlan_set_port_mode(port, mode, extack); |
---|
695 | 630 | if (err) |
---|
696 | 631 | goto unlink_netdev; |
---|
697 | 632 | |
---|
.. | .. |
---|
749 | 684 | [IFLA_IPVLAN_FLAGS] = { .type = NLA_U16 }, |
---|
750 | 685 | }; |
---|
751 | 686 | |
---|
| 687 | +static struct net *ipvlan_get_link_net(const struct net_device *dev) |
---|
| 688 | +{ |
---|
| 689 | + struct ipvl_dev *ipvlan = netdev_priv(dev); |
---|
| 690 | + |
---|
| 691 | + return dev_net(ipvlan->phy_dev); |
---|
| 692 | +} |
---|
| 693 | + |
---|
752 | 694 | static struct rtnl_link_ops ipvlan_link_ops = { |
---|
753 | 695 | .kind = "ipvlan", |
---|
754 | 696 | .priv_size = sizeof(struct ipvl_dev), |
---|
.. | .. |
---|
756 | 698 | .setup = ipvlan_link_setup, |
---|
757 | 699 | .newlink = ipvlan_link_new, |
---|
758 | 700 | .dellink = ipvlan_link_delete, |
---|
| 701 | + .get_link_net = ipvlan_get_link_net, |
---|
759 | 702 | }; |
---|
760 | 703 | |
---|
761 | 704 | int ipvlan_link_register(struct rtnl_link_ops *ops) |
---|
.. | .. |
---|
773 | 716 | static int ipvlan_device_event(struct notifier_block *unused, |
---|
774 | 717 | unsigned long event, void *ptr) |
---|
775 | 718 | { |
---|
| 719 | + struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(ptr); |
---|
| 720 | + struct netdev_notifier_pre_changeaddr_info *prechaddr_info; |
---|
776 | 721 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
---|
777 | 722 | struct ipvl_dev *ipvlan, *next; |
---|
778 | 723 | struct ipvl_port *port; |
---|
779 | 724 | LIST_HEAD(lst_kill); |
---|
| 725 | + int err; |
---|
780 | 726 | |
---|
781 | 727 | if (!netif_is_ipvlan_port(dev)) |
---|
782 | 728 | return NOTIFY_DONE; |
---|
.. | .. |
---|
792 | 738 | |
---|
793 | 739 | case NETDEV_REGISTER: { |
---|
794 | 740 | struct net *oldnet, *newnet = dev_net(dev); |
---|
795 | | - struct ipvlan_netns *old_vnet; |
---|
796 | 741 | |
---|
797 | 742 | oldnet = read_pnet(&port->pnet); |
---|
798 | 743 | if (net_eq(newnet, oldnet)) |
---|
.. | .. |
---|
800 | 745 | |
---|
801 | 746 | write_pnet(&port->pnet, newnet); |
---|
802 | 747 | |
---|
803 | | - old_vnet = net_generic(oldnet, ipvlan_netid); |
---|
804 | | - if (!old_vnet->ipvl_nf_hook_refcnt) |
---|
805 | | - break; |
---|
806 | | - |
---|
807 | | - ipvlan_register_nf_hook(newnet); |
---|
808 | | - ipvlan_unregister_nf_hook(oldnet); |
---|
| 748 | + ipvlan_migrate_l3s_hook(oldnet, newnet); |
---|
809 | 749 | break; |
---|
810 | 750 | } |
---|
811 | 751 | case NETDEV_UNREGISTER: |
---|
.. | .. |
---|
829 | 769 | case NETDEV_CHANGEMTU: |
---|
830 | 770 | list_for_each_entry(ipvlan, &port->ipvlans, pnode) |
---|
831 | 771 | ipvlan_adjust_mtu(ipvlan, dev); |
---|
| 772 | + break; |
---|
| 773 | + |
---|
| 774 | + case NETDEV_PRE_CHANGEADDR: |
---|
| 775 | + prechaddr_info = ptr; |
---|
| 776 | + list_for_each_entry(ipvlan, &port->ipvlans, pnode) { |
---|
| 777 | + err = dev_pre_changeaddr_notify(ipvlan->dev, |
---|
| 778 | + prechaddr_info->dev_addr, |
---|
| 779 | + extack); |
---|
| 780 | + if (err) |
---|
| 781 | + return notifier_from_errno(err); |
---|
| 782 | + } |
---|
832 | 783 | break; |
---|
833 | 784 | |
---|
834 | 785 | case NETDEV_CHANGEADDR: |
---|
.. | .. |
---|
1067 | 1018 | }; |
---|
1068 | 1019 | #endif |
---|
1069 | 1020 | |
---|
1070 | | -static void ipvlan_ns_exit(struct net *net) |
---|
1071 | | -{ |
---|
1072 | | - struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid); |
---|
1073 | | - |
---|
1074 | | - if (WARN_ON_ONCE(vnet->ipvl_nf_hook_refcnt)) { |
---|
1075 | | - vnet->ipvl_nf_hook_refcnt = 0; |
---|
1076 | | - nf_unregister_net_hooks(net, ipvl_nfops, |
---|
1077 | | - ARRAY_SIZE(ipvl_nfops)); |
---|
1078 | | - } |
---|
1079 | | -} |
---|
1080 | | - |
---|
1081 | | -static struct pernet_operations ipvlan_net_ops = { |
---|
1082 | | - .id = &ipvlan_netid, |
---|
1083 | | - .size = sizeof(struct ipvlan_netns), |
---|
1084 | | - .exit = ipvlan_ns_exit, |
---|
1085 | | -}; |
---|
1086 | | - |
---|
1087 | 1021 | static int __init ipvlan_init_module(void) |
---|
1088 | 1022 | { |
---|
1089 | 1023 | int err; |
---|
.. | .. |
---|
1098 | 1032 | register_inetaddr_notifier(&ipvlan_addr4_notifier_block); |
---|
1099 | 1033 | register_inetaddr_validator_notifier(&ipvlan_addr4_vtor_notifier_block); |
---|
1100 | 1034 | |
---|
1101 | | - err = register_pernet_subsys(&ipvlan_net_ops); |
---|
| 1035 | + err = ipvlan_l3s_init(); |
---|
1102 | 1036 | if (err < 0) |
---|
1103 | 1037 | goto error; |
---|
1104 | 1038 | |
---|
1105 | 1039 | err = ipvlan_link_register(&ipvlan_link_ops); |
---|
1106 | 1040 | if (err < 0) { |
---|
1107 | | - unregister_pernet_subsys(&ipvlan_net_ops); |
---|
| 1041 | + ipvlan_l3s_cleanup(); |
---|
1108 | 1042 | goto error; |
---|
1109 | 1043 | } |
---|
1110 | 1044 | |
---|
.. | .. |
---|
1125 | 1059 | static void __exit ipvlan_cleanup_module(void) |
---|
1126 | 1060 | { |
---|
1127 | 1061 | rtnl_link_unregister(&ipvlan_link_ops); |
---|
1128 | | - unregister_pernet_subsys(&ipvlan_net_ops); |
---|
| 1062 | + ipvlan_l3s_cleanup(); |
---|
1129 | 1063 | unregister_netdevice_notifier(&ipvlan_notifier_block); |
---|
1130 | 1064 | unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block); |
---|
1131 | 1065 | unregister_inetaddr_validator_notifier( |
---|