linux/drivers/net/vrf.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * vrf.c: device driver to encapsulate a VRF space
 *
 * Copyright (c) 2015 Cumulus Networks. All rights reserved.
 * Copyright (c) 2015 Shrijeet Mukherjee <[email protected]>
 * Copyright (c) 2015 David Ahern <[email protected]>
 *
 * Based on dummy, team and ipvlan drivers
 */

#include <linux/ethtool.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ip.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/netfilter.h>
#include <linux/rtnetlink.h>
#include <net/rtnetlink.h>
#include <linux/u64_stats_sync.h>
#include <linux/hashtable.h>
#include <linux/spinlock_types.h>

#include <linux/inetdevice.h>
#include <net/arp.h>
#include <net/ip.h>
#include <net/ip_fib.h>
#include <net/ip6_fib.h>
#include <net/ip6_route.h>
#include <net/route.h>
#include <net/addrconf.h>
#include <net/l3mdev.h>
#include <net/fib_rules.h>
#include <net/sch_generic.h>
#include <net/netns/generic.h>
#include <net/netfilter/nf_conntrack.h>

#define DRV_NAME
#define DRV_VERSION

#define FIB_RULE_PREF

#define HT_MAP_BITS
#define HASH_INITVAL

struct  vrf_map {};

struct vrf_map_elem {};

static unsigned int vrf_net_id;

/* per netns vrf data */
struct netns_vrf {};

struct net_vrf {};

static void vrf_rx_stats(struct net_device *dev, int len)
{}

static void vrf_tx_error(struct net_device *vrf_dev, struct sk_buff *skb)
{}

static struct vrf_map *netns_vrf_map(struct net *net)
{}

static struct vrf_map *netns_vrf_map_by_dev(struct net_device *dev)
{}

static int vrf_map_elem_get_vrf_ifindex(struct vrf_map_elem *me)
{}

static struct vrf_map_elem *vrf_map_elem_alloc(gfp_t flags)
{}

static void vrf_map_elem_free(struct vrf_map_elem *me)
{}

static void vrf_map_elem_init(struct vrf_map_elem *me, int table_id,
			      int ifindex, int users)
{}

static struct vrf_map_elem *vrf_map_lookup_elem(struct vrf_map *vmap,
						u32 table_id)
{}

static void vrf_map_add_elem(struct vrf_map *vmap, struct vrf_map_elem *me)
{}

static void vrf_map_del_elem(struct vrf_map_elem *me)
{}

static void vrf_map_lock(struct vrf_map *vmap) __acquires(&vmap->vmap_lock)
{}

static void vrf_map_unlock(struct vrf_map *vmap) __releases(&vmap->vmap_lock)
{}

/* called with rtnl lock held */
static int
vrf_map_register_dev(struct net_device *dev, struct netlink_ext_ack *extack)
{}

/* called with rtnl lock held */
static void vrf_map_unregister_dev(struct net_device *dev)
{}

/* return the vrf device index associated with the table_id */
static int vrf_ifindex_lookup_by_table_id(struct net *net, u32 table_id)
{}

/* by default VRF devices do not have a qdisc and are expected
 * to be created with only a single queue.
 */
static bool qdisc_tx_is_default(const struct net_device *dev)
{}

/* Local traffic destined to local address. Reinsert the packet to rx
 * path, similar to loopback handling.
 */
static int vrf_local_xmit(struct sk_buff *skb, struct net_device *dev,
			  struct dst_entry *dst)
{}

static void vrf_nf_set_untracked(struct sk_buff *skb)
{}

static void vrf_nf_reset_ct(struct sk_buff *skb)
{}

#if IS_ENABLED(CONFIG_IPV6)
static int vrf_ip6_local_out(struct net *net, struct sock *sk,
			     struct sk_buff *skb)
{}

static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb,
					   struct net_device *dev)
{}
#else
static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb,
					   struct net_device *dev)
{
	vrf_tx_error(dev, skb);
	return NET_XMIT_DROP;
}
#endif

/* based on ip_local_out; can't use it b/c the dst is switched pointing to us */
static int vrf_ip_local_out(struct net *net, struct sock *sk,
			    struct sk_buff *skb)
{}

static netdev_tx_t vrf_process_v4_outbound(struct sk_buff *skb,
					   struct net_device *vrf_dev)
{}

static netdev_tx_t is_ip_tx_frame(struct sk_buff *skb, struct net_device *dev)
{}

static netdev_tx_t vrf_xmit(struct sk_buff *skb, struct net_device *dev)
{}

static void vrf_finish_direct(struct sk_buff *skb)
{}

#if IS_ENABLED(CONFIG_IPV6)
/* modelled after ip6_finish_output2 */
static int vrf_finish_output6(struct net *net, struct sock *sk,
			      struct sk_buff *skb)
{}

/* modelled after ip6_output */
static int vrf_output6(struct net *net, struct sock *sk, struct sk_buff *skb)
{}

/* set dst on skb to send packet to us via dev_xmit path. Allows
 * packet to go through device based features such as qdisc, netfilter
 * hooks and packet sockets with skb->dev set to vrf device.
 */
static struct sk_buff *vrf_ip6_out_redirect(struct net_device *vrf_dev,
					    struct sk_buff *skb)
{}

static int vrf_output6_direct_finish(struct net *net, struct sock *sk,
				     struct sk_buff *skb)
{}

static int vrf_output6_direct(struct net *net, struct sock *sk,
			      struct sk_buff *skb)
{}

static int vrf_ip6_out_direct_finish(struct net *net, struct sock *sk,
				     struct sk_buff *skb)
{}

static struct sk_buff *vrf_ip6_out_direct(struct net_device *vrf_dev,
					  struct sock *sk,
					  struct sk_buff *skb)
{}

static struct sk_buff *vrf_ip6_out(struct net_device *vrf_dev,
				   struct sock *sk,
				   struct sk_buff *skb)
{}

/* holding rtnl */
static void vrf_rt6_release(struct net_device *dev, struct net_vrf *vrf)
{}

static int vrf_rt6_create(struct net_device *dev)
{}
#else
static struct sk_buff *vrf_ip6_out(struct net_device *vrf_dev,
				   struct sock *sk,
				   struct sk_buff *skb)
{
	return skb;
}

static void vrf_rt6_release(struct net_device *dev, struct net_vrf *vrf)
{
}

static int vrf_rt6_create(struct net_device *dev)
{
	return 0;
}
#endif

/* modelled after ip_finish_output2 */
static int vrf_finish_output(struct net *net, struct sock *sk, struct sk_buff *skb)
{}

static int vrf_output(struct net *net, struct sock *sk, struct sk_buff *skb)
{}

/* set dst on skb to send packet to us via dev_xmit path. Allows
 * packet to go through device based features such as qdisc, netfilter
 * hooks and packet sockets with skb->dev set to vrf device.
 */
static struct sk_buff *vrf_ip_out_redirect(struct net_device *vrf_dev,
					   struct sk_buff *skb)
{}

static int vrf_output_direct_finish(struct net *net, struct sock *sk,
				    struct sk_buff *skb)
{}

static int vrf_output_direct(struct net *net, struct sock *sk,
			     struct sk_buff *skb)
{}

static int vrf_ip_out_direct_finish(struct net *net, struct sock *sk,
				    struct sk_buff *skb)
{}

static struct sk_buff *vrf_ip_out_direct(struct net_device *vrf_dev,
					 struct sock *sk,
					 struct sk_buff *skb)
{}

static struct sk_buff *vrf_ip_out(struct net_device *vrf_dev,
				  struct sock *sk,
				  struct sk_buff *skb)
{}

/* called with rcu lock held */
static struct sk_buff *vrf_l3_out(struct net_device *vrf_dev,
				  struct sock *sk,
				  struct sk_buff *skb,
				  u16 proto)
{}

/* holding rtnl */
static void vrf_rtable_release(struct net_device *dev, struct net_vrf *vrf)
{}

static int vrf_rtable_create(struct net_device *dev)
{}

/**************************** device handling ********************/

/* cycle interface to flush neighbor cache and move routes across tables */
static void cycle_netdev(struct net_device *dev,
			 struct netlink_ext_ack *extack)
{}

static int do_vrf_add_slave(struct net_device *dev, struct net_device *port_dev,
			    struct netlink_ext_ack *extack)
{}

static int vrf_add_slave(struct net_device *dev, struct net_device *port_dev,
			 struct netlink_ext_ack *extack)
{}

/* inverse of do_vrf_add_slave */
static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev)
{}

static int vrf_del_slave(struct net_device *dev, struct net_device *port_dev)
{}

static void vrf_dev_uninit(struct net_device *dev)
{}

static int vrf_dev_init(struct net_device *dev)
{}

static const struct net_device_ops vrf_netdev_ops =;

static u32 vrf_fib_table(const struct net_device *dev)
{}

static int vrf_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{}

static struct sk_buff *vrf_rcv_nfhook(u8 pf, unsigned int hook,
				      struct sk_buff *skb,
				      struct net_device *dev)
{}

static int vrf_prepare_mac_header(struct sk_buff *skb,
				  struct net_device *vrf_dev, u16 proto)
{}

/* prepare and add the mac header to the packet if it was not set previously.
 * In this way, packet sniffers such as tcpdump can parse the packet correctly.
 * If the mac header was already set, the original mac header is left
 * untouched and the function returns immediately.
 */
static int vrf_add_mac_header_if_unset(struct sk_buff *skb,
				       struct net_device *vrf_dev,
				       u16 proto, struct net_device *orig_dev)
{}

#if IS_ENABLED(CONFIG_IPV6)
/* neighbor handling is done with actual device; do not want
 * to flip skb->dev for those ndisc packets. This really fails
 * for multiple next protocols (e.g., NEXTHDR_HOP). But it is
 * a start.
 */
static bool ipv6_ndisc_frame(const struct sk_buff *skb)
{}

static struct rt6_info *vrf_ip6_route_lookup(struct net *net,
					     const struct net_device *dev,
					     struct flowi6 *fl6,
					     int ifindex,
					     const struct sk_buff *skb,
					     int flags)
{}

static void vrf_ip6_input_dst(struct sk_buff *skb, struct net_device *vrf_dev,
			      int ifindex)
{}

static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev,
				   struct sk_buff *skb)
{}

#else
static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev,
				   struct sk_buff *skb)
{
	return skb;
}
#endif

static struct sk_buff *vrf_ip_rcv(struct net_device *vrf_dev,
				  struct sk_buff *skb)
{}

/* called with rcu lock held */
static struct sk_buff *vrf_l3_rcv(struct net_device *vrf_dev,
				  struct sk_buff *skb,
				  u16 proto)
{}

#if IS_ENABLED(CONFIG_IPV6)
/* send to link-local or multicast address via interface enslaved to
 * VRF device. Force lookup to VRF table without changing flow struct
 * Note: Caller to this function must hold rcu_read_lock() and no refcnt
 * is taken on the dst by this function.
 */
static struct dst_entry *vrf_link_scope_lookup(const struct net_device *dev,
					      struct flowi6 *fl6)
{}
#endif

static const struct l3mdev_ops vrf_l3mdev_ops =;

static void vrf_get_drvinfo(struct net_device *dev,
			    struct ethtool_drvinfo *info)
{}

static const struct ethtool_ops vrf_ethtool_ops =;

static inline size_t vrf_fib_rule_nl_size(void)
{}

static int vrf_fib_rule(const struct net_device *dev, __u8 family, bool add_it)
{}

static int vrf_add_fib_rules(const struct net_device *dev)
{}

static void vrf_setup(struct net_device *dev)
{}

static int vrf_validate(struct nlattr *tb[], struct nlattr *data[],
			struct netlink_ext_ack *extack)
{}

static void vrf_dellink(struct net_device *dev, struct list_head *head)
{}

static int vrf_newlink(struct net *src_net, struct net_device *dev,
		       struct nlattr *tb[], struct nlattr *data[],
		       struct netlink_ext_ack *extack)
{}

static size_t vrf_nl_getsize(const struct net_device *dev)
{}

static int vrf_fillinfo(struct sk_buff *skb,
			const struct net_device *dev)
{}

static size_t vrf_get_slave_size(const struct net_device *bond_dev,
				 const struct net_device *slave_dev)
{}

static int vrf_fill_slave_info(struct sk_buff *skb,
			       const struct net_device *vrf_dev,
			       const struct net_device *slave_dev)
{}

static const struct nla_policy vrf_nl_policy[IFLA_VRF_MAX + 1] =;

static struct rtnl_link_ops vrf_link_ops __read_mostly =;

static int vrf_device_event(struct notifier_block *unused,
			    unsigned long event, void *ptr)
{}

static struct notifier_block vrf_notifier_block __read_mostly =;

static int vrf_map_init(struct vrf_map *vmap)
{}

#ifdef CONFIG_SYSCTL
static bool vrf_strict_mode(struct vrf_map *vmap)
{}

static int vrf_strict_mode_change(struct vrf_map *vmap, bool new_mode)
{}

static int vrf_shared_table_handler(const struct ctl_table *table, int write,
				    void *buffer, size_t *lenp, loff_t *ppos)
{}

static const struct ctl_table vrf_table[] =;

static int vrf_netns_init_sysctl(struct net *net, struct netns_vrf *nn_vrf)
{}

static void vrf_netns_exit_sysctl(struct net *net)
{}
#else
static int vrf_netns_init_sysctl(struct net *net, struct netns_vrf *nn_vrf)
{
	return 0;
}

static void vrf_netns_exit_sysctl(struct net *net)
{
}
#endif

/* Initialize per network namespace state */
static int __net_init vrf_netns_init(struct net *net)
{}

static void __net_exit vrf_netns_exit(struct net *net)
{}

static struct pernet_operations vrf_net_ops __net_initdata =;

static int __init vrf_init_module(void)
{}

module_init();
MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();
MODULE_ALIAS_RTNL_LINK();
MODULE_VERSION();