LCOV - code coverage report
Current view: top level - net/core - failover.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 34 150 22.7 %
Date: 2021-04-22 12:43:58 Functions: 5 11 45.5 %

          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           1 : static struct net_device *failover_get_bymac(u8 *mac, struct failover_ops **ops)
      21             : {
      22           1 :         struct net_device *failover_dev;
      23           1 :         struct failover *failover;
      24             : 
      25           1 :         spin_lock(&failover_lock);
      26           1 :         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           1 :         spin_unlock(&failover_lock);
      35           1 :         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           2 : static int failover_slave_register(struct net_device *slave_dev)
      47             : {
      48           2 :         struct netdev_lag_upper_info lag_upper_info;
      49           2 :         struct net_device *failover_dev;
      50           2 :         struct failover_ops *fops;
      51           2 :         int err;
      52             : 
      53           2 :         if (slave_dev->type != ARPHRD_ETHER)
      54           1 :                 goto done;
      55             : 
      56           1 :         ASSERT_RTNL();
      57             : 
      58           1 :         failover_dev = failover_get_bymac(slave_dev->perm_addr, &fops);
      59           1 :         if (!failover_dev)
      60           1 :                 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           2 : static int failover_slave_link_change(struct net_device *slave_dev)
     136             : {
     137           2 :         struct net_device *failover_dev;
     138           2 :         struct failover_ops *fops;
     139             : 
     140           2 :         if (!netif_is_failover_slave(slave_dev))
     141           2 :                 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           6 : failover_event(struct notifier_block *this, unsigned long event, void *ptr)
     187             : {
     188           6 :         struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
     189             : 
     190             :         /* Skip parent events */
     191           6 :         if (netif_is_failover(event_dev))
     192             :                 return NOTIFY_DONE;
     193             : 
     194           6 :         switch (event) {
     195           2 :         case NETDEV_REGISTER:
     196           2 :                 return failover_slave_register(event_dev);
     197           0 :         case NETDEV_UNREGISTER:
     198           0 :                 return failover_slave_unregister(event_dev);
     199           2 :         case NETDEV_UP:
     200             :         case NETDEV_DOWN:
     201             :         case NETDEV_CHANGE:
     202           2 :                 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           0 :                 return ERR_PTR(-EINVAL);
     249             : 
     250           0 :         failover = kzalloc(sizeof(*failover), GFP_KERNEL);
     251           0 :         if (!failover)
     252           0 :                 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           1 : failover_init(void)
     300             : {
     301           1 :         register_netdevice_notifier(&failover_notifier);
     302             : 
     303           1 :         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");

Generated by: LCOV version 1.14