linux/net/mpls/af_mpls.c

// SPDX-License-Identifier: GPL-2.0-only
#include <linux/types.h>
#include <linux/skbuff.h>
#include <linux/socket.h>
#include <linux/sysctl.h>
#include <linux/net.h>
#include <linux/module.h>
#include <linux/if_arp.h>
#include <linux/ipv6.h>
#include <linux/mpls.h>
#include <linux/netconf.h>
#include <linux/nospec.h>
#include <linux/vmalloc.h>
#include <linux/percpu.h>
#include <net/gso.h>
#include <net/ip.h>
#include <net/dst.h>
#include <net/sock.h>
#include <net/arp.h>
#include <net/ip_fib.h>
#include <net/netevent.h>
#include <net/ip_tunnels.h>
#include <net/netns/generic.h>
#if IS_ENABLED(CONFIG_IPV6)
#include <net/ipv6.h>
#endif
#include <net/ipv6_stubs.h>
#include <net/rtnh.h>
#include "internal.h"

/* max memory we will use for mpls_route */
#define MAX_MPLS_ROUTE_MEM

/* Maximum number of labels to look ahead at when selecting a path of
 * a multipath route
 */
#define MAX_MP_SELECT_LABELS

#define MPLS_NEIGH_TABLE_UNSPEC

static int label_limit =;
static int ttl_max =;

#if IS_ENABLED(CONFIG_NET_IP_TUNNEL)
static size_t ipgre_mpls_encap_hlen(struct ip_tunnel_encap *e)
{}

static const struct ip_tunnel_encap_ops mpls_iptun_ops =;

static int ipgre_tunnel_encap_add_mpls_ops(void)
{}

static void ipgre_tunnel_encap_del_mpls_ops(void)
{}
#else
static int ipgre_tunnel_encap_add_mpls_ops(void)
{
	return 0;
}

static void ipgre_tunnel_encap_del_mpls_ops(void)
{
}
#endif

static void rtmsg_lfib(int event, u32 label, struct mpls_route *rt,
		       struct nlmsghdr *nlh, struct net *net, u32 portid,
		       unsigned int nlm_flags);

static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned index)
{}

bool mpls_output_possible(const struct net_device *dev)
{}
EXPORT_SYMBOL_GPL();

static u8 *__mpls_nh_via(struct mpls_route *rt, struct mpls_nh *nh)
{}

static const u8 *mpls_nh_via(const struct mpls_route *rt,
			     const struct mpls_nh *nh)
{}

static unsigned int mpls_nh_header_size(const struct mpls_nh *nh)
{}

unsigned int mpls_dev_mtu(const struct net_device *dev)
{}
EXPORT_SYMBOL_GPL();

bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu)
{}
EXPORT_SYMBOL_GPL();

void mpls_stats_inc_outucastpkts(struct net_device *dev,
				 const struct sk_buff *skb)
{}
EXPORT_SYMBOL_GPL();

static u32 mpls_multipath_hash(struct mpls_route *rt, struct sk_buff *skb)
{}

static struct mpls_nh *mpls_get_nexthop(struct mpls_route *rt, u8 index)
{}

/* number of alive nexthops (rt->rt_nhn_alive) and the flags for
 * a next hop (nh->nh_flags) are modified by netdev event handlers.
 * Since those fields can change at any moment, use READ_ONCE to
 * access both.
 */
static const struct mpls_nh *mpls_select_multipath(struct mpls_route *rt,
						   struct sk_buff *skb)
{}

static bool mpls_egress(struct net *net, struct mpls_route *rt,
			struct sk_buff *skb, struct mpls_entry_decoded dec)
{}

static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
			struct packet_type *pt, struct net_device *orig_dev)
{}

static struct packet_type mpls_packet_type __read_mostly =;

static const struct nla_policy rtm_mpls_policy[RTA_MAX+1] =;

struct mpls_route_config {};

/* all nexthops within a route have the same size based on max
 * number of labels and max via length for a hop
 */
static struct mpls_route *mpls_rt_alloc(u8 num_nh, u8 max_alen, u8 max_labels)
{}

static void mpls_rt_free(struct mpls_route *rt)
{}

static void mpls_notify_route(struct net *net, unsigned index,
			      struct mpls_route *old, struct mpls_route *new,
			      const struct nl_info *info)
{}

static void mpls_route_update(struct net *net, unsigned index,
			      struct mpls_route *new,
			      const struct nl_info *info)
{}

static unsigned find_free_label(struct net *net)
{}

#if IS_ENABLED(CONFIG_INET)
static struct net_device *inet_fib_lookup_dev(struct net *net,
					      const void *addr)
{}
#else
static struct net_device *inet_fib_lookup_dev(struct net *net,
					      const void *addr)
{
	return ERR_PTR(-EAFNOSUPPORT);
}
#endif

#if IS_ENABLED(CONFIG_IPV6)
static struct net_device *inet6_fib_lookup_dev(struct net *net,
					       const void *addr)
{}
#else
static struct net_device *inet6_fib_lookup_dev(struct net *net,
					       const void *addr)
{
	return ERR_PTR(-EAFNOSUPPORT);
}
#endif

static struct net_device *find_outdev(struct net *net,
				      struct mpls_route *rt,
				      struct mpls_nh *nh, int oif)
{}

static int mpls_nh_assign_dev(struct net *net, struct mpls_route *rt,
			      struct mpls_nh *nh, int oif)
{}

static int nla_get_via(const struct nlattr *nla, u8 *via_alen, u8 *via_table,
		       u8 via_addr[], struct netlink_ext_ack *extack)
{}

static int mpls_nh_build_from_cfg(struct mpls_route_config *cfg,
				  struct mpls_route *rt)
{}

static int mpls_nh_build(struct net *net, struct mpls_route *rt,
			 struct mpls_nh *nh, int oif, struct nlattr *via,
			 struct nlattr *newdst, u8 max_labels,
			 struct netlink_ext_ack *extack)
{}

static u8 mpls_count_nexthops(struct rtnexthop *rtnh, int len,
			      u8 cfg_via_alen, u8 *max_via_alen,
			      u8 *max_labels)
{}

static int mpls_nh_build_multi(struct mpls_route_config *cfg,
			       struct mpls_route *rt, u8 max_labels,
			       struct netlink_ext_ack *extack)
{}

static bool mpls_label_ok(struct net *net, unsigned int *index,
			  struct netlink_ext_ack *extack)
{}

static int mpls_route_add(struct mpls_route_config *cfg,
			  struct netlink_ext_ack *extack)
{}

static int mpls_route_del(struct mpls_route_config *cfg,
			  struct netlink_ext_ack *extack)
{}

static void mpls_get_stats(struct mpls_dev *mdev,
			   struct mpls_link_stats *stats)
{}

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

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

static int mpls_netconf_fill_devconf(struct sk_buff *skb, struct mpls_dev *mdev,
				     u32 portid, u32 seq, int event,
				     unsigned int flags, int type)
{}

static int mpls_netconf_msgsize_devconf(int type)
{}

static void mpls_netconf_notify_devconf(struct net *net, int event,
					int type, struct mpls_dev *mdev)
{}

static const struct nla_policy devconf_mpls_policy[NETCONFA_MAX + 1] =;

static int mpls_netconf_valid_get_req(struct sk_buff *skb,
				      const struct nlmsghdr *nlh,
				      struct nlattr **tb,
				      struct netlink_ext_ack *extack)
{}

static int mpls_netconf_get_devconf(struct sk_buff *in_skb,
				    struct nlmsghdr *nlh,
				    struct netlink_ext_ack *extack)
{}

static int mpls_netconf_dump_devconf(struct sk_buff *skb,
				     struct netlink_callback *cb)
{}

#define MPLS_PERDEV_SYSCTL_OFFSET(field)

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

static const struct ctl_table mpls_dev_table[] =;

static int mpls_dev_sysctl_register(struct net_device *dev,
				    struct mpls_dev *mdev)
{}

static void mpls_dev_sysctl_unregister(struct net_device *dev,
				       struct mpls_dev *mdev)
{}

static struct mpls_dev *mpls_add_dev(struct net_device *dev)
{}

static void mpls_dev_destroy_rcu(struct rcu_head *head)
{}

static int mpls_ifdown(struct net_device *dev, int event)
{}

static void mpls_ifup(struct net_device *dev, unsigned int flags)
{}

static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
			   void *ptr)
{}

static struct notifier_block mpls_dev_notifier =;

static int nla_put_via(struct sk_buff *skb,
		       u8 table, const void *addr, int alen)
{}

int nla_put_labels(struct sk_buff *skb, int attrtype,
		   u8 labels, const u32 label[])
{}
EXPORT_SYMBOL_GPL();

int nla_get_labels(const struct nlattr *nla, u8 max_labels, u8 *labels,
		   u32 label[], struct netlink_ext_ack *extack)
{}
EXPORT_SYMBOL_GPL();

static int rtm_to_route_config(struct sk_buff *skb,
			       struct nlmsghdr *nlh,
			       struct mpls_route_config *cfg,
			       struct netlink_ext_ack *extack)
{}

static int mpls_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
			     struct netlink_ext_ack *extack)
{}


static int mpls_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
			     struct netlink_ext_ack *extack)
{}

static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
			   u32 label, struct mpls_route *rt, int flags)
{}

#if IS_ENABLED(CONFIG_INET)
static int mpls_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
				   struct fib_dump_filter *filter,
				   struct netlink_callback *cb)
{}
#else
static int mpls_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
				   struct fib_dump_filter *filter,
				   struct netlink_callback *cb)
{
	struct netlink_ext_ack *extack = cb->extack;
	struct nlattr *tb[RTA_MAX + 1];
	struct rtmsg *rtm;
	int err, i;

	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) {
		NL_SET_ERR_MSG_MOD(extack, "Invalid header for FIB dump request");
		return -EINVAL;
	}

	rtm = nlmsg_data(nlh);
	if (rtm->rtm_dst_len || rtm->rtm_src_len  || rtm->rtm_tos   ||
	    rtm->rtm_table   || rtm->rtm_scope    || rtm->rtm_type  ||
	    rtm->rtm_flags) {
		NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for FIB dump request");
		return -EINVAL;
	}

	if (rtm->rtm_protocol) {
		filter->protocol = rtm->rtm_protocol;
		filter->filter_set = 1;
		cb->answer_flags = NLM_F_DUMP_FILTERED;
	}

	err = nlmsg_parse_deprecated_strict(nlh, sizeof(*rtm), tb, RTA_MAX,
					    rtm_mpls_policy, extack);
	if (err < 0)
		return err;

	for (i = 0; i <= RTA_MAX; ++i) {
		int ifindex;

		if (i == RTA_OIF) {
			ifindex = nla_get_u32(tb[i]);
			filter->dev = __dev_get_by_index(net, ifindex);
			if (!filter->dev)
				return -ENODEV;
			filter->filter_set = 1;
		} else if (tb[i]) {
			NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in dump request");
			return -EINVAL;
		}
	}

	return 0;
}
#endif

static bool mpls_rt_uses_dev(struct mpls_route *rt,
			     const struct net_device *dev)
{}

static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
{}

static inline size_t lfib_nlmsg_size(struct mpls_route *rt)
{}

static void rtmsg_lfib(int event, u32 label, struct mpls_route *rt,
		       struct nlmsghdr *nlh, struct net *net, u32 portid,
		       unsigned int nlm_flags)
{}

static int mpls_valid_getroute_req(struct sk_buff *skb,
				   const struct nlmsghdr *nlh,
				   struct nlattr **tb,
				   struct netlink_ext_ack *extack)
{}

static int mpls_getroute(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
			 struct netlink_ext_ack *extack)
{}

static int resize_platform_label_table(struct net *net, size_t limit)
{}

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

#define MPLS_NS_SYSCTL_OFFSET(field)

static const struct ctl_table mpls_table[] =;

static int mpls_net_init(struct net *net)
{}

static void mpls_net_exit(struct net *net)
{}

static struct pernet_operations mpls_net_ops =;

static struct rtnl_af_ops mpls_af_ops __read_mostly =;

static int __init mpls_init(void)
{}
module_init();

static void __exit mpls_exit(void)
{}
module_exit(mpls_exit);

MODULE_DESCRIPTION();
MODULE_LICENSE();
MODULE_ALIAS_NETPROTO();