xref: /linux/net/core/failover.c (revision 66182ca873a4e87b3496eca79d57f86b76d7f52d)
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