cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

failover.c (7685B)


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