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