Commit | Line | Data |
---|---|---|
69204174 YO |
1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /* Copyright (c) 2019-2021 Marvell International Ltd. All rights reserved */ | |
3 | ||
4 | #include <linux/kernel.h> | |
5 | #include <linux/types.h> | |
da3c1639 | 6 | #include <linux/inetdevice.h> |
15fa9e8c | 7 | #include <net/switchdev.h> |
69204174 YO |
8 | |
9 | #include "prestera.h" | |
bca5859b | 10 | #include "prestera_router_hw.h" |
69204174 | 11 | |
15fa9e8c YO |
12 | /* This util to be used, to convert kernel rules for default vr in hw_vr */ |
13 | static u32 prestera_fix_tb_id(u32 tb_id) | |
14 | { | |
15 | if (tb_id == RT_TABLE_UNSPEC || | |
16 | tb_id == RT_TABLE_LOCAL || | |
17 | tb_id == RT_TABLE_DEFAULT) | |
18 | tb_id = RT_TABLE_MAIN; | |
19 | ||
20 | return tb_id; | |
21 | } | |
22 | ||
da3c1639 YO |
23 | static int __prestera_inetaddr_port_event(struct net_device *port_dev, |
24 | unsigned long event, | |
25 | struct netlink_ext_ack *extack) | |
26 | { | |
27 | struct prestera_port *port = netdev_priv(port_dev); | |
28 | int err; | |
15fa9e8c YO |
29 | struct prestera_rif_entry *re; |
30 | struct prestera_rif_entry_key re_key = {}; | |
31 | u32 kern_tb_id; | |
da3c1639 YO |
32 | |
33 | err = prestera_is_valid_mac_addr(port, port_dev->dev_addr); | |
34 | if (err) { | |
35 | NL_SET_ERR_MSG_MOD(extack, "RIF MAC must have the same prefix"); | |
36 | return err; | |
37 | } | |
38 | ||
15fa9e8c YO |
39 | kern_tb_id = l3mdev_fib_table(port_dev); |
40 | re_key.iface.type = PRESTERA_IF_PORT_E; | |
41 | re_key.iface.dev_port.hw_dev_num = port->dev_id; | |
42 | re_key.iface.dev_port.port_num = port->hw_id; | |
43 | re = prestera_rif_entry_find(port->sw, &re_key); | |
44 | ||
da3c1639 YO |
45 | switch (event) { |
46 | case NETDEV_UP: | |
15fa9e8c YO |
47 | if (re) { |
48 | NL_SET_ERR_MSG_MOD(extack, "rif_entry already exist"); | |
49 | return -EEXIST; | |
50 | } | |
51 | re = prestera_rif_entry_create(port->sw, &re_key, | |
52 | prestera_fix_tb_id(kern_tb_id), | |
53 | port_dev->dev_addr); | |
54 | if (!re) { | |
55 | NL_SET_ERR_MSG_MOD(extack, "Can't create rif_entry"); | |
56 | return -EINVAL; | |
57 | } | |
58 | dev_hold(port_dev); | |
59 | break; | |
da3c1639 | 60 | case NETDEV_DOWN: |
15fa9e8c YO |
61 | if (!re) { |
62 | NL_SET_ERR_MSG_MOD(extack, "rif_entry not exist"); | |
63 | return -EEXIST; | |
64 | } | |
65 | prestera_rif_entry_destroy(port->sw, re); | |
66 | dev_put(port_dev); | |
da3c1639 YO |
67 | break; |
68 | } | |
69 | ||
70 | return 0; | |
71 | } | |
72 | ||
73 | static int __prestera_inetaddr_event(struct prestera_switch *sw, | |
74 | struct net_device *dev, | |
75 | unsigned long event, | |
76 | struct netlink_ext_ack *extack) | |
77 | { | |
78 | if (prestera_netdev_check(dev) && !netif_is_bridge_port(dev) && | |
79 | !netif_is_lag_port(dev) && !netif_is_ovs_port(dev)) | |
80 | return __prestera_inetaddr_port_event(dev, event, extack); | |
81 | ||
82 | return 0; | |
83 | } | |
84 | ||
85 | static int __prestera_inetaddr_cb(struct notifier_block *nb, | |
86 | unsigned long event, void *ptr) | |
87 | { | |
88 | struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; | |
89 | struct net_device *dev = ifa->ifa_dev->dev; | |
90 | struct prestera_router *router = container_of(nb, | |
91 | struct prestera_router, | |
92 | inetaddr_nb); | |
93 | struct in_device *idev; | |
94 | int err = 0; | |
95 | ||
96 | if (event != NETDEV_DOWN) | |
97 | goto out; | |
98 | ||
99 | /* Ignore if this is not latest address */ | |
100 | idev = __in_dev_get_rtnl(dev); | |
101 | if (idev && idev->ifa_list) | |
102 | goto out; | |
103 | ||
104 | err = __prestera_inetaddr_event(router->sw, dev, event, NULL); | |
105 | out: | |
106 | return notifier_from_errno(err); | |
107 | } | |
108 | ||
109 | static int __prestera_inetaddr_valid_cb(struct notifier_block *nb, | |
110 | unsigned long event, void *ptr) | |
111 | { | |
112 | struct in_validator_info *ivi = (struct in_validator_info *)ptr; | |
113 | struct net_device *dev = ivi->ivi_dev->dev; | |
114 | struct prestera_router *router = container_of(nb, | |
115 | struct prestera_router, | |
116 | inetaddr_valid_nb); | |
117 | struct in_device *idev; | |
118 | int err = 0; | |
119 | ||
120 | if (event != NETDEV_UP) | |
121 | goto out; | |
122 | ||
123 | /* Ignore if this is not first address */ | |
124 | idev = __in_dev_get_rtnl(dev); | |
125 | if (idev && idev->ifa_list) | |
126 | goto out; | |
127 | ||
128 | if (ipv4_is_multicast(ivi->ivi_addr)) { | |
129 | err = -EINVAL; | |
130 | goto out; | |
131 | } | |
132 | ||
133 | err = __prestera_inetaddr_event(router->sw, dev, event, ivi->extack); | |
134 | out: | |
135 | return notifier_from_errno(err); | |
136 | } | |
137 | ||
69204174 YO |
138 | int prestera_router_init(struct prestera_switch *sw) |
139 | { | |
140 | struct prestera_router *router; | |
bca5859b | 141 | int err; |
69204174 YO |
142 | |
143 | router = kzalloc(sizeof(*sw->router), GFP_KERNEL); | |
144 | if (!router) | |
145 | return -ENOMEM; | |
146 | ||
147 | sw->router = router; | |
148 | router->sw = sw; | |
149 | ||
bca5859b YO |
150 | err = prestera_router_hw_init(sw); |
151 | if (err) | |
152 | goto err_router_lib_init; | |
153 | ||
da3c1639 YO |
154 | router->inetaddr_valid_nb.notifier_call = __prestera_inetaddr_valid_cb; |
155 | err = register_inetaddr_validator_notifier(&router->inetaddr_valid_nb); | |
156 | if (err) | |
157 | goto err_register_inetaddr_validator_notifier; | |
158 | ||
159 | router->inetaddr_nb.notifier_call = __prestera_inetaddr_cb; | |
160 | err = register_inetaddr_notifier(&router->inetaddr_nb); | |
161 | if (err) | |
162 | goto err_register_inetaddr_notifier; | |
163 | ||
69204174 | 164 | return 0; |
bca5859b | 165 | |
da3c1639 YO |
166 | err_register_inetaddr_notifier: |
167 | unregister_inetaddr_validator_notifier(&router->inetaddr_valid_nb); | |
168 | err_register_inetaddr_validator_notifier: | |
169 | /* prestera_router_hw_fini */ | |
bca5859b YO |
170 | err_router_lib_init: |
171 | kfree(sw->router); | |
172 | return err; | |
69204174 YO |
173 | } |
174 | ||
175 | void prestera_router_fini(struct prestera_switch *sw) | |
176 | { | |
da3c1639 YO |
177 | unregister_inetaddr_notifier(&sw->router->inetaddr_nb); |
178 | unregister_inetaddr_validator_notifier(&sw->router->inetaddr_valid_nb); | |
179 | /* router_hw_fini */ | |
69204174 YO |
180 | kfree(sw->router); |
181 | sw->router = NULL; | |
182 | } |