#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"
#define MAX_MPLS_ROUTE_MEM …
#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)
{ … }
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 { … };
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(…);