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

vport-netdev.c (4908B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2007-2012 Nicira, Inc.
      4 */
      5
      6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      7
      8#include <linux/if_arp.h>
      9#include <linux/if_bridge.h>
     10#include <linux/if_vlan.h>
     11#include <linux/kernel.h>
     12#include <linux/llc.h>
     13#include <linux/rtnetlink.h>
     14#include <linux/skbuff.h>
     15#include <linux/openvswitch.h>
     16#include <linux/export.h>
     17
     18#include <net/ip_tunnels.h>
     19#include <net/rtnetlink.h>
     20
     21#include "datapath.h"
     22#include "vport.h"
     23#include "vport-internal_dev.h"
     24#include "vport-netdev.h"
     25
     26static struct vport_ops ovs_netdev_vport_ops;
     27
     28/* Must be called with rcu_read_lock. */
     29static void netdev_port_receive(struct sk_buff *skb)
     30{
     31	struct vport *vport;
     32
     33	vport = ovs_netdev_get_vport(skb->dev);
     34	if (unlikely(!vport))
     35		goto error;
     36
     37	if (unlikely(skb_warn_if_lro(skb)))
     38		goto error;
     39
     40	/* Make our own copy of the packet.  Otherwise we will mangle the
     41	 * packet for anyone who came before us (e.g. tcpdump via AF_PACKET).
     42	 */
     43	skb = skb_share_check(skb, GFP_ATOMIC);
     44	if (unlikely(!skb))
     45		return;
     46
     47	if (skb->dev->type == ARPHRD_ETHER)
     48		skb_push_rcsum(skb, ETH_HLEN);
     49
     50	ovs_vport_receive(vport, skb, skb_tunnel_info(skb));
     51	return;
     52error:
     53	kfree_skb(skb);
     54}
     55
     56/* Called with rcu_read_lock and bottom-halves disabled. */
     57static rx_handler_result_t netdev_frame_hook(struct sk_buff **pskb)
     58{
     59	struct sk_buff *skb = *pskb;
     60
     61	if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
     62		return RX_HANDLER_PASS;
     63
     64	netdev_port_receive(skb);
     65	return RX_HANDLER_CONSUMED;
     66}
     67
     68static struct net_device *get_dpdev(const struct datapath *dp)
     69{
     70	struct vport *local;
     71
     72	local = ovs_vport_ovsl(dp, OVSP_LOCAL);
     73	return local->dev;
     74}
     75
     76struct vport *ovs_netdev_link(struct vport *vport, const char *name)
     77{
     78	int err;
     79
     80	vport->dev = dev_get_by_name(ovs_dp_get_net(vport->dp), name);
     81	if (!vport->dev) {
     82		err = -ENODEV;
     83		goto error_free_vport;
     84	}
     85	netdev_tracker_alloc(vport->dev, &vport->dev_tracker, GFP_KERNEL);
     86	if (vport->dev->flags & IFF_LOOPBACK ||
     87	    (vport->dev->type != ARPHRD_ETHER &&
     88	     vport->dev->type != ARPHRD_NONE) ||
     89	    ovs_is_internal_dev(vport->dev)) {
     90		err = -EINVAL;
     91		goto error_put;
     92	}
     93
     94	rtnl_lock();
     95	err = netdev_master_upper_dev_link(vport->dev,
     96					   get_dpdev(vport->dp),
     97					   NULL, NULL, NULL);
     98	if (err)
     99		goto error_unlock;
    100
    101	err = netdev_rx_handler_register(vport->dev, netdev_frame_hook,
    102					 vport);
    103	if (err)
    104		goto error_master_upper_dev_unlink;
    105
    106	dev_disable_lro(vport->dev);
    107	dev_set_promiscuity(vport->dev, 1);
    108	vport->dev->priv_flags |= IFF_OVS_DATAPATH;
    109	rtnl_unlock();
    110
    111	return vport;
    112
    113error_master_upper_dev_unlink:
    114	netdev_upper_dev_unlink(vport->dev, get_dpdev(vport->dp));
    115error_unlock:
    116	rtnl_unlock();
    117error_put:
    118	dev_put_track(vport->dev, &vport->dev_tracker);
    119error_free_vport:
    120	ovs_vport_free(vport);
    121	return ERR_PTR(err);
    122}
    123EXPORT_SYMBOL_GPL(ovs_netdev_link);
    124
    125static struct vport *netdev_create(const struct vport_parms *parms)
    126{
    127	struct vport *vport;
    128
    129	vport = ovs_vport_alloc(0, &ovs_netdev_vport_ops, parms);
    130	if (IS_ERR(vport))
    131		return vport;
    132
    133	return ovs_netdev_link(vport, parms->name);
    134}
    135
    136static void vport_netdev_free(struct rcu_head *rcu)
    137{
    138	struct vport *vport = container_of(rcu, struct vport, rcu);
    139
    140	dev_put_track(vport->dev, &vport->dev_tracker);
    141	ovs_vport_free(vport);
    142}
    143
    144void ovs_netdev_detach_dev(struct vport *vport)
    145{
    146	ASSERT_RTNL();
    147	vport->dev->priv_flags &= ~IFF_OVS_DATAPATH;
    148	netdev_rx_handler_unregister(vport->dev);
    149	netdev_upper_dev_unlink(vport->dev,
    150				netdev_master_upper_dev_get(vport->dev));
    151	dev_set_promiscuity(vport->dev, -1);
    152}
    153
    154static void netdev_destroy(struct vport *vport)
    155{
    156	rtnl_lock();
    157	if (netif_is_ovs_port(vport->dev))
    158		ovs_netdev_detach_dev(vport);
    159	rtnl_unlock();
    160
    161	call_rcu(&vport->rcu, vport_netdev_free);
    162}
    163
    164void ovs_netdev_tunnel_destroy(struct vport *vport)
    165{
    166	rtnl_lock();
    167	if (netif_is_ovs_port(vport->dev))
    168		ovs_netdev_detach_dev(vport);
    169
    170	/* We can be invoked by both explicit vport deletion and
    171	 * underlying netdev deregistration; delete the link only
    172	 * if it's not already shutting down.
    173	 */
    174	if (vport->dev->reg_state == NETREG_REGISTERED)
    175		rtnl_delete_link(vport->dev);
    176	dev_put_track(vport->dev, &vport->dev_tracker);
    177	vport->dev = NULL;
    178	rtnl_unlock();
    179
    180	call_rcu(&vport->rcu, vport_netdev_free);
    181}
    182EXPORT_SYMBOL_GPL(ovs_netdev_tunnel_destroy);
    183
    184/* Returns null if this device is not attached to a datapath. */
    185struct vport *ovs_netdev_get_vport(struct net_device *dev)
    186{
    187	if (likely(netif_is_ovs_port(dev)))
    188		return (struct vport *)
    189			rcu_dereference_rtnl(dev->rx_handler_data);
    190	else
    191		return NULL;
    192}
    193
    194static struct vport_ops ovs_netdev_vport_ops = {
    195	.type		= OVS_VPORT_TYPE_NETDEV,
    196	.create		= netdev_create,
    197	.destroy	= netdev_destroy,
    198	.send		= dev_queue_xmit,
    199};
    200
    201int __init ovs_netdev_init(void)
    202{
    203	return ovs_vport_ops_register(&ovs_netdev_vport_ops);
    204}
    205
    206void ovs_netdev_exit(void)
    207{
    208	ovs_vport_ops_unregister(&ovs_netdev_vport_ops);
    209}