#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/vmalloc.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/netns/generic.h>
#include "internal.h"
#define LABEL_NOT_SPECIFIED (1<<20)
#define MAX_NEW_LABELS 2
/* This maximum ha length copied from the definition of struct neighbour */
#define MAX_VIA_ALEN (ALIGN(MAX_ADDR_LEN, sizeof(unsigned long)))
struct mpls_route { /* next hop label forwarding entry */
struct net_device __rcu *rt_dev;
struct rcu_head rt_rcu;
u32 rt_label[MAX_NEW_LABELS];
u8 rt_protocol; /* routing protocol that set this entry */
u8 rt_labels;
u8 rt_via_alen;
u8 rt_via_table;
u8 rt_via[0];
};
static int zero = 0;
static int label_limit = (1 << 20) - 1;
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)
{
struct mpls_route *rt = NULL;
if (index < net->mpls.platform_labels) {
struct mpls_route __rcu **platform_label =
rcu_dereference(net->mpls.platform_label);
rt = rcu_dereference(platform_label[index]);
}
return rt;
}
static bool mpls_output_possible(const struct net_device *dev)
{
return dev && (dev->flags & IFF_UP) && netif_carrier_ok(dev);
}
static unsigned int mpls_rt_header_size(const struct mpls_route *rt)
{
/* The size of the layer 2.5 labels to be added for this route */
return rt->rt_labels * sizeof(struct mpls_shim_hdr);
}
static unsigned int mpls_dev_mtu(const struct net_device *dev)
{
/* The amount of data the layer 2 frame can hold */
return dev->mtu;
}
static bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu)
{
if (skb->len <= mtu)
return false;
if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu)
return false;
return true;
}
static bool mpls_egress(struct mpls_route *rt, struct sk_buff *skb,
struct mpls_entry_decoded dec)
{
/* RFC4385 and RFC5586 encode other packets in mpls such that
* they don't conflict with the ip version number, making
* decoding by examining the ip version correct in everything
* except for the strangest cases.
*
* The strange cases if we choose to support them will require
* manual configuration.
*/
struct iphdr *hdr4;
bool success = true;
/* The IPv4 code below accesses through the IPv4 header
* checksum, which is 12 bytes into the packet.
* The IPv6 code below accesses through the IPv6 hop limit
* which is 8 bytes into the packet.
*
* For all supported cases there should always be at least 12
* bytes of packet data present. The IPv4 header is 20 bytes
* without options and the IPv6 header is always 40 bytes
* long.
*/
if (!pskb_may_pull(skb, 12))
return false;
/* Use ip_hdr to find the ip protocol version */
hdr4 = ip_hdr(skb);
if (hdr4->version == 4) {
skb->protocol = htons(ETH_P_IP);
csum_replace2(&hdr4->check,
htons(hdr4->ttl << 8),
htons(dec.ttl << 8));
hdr4->ttl = dec.ttl;
}
else if (hdr4->version == 6) {
struct ipv6hdr *hdr6 = ipv6_hdr(skb);
skb->protocol = htons(ETH_P_IPV6);
hdr6->hop_limit = dec.ttl;
}
else
/* version 0 and version 1 are used by pseudo wires */
success = false;
return success;
}
static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
struct net *net = dev_net(dev);
struct mpls_shim_hdr *hdr;
struct mpls_route *rt;
struct mpls_entry_decoded dec;
struct net_device *out_dev;
unsigned int hh_len;
unsigned int new_header_size;
unsigned int mtu;
int err;
/* Careful this entire function runs inside of an rcu critical section */
if (skb->pkt_type != PACKET_HOST)
goto drop;
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
goto drop;
if (!pskb_may_pull(skb, sizeof(*hdr)))
goto drop;
/* Read and decode the label */
hdr = mpls_hdr(skb);
dec = mpls_entry_decode(hdr);
/* Pop the label */
skb_pull(skb, sizeof(*hdr));
skb_reset_network_header(skb);
skb_orphan(skb);
rt = mpls_route_input_rcu(net, dec.label);
if (!rt)
goto drop;
/* Find the output device */
out_dev = rcu_dereference(rt->rt_dev);
if (!mpls_output_possible(out_dev))
goto drop;
if (skb_warn_if_lro(skb))
goto drop;
skb_forward_csum(skb);
/* Verify ttl is valid */
if (dec.ttl <= 1)
goto drop;
dec.ttl -= 1;
/* Verify the destination can hold the packet */
new_header_size = mpls_rt_header_size(rt);
mtu = mpls_dev_mtu(