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

ipvlan_l3s.c (4583B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/* Copyright (c) 2014 Mahesh Bandewar <maheshb@google.com>
      3 */
      4
      5#include "ipvlan.h"
      6
      7static unsigned int ipvlan_netid __read_mostly;
      8
      9struct ipvlan_netns {
     10	unsigned int ipvl_nf_hook_refcnt;
     11};
     12
     13static struct ipvl_addr *ipvlan_skb_to_addr(struct sk_buff *skb,
     14					    struct net_device *dev)
     15{
     16	struct ipvl_addr *addr = NULL;
     17	struct ipvl_port *port;
     18	int addr_type;
     19	void *lyr3h;
     20
     21	if (!dev || !netif_is_ipvlan_port(dev))
     22		goto out;
     23
     24	port = ipvlan_port_get_rcu(dev);
     25	if (!port || port->mode != IPVLAN_MODE_L3S)
     26		goto out;
     27
     28	lyr3h = ipvlan_get_L3_hdr(port, skb, &addr_type);
     29	if (!lyr3h)
     30		goto out;
     31
     32	addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true);
     33out:
     34	return addr;
     35}
     36
     37static struct sk_buff *ipvlan_l3_rcv(struct net_device *dev,
     38				     struct sk_buff *skb, u16 proto)
     39{
     40	struct ipvl_addr *addr;
     41	struct net_device *sdev;
     42
     43	addr = ipvlan_skb_to_addr(skb, dev);
     44	if (!addr)
     45		goto out;
     46
     47	sdev = addr->master->dev;
     48	switch (proto) {
     49	case AF_INET:
     50	{
     51		struct iphdr *ip4h = ip_hdr(skb);
     52		int err;
     53
     54		err = ip_route_input_noref(skb, ip4h->daddr, ip4h->saddr,
     55					   ip4h->tos, sdev);
     56		if (unlikely(err))
     57			goto out;
     58		break;
     59	}
     60#if IS_ENABLED(CONFIG_IPV6)
     61	case AF_INET6:
     62	{
     63		struct dst_entry *dst;
     64		struct ipv6hdr *ip6h = ipv6_hdr(skb);
     65		int flags = RT6_LOOKUP_F_HAS_SADDR;
     66		struct flowi6 fl6 = {
     67			.flowi6_iif   = sdev->ifindex,
     68			.daddr        = ip6h->daddr,
     69			.saddr        = ip6h->saddr,
     70			.flowlabel    = ip6_flowinfo(ip6h),
     71			.flowi6_mark  = skb->mark,
     72			.flowi6_proto = ip6h->nexthdr,
     73		};
     74
     75		skb_dst_drop(skb);
     76		dst = ip6_route_input_lookup(dev_net(sdev), sdev, &fl6,
     77					     skb, flags);
     78		skb_dst_set(skb, dst);
     79		break;
     80	}
     81#endif
     82	default:
     83		break;
     84	}
     85out:
     86	return skb;
     87}
     88
     89static const struct l3mdev_ops ipvl_l3mdev_ops = {
     90	.l3mdev_l3_rcv = ipvlan_l3_rcv,
     91};
     92
     93static unsigned int ipvlan_nf_input(void *priv, struct sk_buff *skb,
     94				    const struct nf_hook_state *state)
     95{
     96	struct ipvl_addr *addr;
     97	unsigned int len;
     98
     99	addr = ipvlan_skb_to_addr(skb, skb->dev);
    100	if (!addr)
    101		goto out;
    102
    103	skb->dev = addr->master->dev;
    104	len = skb->len + ETH_HLEN;
    105	ipvlan_count_rx(addr->master, len, true, false);
    106out:
    107	return NF_ACCEPT;
    108}
    109
    110static const struct nf_hook_ops ipvl_nfops[] = {
    111	{
    112		.hook     = ipvlan_nf_input,
    113		.pf       = NFPROTO_IPV4,
    114		.hooknum  = NF_INET_LOCAL_IN,
    115		.priority = INT_MAX,
    116	},
    117#if IS_ENABLED(CONFIG_IPV6)
    118	{
    119		.hook     = ipvlan_nf_input,
    120		.pf       = NFPROTO_IPV6,
    121		.hooknum  = NF_INET_LOCAL_IN,
    122		.priority = INT_MAX,
    123	},
    124#endif
    125};
    126
    127static int ipvlan_register_nf_hook(struct net *net)
    128{
    129	struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid);
    130	int err = 0;
    131
    132	if (!vnet->ipvl_nf_hook_refcnt) {
    133		err = nf_register_net_hooks(net, ipvl_nfops,
    134					    ARRAY_SIZE(ipvl_nfops));
    135		if (!err)
    136			vnet->ipvl_nf_hook_refcnt = 1;
    137	} else {
    138		vnet->ipvl_nf_hook_refcnt++;
    139	}
    140
    141	return err;
    142}
    143
    144static void ipvlan_unregister_nf_hook(struct net *net)
    145{
    146	struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid);
    147
    148	if (WARN_ON(!vnet->ipvl_nf_hook_refcnt))
    149		return;
    150
    151	vnet->ipvl_nf_hook_refcnt--;
    152	if (!vnet->ipvl_nf_hook_refcnt)
    153		nf_unregister_net_hooks(net, ipvl_nfops,
    154					ARRAY_SIZE(ipvl_nfops));
    155}
    156
    157void ipvlan_migrate_l3s_hook(struct net *oldnet, struct net *newnet)
    158{
    159	struct ipvlan_netns *old_vnet;
    160
    161	ASSERT_RTNL();
    162
    163	old_vnet = net_generic(oldnet, ipvlan_netid);
    164	if (!old_vnet->ipvl_nf_hook_refcnt)
    165		return;
    166
    167	ipvlan_register_nf_hook(newnet);
    168	ipvlan_unregister_nf_hook(oldnet);
    169}
    170
    171static void ipvlan_ns_exit(struct net *net)
    172{
    173	struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid);
    174
    175	if (WARN_ON_ONCE(vnet->ipvl_nf_hook_refcnt)) {
    176		vnet->ipvl_nf_hook_refcnt = 0;
    177		nf_unregister_net_hooks(net, ipvl_nfops,
    178					ARRAY_SIZE(ipvl_nfops));
    179	}
    180}
    181
    182static struct pernet_operations ipvlan_net_ops = {
    183	.id   = &ipvlan_netid,
    184	.size = sizeof(struct ipvlan_netns),
    185	.exit = ipvlan_ns_exit,
    186};
    187
    188int ipvlan_l3s_init(void)
    189{
    190	return register_pernet_subsys(&ipvlan_net_ops);
    191}
    192
    193void ipvlan_l3s_cleanup(void)
    194{
    195	unregister_pernet_subsys(&ipvlan_net_ops);
    196}
    197
    198int ipvlan_l3s_register(struct ipvl_port *port)
    199{
    200	struct net_device *dev = port->dev;
    201	int ret;
    202
    203	ASSERT_RTNL();
    204
    205	ret = ipvlan_register_nf_hook(read_pnet(&port->pnet));
    206	if (!ret) {
    207		dev->l3mdev_ops = &ipvl_l3mdev_ops;
    208		dev->priv_flags |= IFF_L3MDEV_RX_HANDLER;
    209	}
    210
    211	return ret;
    212}
    213
    214void ipvlan_l3s_unregister(struct ipvl_port *port)
    215{
    216	struct net_device *dev = port->dev;
    217
    218	ASSERT_RTNL();
    219
    220	dev->priv_flags &= ~IFF_L3MDEV_RX_HANDLER;
    221	ipvlan_unregister_nf_hook(read_pnet(&port->pnet));
    222	dev->l3mdev_ops = NULL;
    223}