LCOV - code coverage report
Current view: top level - net/core - failover.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 23 148 15.5 %
Date: 2022-04-01 14:17:54 Functions: 4 11 36.4 %
Branches: 7 99 7.1 %

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