Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /* Copyright (c) 2018, Intel Corporation. */
3 : :
4 : : /* A common module to handle registrations and notifications for paravirtual
5 : : * drivers to enable accelerated datapath and support VF live migration.
6 : : *
7 : : * The notifier and event handling code is based on netvsc driver.
8 : : */
9 : :
10 : : #include <linux/module.h>
11 : : #include <linux/etherdevice.h>
12 : : #include <uapi/linux/if_arp.h>
13 : : #include <linux/rtnetlink.h>
14 : : #include <linux/if_vlan.h>
15 : : #include <net/failover.h>
16 : :
17 : : static LIST_HEAD(failover_list);
18 : : static DEFINE_SPINLOCK(failover_lock);
19 : :
20 : 3 : static struct net_device *failover_get_bymac(u8 *mac, struct failover_ops **ops)
21 : : {
22 : 3 : struct net_device *failover_dev;
23 : 3 : struct failover *failover;
24 : :
25 : 3 : spin_lock(&failover_lock);
26 [ - + ]: 3 : list_for_each_entry(failover, &failover_list, list) {
27 : 0 : failover_dev = rtnl_dereference(failover->failover_dev);
28 [ # # ]: 0 : if (ether_addr_equal(failover_dev->perm_addr, mac)) {
29 : 0 : *ops = rtnl_dereference(failover->ops);
30 : 0 : spin_unlock(&failover_lock);
31 : 0 : return failover_dev;
32 : : }
33 : : }
34 : 3 : spin_unlock(&failover_lock);
35 : 3 : return NULL;
36 : : }
37 : :
38 : : /**
39 : : * failover_slave_register - Register a slave netdev
40 : : *
41 : : * @slave_dev: slave netdev that is being registered
42 : : *
43 : : * Registers a slave device to a failover instance. Only ethernet devices
44 : : * are supported.
45 : : */
46 : 9 : static int failover_slave_register(struct net_device *slave_dev)
47 : : {
48 : 9 : struct netdev_lag_upper_info lag_upper_info;
49 : 9 : struct net_device *failover_dev;
50 : 9 : struct failover_ops *fops;
51 : 9 : int err;
52 : :
53 [ + + ]: 9 : if (slave_dev->type != ARPHRD_ETHER)
54 : 6 : goto done;
55 : :
56 [ - + - - ]: 3 : ASSERT_RTNL();
57 : :
58 : 3 : failover_dev = failover_get_bymac(slave_dev->perm_addr, &fops);
59 [ + - ]: 3 : if (!failover_dev)
60 : 3 : goto done;
61 : :
62 [ # # # # : 0 : if (fops && fops->slave_pre_register &&
# # ]
63 : 0 : fops->slave_pre_register(slave_dev, failover_dev))
64 : 0 : goto done;
65 : :
66 : 0 : err = netdev_rx_handler_register(slave_dev, fops->slave_handle_frame,
67 : : failover_dev);
68 [ # # ]: 0 : if (err) {
69 : 0 : netdev_err(slave_dev, "can not register failover rx handler (err = %d)\n",
70 : : err);
71 : 0 : goto done;
72 : : }
73 : :
74 : 0 : lag_upper_info.tx_type = NETDEV_LAG_TX_TYPE_ACTIVEBACKUP;
75 : 0 : err = netdev_master_upper_dev_link(slave_dev, failover_dev, NULL,
76 : : &lag_upper_info, NULL);
77 [ # # ]: 0 : if (err) {
78 : 0 : netdev_err(slave_dev, "can not set failover device %s (err = %d)\n",
79 : 0 : failover_dev->name, err);
80 : 0 : goto err_upper_link;
81 : : }
82 : :
83 : 0 : slave_dev->priv_flags |= (IFF_FAILOVER_SLAVE | IFF_LIVE_RENAME_OK);
84 : :
85 [ # # # # : 0 : if (fops && fops->slave_register &&
# # ]
86 : 0 : !fops->slave_register(slave_dev, failover_dev))
87 : : return NOTIFY_OK;
88 : :
89 : 0 : netdev_upper_dev_unlink(slave_dev, failover_dev);
90 : 0 : slave_dev->priv_flags &= ~(IFF_FAILOVER_SLAVE | IFF_LIVE_RENAME_OK);
91 : 0 : err_upper_link:
92 : 0 : netdev_rx_handler_unregister(slave_dev);
93 : : done:
94 : : return NOTIFY_DONE;
95 : : }
96 : :
97 : : /**
98 : : * failover_slave_unregister - Unregister a slave netdev
99 : : *
100 : : * @slave_dev: slave netdev that is being unregistered
101 : : *
102 : : * Unregisters a slave device from a failover instance.
103 : : */
104 : 0 : int failover_slave_unregister(struct net_device *slave_dev)
105 : : {
106 : 0 : struct net_device *failover_dev;
107 : 0 : struct failover_ops *fops;
108 : :
109 [ # # ]: 0 : if (!netif_is_failover_slave(slave_dev))
110 : 0 : goto done;
111 : :
112 [ # # # # ]: 0 : ASSERT_RTNL();
113 : :
114 : 0 : failover_dev = failover_get_bymac(slave_dev->perm_addr, &fops);
115 [ # # ]: 0 : if (!failover_dev)
116 : 0 : goto done;
117 : :
118 [ # # # # : 0 : if (fops && fops->slave_pre_unregister &&
# # ]
119 : 0 : fops->slave_pre_unregister(slave_dev, failover_dev))
120 : 0 : goto done;
121 : :
122 : 0 : netdev_rx_handler_unregister(slave_dev);
123 : 0 : netdev_upper_dev_unlink(slave_dev, failover_dev);
124 : 0 : slave_dev->priv_flags &= ~(IFF_FAILOVER_SLAVE | IFF_LIVE_RENAME_OK);
125 : :
126 [ # # # # : 0 : if (fops && fops->slave_unregister &&
# # ]
127 : 0 : !fops->slave_unregister(slave_dev, failover_dev))
128 : 0 : return NOTIFY_OK;
129 : :
130 : 0 : done:
131 : : return NOTIFY_DONE;
132 : : }
133 : : EXPORT_SYMBOL_GPL(failover_slave_unregister);
134 : :
135 : 9 : static int failover_slave_link_change(struct net_device *slave_dev)
136 : : {
137 : 9 : struct net_device *failover_dev;
138 : 9 : struct failover_ops *fops;
139 : :
140 [ + - ]: 9 : if (!netif_is_failover_slave(slave_dev))
141 : 9 : goto done;
142 : :
143 [ # # # # ]: 0 : ASSERT_RTNL();
144 : :
145 : 0 : failover_dev = failover_get_bymac(slave_dev->perm_addr, &fops);
146 [ # # ]: 0 : if (!failover_dev)
147 : 0 : goto done;
148 : :
149 [ # # ]: 0 : if (!netif_running(failover_dev))
150 : 0 : goto done;
151 : :
152 [ # # # # : 0 : if (fops && fops->slave_link_change &&
# # ]
153 : 0 : !fops->slave_link_change(slave_dev, failover_dev))
154 : 0 : return NOTIFY_OK;
155 : :
156 : 0 : done:
157 : : return NOTIFY_DONE;
158 : : }
159 : :
160 : 0 : static int failover_slave_name_change(struct net_device *slave_dev)
161 : : {
162 : 0 : struct net_device *failover_dev;
163 : 0 : struct failover_ops *fops;
164 : :
165 [ # # ]: 0 : if (!netif_is_failover_slave(slave_dev))
166 : 0 : goto done;
167 : :
168 [ # # # # ]: 0 : ASSERT_RTNL();
169 : :
170 : 0 : failover_dev = failover_get_bymac(slave_dev->perm_addr, &fops);
171 [ # # ]: 0 : if (!failover_dev)
172 : 0 : goto done;
173 : :
174 [ # # ]: 0 : if (!netif_running(failover_dev))
175 : 0 : goto done;
176 : :
177 [ # # # # : 0 : if (fops && fops->slave_name_change &&
# # ]
178 : 0 : !fops->slave_name_change(slave_dev, failover_dev))
179 : 0 : return NOTIFY_OK;
180 : :
181 : 0 : done:
182 : : return NOTIFY_DONE;
183 : : }
184 : :
185 : : static int
186 : 30 : failover_event(struct notifier_block *this, unsigned long event, void *ptr)
187 : : {
188 [ + - ]: 30 : struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
189 : :
190 : : /* Skip parent events */
191 [ + - ]: 30 : if (netif_is_failover(event_dev))
192 : : return NOTIFY_DONE;
193 : :
194 [ + - + - : 30 : switch (event) {
+ ]
195 : 9 : case NETDEV_REGISTER:
196 : 9 : return failover_slave_register(event_dev);
197 : 0 : case NETDEV_UNREGISTER:
198 : 0 : return failover_slave_unregister(event_dev);
199 : 9 : case NETDEV_UP:
200 : : case NETDEV_DOWN:
201 : : case NETDEV_CHANGE:
202 : 9 : return failover_slave_link_change(event_dev);
203 : 0 : case NETDEV_CHANGENAME:
204 : 0 : return failover_slave_name_change(event_dev);
205 : : default:
206 : : return NOTIFY_DONE;
207 : : }
208 : : }
209 : :
210 : : static struct notifier_block failover_notifier = {
211 : : .notifier_call = failover_event,
212 : : };
213 : :
214 : : static void
215 : 0 : failover_existing_slave_register(struct net_device *failover_dev)
216 : : {
217 : 0 : struct net *net = dev_net(failover_dev);
218 : 0 : struct net_device *dev;
219 : :
220 : 0 : rtnl_lock();
221 [ # # ]: 0 : for_each_netdev(net, dev) {
222 [ # # ]: 0 : if (netif_is_failover(dev))
223 : 0 : continue;
224 [ # # ]: 0 : if (ether_addr_equal(failover_dev->perm_addr, dev->perm_addr))
225 : 0 : failover_slave_register(dev);
226 : : }
227 : 0 : rtnl_unlock();
228 : 0 : }
229 : :
230 : : /**
231 : : * failover_register - Register a failover instance
232 : : *
233 : : * @dev: failover netdev
234 : : * @ops: failover ops
235 : : *
236 : : * Allocate and register a failover instance for a failover netdev. ops
237 : : * provides handlers for slave device register/unregister/link change/
238 : : * name change events.
239 : : *
240 : : * Return: pointer to failover instance
241 : : */
242 : 0 : struct failover *failover_register(struct net_device *dev,
243 : : struct failover_ops *ops)
244 : : {
245 : 0 : struct failover *failover;
246 : :
247 [ # # ]: 0 : if (dev->type != ARPHRD_ETHER)
248 : : return ERR_PTR(-EINVAL);
249 : :
250 : 0 : failover = kzalloc(sizeof(*failover), GFP_KERNEL);
251 [ # # ]: 0 : if (!failover)
252 : : return ERR_PTR(-ENOMEM);
253 : :
254 : 0 : rcu_assign_pointer(failover->ops, ops);
255 : 0 : dev_hold(dev);
256 : 0 : dev->priv_flags |= IFF_FAILOVER;
257 : 0 : rcu_assign_pointer(failover->failover_dev, dev);
258 : :
259 : 0 : spin_lock(&failover_lock);
260 : 0 : list_add_tail(&failover->list, &failover_list);
261 : 0 : spin_unlock(&failover_lock);
262 : :
263 : 0 : netdev_info(dev, "failover master:%s registered\n", dev->name);
264 : :
265 : 0 : failover_existing_slave_register(dev);
266 : :
267 : 0 : return failover;
268 : : }
269 : : EXPORT_SYMBOL_GPL(failover_register);
270 : :
271 : : /**
272 : : * failover_unregister - Unregister a failover instance
273 : : *
274 : : * @failover: pointer to failover instance
275 : : *
276 : : * Unregisters and frees a failover instance.
277 : : */
278 : 0 : void failover_unregister(struct failover *failover)
279 : : {
280 : 0 : struct net_device *failover_dev;
281 : :
282 : 0 : failover_dev = rcu_dereference(failover->failover_dev);
283 : :
284 : 0 : netdev_info(failover_dev, "failover master:%s unregistered\n",
285 : 0 : failover_dev->name);
286 : :
287 : 0 : failover_dev->priv_flags &= ~IFF_FAILOVER;
288 : 0 : dev_put(failover_dev);
289 : :
290 : 0 : spin_lock(&failover_lock);
291 : 0 : list_del(&failover->list);
292 : 0 : spin_unlock(&failover_lock);
293 : :
294 : 0 : kfree(failover);
295 : 0 : }
296 : : EXPORT_SYMBOL_GPL(failover_unregister);
297 : :
298 : : static __init int
299 : 3 : failover_init(void)
300 : : {
301 : 3 : register_netdevice_notifier(&failover_notifier);
302 : :
303 : 3 : return 0;
304 : : }
305 : : module_init(failover_init);
306 : :
307 : : static __exit
308 : 0 : void failover_exit(void)
309 : : {
310 : 0 : unregister_netdevice_notifier(&failover_notifier);
311 : 0 : }
312 : : module_exit(failover_exit);
313 : :
314 : : MODULE_DESCRIPTION("Generic failover infrastructure/interface");
315 : : MODULE_LICENSE("GPL v2");
|