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 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 */ 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 */ 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 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 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 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 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 */ 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 */ 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 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 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