10189197fSEric W. Biederman #include <linux/types.h> 20189197fSEric W. Biederman #include <linux/skbuff.h> 30189197fSEric W. Biederman #include <linux/socket.h> 47720c01fSEric W. Biederman #include <linux/sysctl.h> 50189197fSEric W. Biederman #include <linux/net.h> 60189197fSEric W. Biederman #include <linux/module.h> 70189197fSEric W. Biederman #include <linux/if_arp.h> 80189197fSEric W. Biederman #include <linux/ipv6.h> 90189197fSEric W. Biederman #include <linux/mpls.h> 100189197fSEric W. Biederman #include <net/ip.h> 110189197fSEric W. Biederman #include <net/dst.h> 120189197fSEric W. Biederman #include <net/sock.h> 130189197fSEric W. Biederman #include <net/arp.h> 140189197fSEric W. Biederman #include <net/ip_fib.h> 150189197fSEric W. Biederman #include <net/netevent.h> 160189197fSEric W. Biederman #include <net/netns/generic.h> 170189197fSEric W. Biederman #include "internal.h" 180189197fSEric W. Biederman 19a2519929SEric W. Biederman #define LABEL_NOT_SPECIFIED (1<<20) 200189197fSEric W. Biederman #define MAX_NEW_LABELS 2 210189197fSEric W. Biederman 220189197fSEric W. Biederman /* This maximum ha length copied from the definition of struct neighbour */ 230189197fSEric W. Biederman #define MAX_VIA_ALEN (ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))) 240189197fSEric W. Biederman 250189197fSEric W. Biederman struct mpls_route { /* next hop label forwarding entry */ 260189197fSEric W. Biederman struct net_device *rt_dev; 270189197fSEric W. Biederman struct rcu_head rt_rcu; 280189197fSEric W. Biederman u32 rt_label[MAX_NEW_LABELS]; 290189197fSEric W. Biederman u8 rt_protocol; /* routing protocol that set this entry */ 300189197fSEric W. Biederman u8 rt_labels:2, 310189197fSEric W. Biederman rt_via_alen:6; 320189197fSEric W. Biederman unsigned short rt_via_family; 330189197fSEric W. Biederman u8 rt_via[0]; 340189197fSEric W. Biederman }; 350189197fSEric W. Biederman 367720c01fSEric W. Biederman static int zero = 0; 377720c01fSEric W. Biederman static int label_limit = (1 << 20) - 1; 387720c01fSEric W. Biederman 390189197fSEric W. Biederman static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned index) 400189197fSEric W. Biederman { 410189197fSEric W. Biederman struct mpls_route *rt = NULL; 420189197fSEric W. Biederman 430189197fSEric W. Biederman if (index < net->mpls.platform_labels) { 440189197fSEric W. Biederman struct mpls_route __rcu **platform_label = 450189197fSEric W. Biederman rcu_dereference(net->mpls.platform_label); 460189197fSEric W. Biederman rt = rcu_dereference(platform_label[index]); 470189197fSEric W. Biederman } 480189197fSEric W. Biederman return rt; 490189197fSEric W. Biederman } 500189197fSEric W. Biederman 510189197fSEric W. Biederman static bool mpls_output_possible(const struct net_device *dev) 520189197fSEric W. Biederman { 530189197fSEric W. Biederman return dev && (dev->flags & IFF_UP) && netif_carrier_ok(dev); 540189197fSEric W. Biederman } 550189197fSEric W. Biederman 560189197fSEric W. Biederman static unsigned int mpls_rt_header_size(const struct mpls_route *rt) 570189197fSEric W. Biederman { 580189197fSEric W. Biederman /* The size of the layer 2.5 labels to be added for this route */ 590189197fSEric W. Biederman return rt->rt_labels * sizeof(struct mpls_shim_hdr); 600189197fSEric W. Biederman } 610189197fSEric W. Biederman 620189197fSEric W. Biederman static unsigned int mpls_dev_mtu(const struct net_device *dev) 630189197fSEric W. Biederman { 640189197fSEric W. Biederman /* The amount of data the layer 2 frame can hold */ 650189197fSEric W. Biederman return dev->mtu; 660189197fSEric W. Biederman } 670189197fSEric W. Biederman 680189197fSEric W. Biederman static bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) 690189197fSEric W. Biederman { 700189197fSEric W. Biederman if (skb->len <= mtu) 710189197fSEric W. Biederman return false; 720189197fSEric W. Biederman 730189197fSEric W. Biederman if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu) 740189197fSEric W. Biederman return false; 750189197fSEric W. Biederman 760189197fSEric W. Biederman return true; 770189197fSEric W. Biederman } 780189197fSEric W. Biederman 790189197fSEric W. Biederman static bool mpls_egress(struct mpls_route *rt, struct sk_buff *skb, 800189197fSEric W. Biederman struct mpls_entry_decoded dec) 810189197fSEric W. Biederman { 820189197fSEric W. Biederman /* RFC4385 and RFC5586 encode other packets in mpls such that 830189197fSEric W. Biederman * they don't conflict with the ip version number, making 840189197fSEric W. Biederman * decoding by examining the ip version correct in everything 850189197fSEric W. Biederman * except for the strangest cases. 860189197fSEric W. Biederman * 870189197fSEric W. Biederman * The strange cases if we choose to support them will require 880189197fSEric W. Biederman * manual configuration. 890189197fSEric W. Biederman */ 900189197fSEric W. Biederman struct iphdr *hdr4 = ip_hdr(skb); 910189197fSEric W. Biederman bool success = true; 920189197fSEric W. Biederman 930189197fSEric W. Biederman if (hdr4->version == 4) { 940189197fSEric W. Biederman skb->protocol = htons(ETH_P_IP); 950189197fSEric W. Biederman csum_replace2(&hdr4->check, 960189197fSEric W. Biederman htons(hdr4->ttl << 8), 970189197fSEric W. Biederman htons(dec.ttl << 8)); 980189197fSEric W. Biederman hdr4->ttl = dec.ttl; 990189197fSEric W. Biederman } 1000189197fSEric W. Biederman else if (hdr4->version == 6) { 1010189197fSEric W. Biederman struct ipv6hdr *hdr6 = ipv6_hdr(skb); 1020189197fSEric W. Biederman skb->protocol = htons(ETH_P_IPV6); 1030189197fSEric W. Biederman hdr6->hop_limit = dec.ttl; 1040189197fSEric W. Biederman } 1050189197fSEric W. Biederman else 1060189197fSEric W. Biederman /* version 0 and version 1 are used by pseudo wires */ 1070189197fSEric W. Biederman success = false; 1080189197fSEric W. Biederman return success; 1090189197fSEric W. Biederman } 1100189197fSEric W. Biederman 1110189197fSEric W. Biederman static int mpls_forward(struct sk_buff *skb, struct net_device *dev, 1120189197fSEric W. Biederman struct packet_type *pt, struct net_device *orig_dev) 1130189197fSEric W. Biederman { 1140189197fSEric W. Biederman struct net *net = dev_net(dev); 1150189197fSEric W. Biederman struct mpls_shim_hdr *hdr; 1160189197fSEric W. Biederman struct mpls_route *rt; 1170189197fSEric W. Biederman struct mpls_entry_decoded dec; 1180189197fSEric W. Biederman struct net_device *out_dev; 1190189197fSEric W. Biederman unsigned int hh_len; 1200189197fSEric W. Biederman unsigned int new_header_size; 1210189197fSEric W. Biederman unsigned int mtu; 1220189197fSEric W. Biederman int err; 1230189197fSEric W. Biederman 1240189197fSEric W. Biederman /* Careful this entire function runs inside of an rcu critical section */ 1250189197fSEric W. Biederman 1260189197fSEric W. Biederman if (skb->pkt_type != PACKET_HOST) 1270189197fSEric W. Biederman goto drop; 1280189197fSEric W. Biederman 1290189197fSEric W. Biederman if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) 1300189197fSEric W. Biederman goto drop; 1310189197fSEric W. Biederman 1320189197fSEric W. Biederman if (!pskb_may_pull(skb, sizeof(*hdr))) 1330189197fSEric W. Biederman goto drop; 1340189197fSEric W. Biederman 1350189197fSEric W. Biederman /* Read and decode the label */ 1360189197fSEric W. Biederman hdr = mpls_hdr(skb); 1370189197fSEric W. Biederman dec = mpls_entry_decode(hdr); 1380189197fSEric W. Biederman 1390189197fSEric W. Biederman /* Pop the label */ 1400189197fSEric W. Biederman skb_pull(skb, sizeof(*hdr)); 1410189197fSEric W. Biederman skb_reset_network_header(skb); 1420189197fSEric W. Biederman 1430189197fSEric W. Biederman skb_orphan(skb); 1440189197fSEric W. Biederman 1450189197fSEric W. Biederman rt = mpls_route_input_rcu(net, dec.label); 1460189197fSEric W. Biederman if (!rt) 1470189197fSEric W. Biederman goto drop; 1480189197fSEric W. Biederman 1490189197fSEric W. Biederman /* Find the output device */ 1500189197fSEric W. Biederman out_dev = rt->rt_dev; 1510189197fSEric W. Biederman if (!mpls_output_possible(out_dev)) 1520189197fSEric W. Biederman goto drop; 1530189197fSEric W. Biederman 1540189197fSEric W. Biederman if (skb_warn_if_lro(skb)) 1550189197fSEric W. Biederman goto drop; 1560189197fSEric W. Biederman 1570189197fSEric W. Biederman skb_forward_csum(skb); 1580189197fSEric W. Biederman 1590189197fSEric W. Biederman /* Verify ttl is valid */ 1600189197fSEric W. Biederman if (dec.ttl <= 2) 1610189197fSEric W. Biederman goto drop; 1620189197fSEric W. Biederman dec.ttl -= 1; 1630189197fSEric W. Biederman 1640189197fSEric W. Biederman /* Verify the destination can hold the packet */ 1650189197fSEric W. Biederman new_header_size = mpls_rt_header_size(rt); 1660189197fSEric W. Biederman mtu = mpls_dev_mtu(out_dev); 1670189197fSEric W. Biederman if (mpls_pkt_too_big(skb, mtu - new_header_size)) 1680189197fSEric W. Biederman goto drop; 1690189197fSEric W. Biederman 1700189197fSEric W. Biederman hh_len = LL_RESERVED_SPACE(out_dev); 1710189197fSEric W. Biederman if (!out_dev->header_ops) 1720189197fSEric W. Biederman hh_len = 0; 1730189197fSEric W. Biederman 1740189197fSEric W. Biederman /* Ensure there is enough space for the headers in the skb */ 1750189197fSEric W. Biederman if (skb_cow(skb, hh_len + new_header_size)) 1760189197fSEric W. Biederman goto drop; 1770189197fSEric W. Biederman 1780189197fSEric W. Biederman skb->dev = out_dev; 1790189197fSEric W. Biederman skb->protocol = htons(ETH_P_MPLS_UC); 1800189197fSEric W. Biederman 1810189197fSEric W. Biederman if (unlikely(!new_header_size && dec.bos)) { 1820189197fSEric W. Biederman /* Penultimate hop popping */ 1830189197fSEric W. Biederman if (!mpls_egress(rt, skb, dec)) 1840189197fSEric W. Biederman goto drop; 1850189197fSEric W. Biederman } else { 1860189197fSEric W. Biederman bool bos; 1870189197fSEric W. Biederman int i; 1880189197fSEric W. Biederman skb_push(skb, new_header_size); 1890189197fSEric W. Biederman skb_reset_network_header(skb); 1900189197fSEric W. Biederman /* Push the new labels */ 1910189197fSEric W. Biederman hdr = mpls_hdr(skb); 1920189197fSEric W. Biederman bos = dec.bos; 1930189197fSEric W. Biederman for (i = rt->rt_labels - 1; i >= 0; i--) { 1940189197fSEric W. Biederman hdr[i] = mpls_entry_encode(rt->rt_label[i], dec.ttl, 0, bos); 1950189197fSEric W. Biederman bos = false; 1960189197fSEric W. Biederman } 1970189197fSEric W. Biederman } 1980189197fSEric W. Biederman 1990189197fSEric W. Biederman err = neigh_xmit(rt->rt_via_family, out_dev, rt->rt_via, skb); 2000189197fSEric W. Biederman if (err) 2010189197fSEric W. Biederman net_dbg_ratelimited("%s: packet transmission failed: %d\n", 2020189197fSEric W. Biederman __func__, err); 2030189197fSEric W. Biederman return 0; 2040189197fSEric W. Biederman 2050189197fSEric W. Biederman drop: 2060189197fSEric W. Biederman kfree_skb(skb); 2070189197fSEric W. Biederman return NET_RX_DROP; 2080189197fSEric W. Biederman } 2090189197fSEric W. Biederman 2100189197fSEric W. Biederman static struct packet_type mpls_packet_type __read_mostly = { 2110189197fSEric W. Biederman .type = cpu_to_be16(ETH_P_MPLS_UC), 2120189197fSEric W. Biederman .func = mpls_forward, 2130189197fSEric W. Biederman }; 2140189197fSEric W. Biederman 215*03c05665SEric W. Biederman const struct nla_policy rtm_mpls_policy[RTA_MAX+1] = { 216*03c05665SEric W. Biederman [RTA_DST] = { .type = NLA_U32 }, 217*03c05665SEric W. Biederman [RTA_OIF] = { .type = NLA_U32 }, 218*03c05665SEric W. Biederman }; 219*03c05665SEric W. Biederman 220a2519929SEric W. Biederman struct mpls_route_config { 221a2519929SEric W. Biederman u32 rc_protocol; 222a2519929SEric W. Biederman u32 rc_ifindex; 223a2519929SEric W. Biederman u16 rc_via_family; 224a2519929SEric W. Biederman u16 rc_via_alen; 225a2519929SEric W. Biederman u8 rc_via[MAX_VIA_ALEN]; 226a2519929SEric W. Biederman u32 rc_label; 227a2519929SEric W. Biederman u32 rc_output_labels; 228a2519929SEric W. Biederman u32 rc_output_label[MAX_NEW_LABELS]; 229a2519929SEric W. Biederman u32 rc_nlflags; 230a2519929SEric W. Biederman struct nl_info rc_nlinfo; 231a2519929SEric W. Biederman }; 232a2519929SEric W. Biederman 2330189197fSEric W. Biederman static struct mpls_route *mpls_rt_alloc(size_t alen) 2340189197fSEric W. Biederman { 2350189197fSEric W. Biederman struct mpls_route *rt; 2360189197fSEric W. Biederman 2370189197fSEric W. Biederman rt = kzalloc(GFP_KERNEL, sizeof(*rt) + alen); 2380189197fSEric W. Biederman if (rt) 2390189197fSEric W. Biederman rt->rt_via_alen = alen; 2400189197fSEric W. Biederman return rt; 2410189197fSEric W. Biederman } 2420189197fSEric W. Biederman 2430189197fSEric W. Biederman static void mpls_rt_free(struct mpls_route *rt) 2440189197fSEric W. Biederman { 2450189197fSEric W. Biederman if (rt) 2460189197fSEric W. Biederman kfree_rcu(rt, rt_rcu); 2470189197fSEric W. Biederman } 2480189197fSEric W. Biederman 2490189197fSEric W. Biederman static void mpls_route_update(struct net *net, unsigned index, 2500189197fSEric W. Biederman struct net_device *dev, struct mpls_route *new, 2510189197fSEric W. Biederman const struct nl_info *info) 2520189197fSEric W. Biederman { 2530189197fSEric W. Biederman struct mpls_route *rt, *old = NULL; 2540189197fSEric W. Biederman 2550189197fSEric W. Biederman ASSERT_RTNL(); 2560189197fSEric W. Biederman 2570189197fSEric W. Biederman rt = net->mpls.platform_label[index]; 2580189197fSEric W. Biederman if (!dev || (rt && (rt->rt_dev == dev))) { 2590189197fSEric W. Biederman rcu_assign_pointer(net->mpls.platform_label[index], new); 2600189197fSEric W. Biederman old = rt; 2610189197fSEric W. Biederman } 2620189197fSEric W. Biederman 2630189197fSEric W. Biederman /* If we removed a route free it now */ 2640189197fSEric W. Biederman mpls_rt_free(old); 2650189197fSEric W. Biederman } 2660189197fSEric W. Biederman 267a2519929SEric W. Biederman static unsigned find_free_label(struct net *net) 268a2519929SEric W. Biederman { 269a2519929SEric W. Biederman unsigned index; 270a2519929SEric W. Biederman for (index = 16; index < net->mpls.platform_labels; index++) { 271a2519929SEric W. Biederman if (!net->mpls.platform_label[index]) 272a2519929SEric W. Biederman return index; 273a2519929SEric W. Biederman } 274a2519929SEric W. Biederman return LABEL_NOT_SPECIFIED; 275a2519929SEric W. Biederman } 276a2519929SEric W. Biederman 277a2519929SEric W. Biederman static int mpls_route_add(struct mpls_route_config *cfg) 278a2519929SEric W. Biederman { 279a2519929SEric W. Biederman struct net *net = cfg->rc_nlinfo.nl_net; 280a2519929SEric W. Biederman struct net_device *dev = NULL; 281a2519929SEric W. Biederman struct mpls_route *rt, *old; 282a2519929SEric W. Biederman unsigned index; 283a2519929SEric W. Biederman int i; 284a2519929SEric W. Biederman int err = -EINVAL; 285a2519929SEric W. Biederman 286a2519929SEric W. Biederman index = cfg->rc_label; 287a2519929SEric W. Biederman 288a2519929SEric W. Biederman /* If a label was not specified during insert pick one */ 289a2519929SEric W. Biederman if ((index == LABEL_NOT_SPECIFIED) && 290a2519929SEric W. Biederman (cfg->rc_nlflags & NLM_F_CREATE)) { 291a2519929SEric W. Biederman index = find_free_label(net); 292a2519929SEric W. Biederman } 293a2519929SEric W. Biederman 294a2519929SEric W. Biederman /* The first 16 labels are reserved, and may not be set */ 295a2519929SEric W. Biederman if (index < 16) 296a2519929SEric W. Biederman goto errout; 297a2519929SEric W. Biederman 298a2519929SEric W. Biederman /* The full 20 bit range may not be supported. */ 299a2519929SEric W. Biederman if (index >= net->mpls.platform_labels) 300a2519929SEric W. Biederman goto errout; 301a2519929SEric W. Biederman 302a2519929SEric W. Biederman /* Ensure only a supported number of labels are present */ 303a2519929SEric W. Biederman if (cfg->rc_output_labels > MAX_NEW_LABELS) 304a2519929SEric W. Biederman goto errout; 305a2519929SEric W. Biederman 306a2519929SEric W. Biederman err = -ENODEV; 307a2519929SEric W. Biederman dev = dev_get_by_index(net, cfg->rc_ifindex); 308a2519929SEric W. Biederman if (!dev) 309a2519929SEric W. Biederman goto errout; 310a2519929SEric W. Biederman 311a2519929SEric W. Biederman /* For now just support ethernet devices */ 312a2519929SEric W. Biederman err = -EINVAL; 313a2519929SEric W. Biederman if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK)) 314a2519929SEric W. Biederman goto errout; 315a2519929SEric W. Biederman 316a2519929SEric W. Biederman err = -EINVAL; 317a2519929SEric W. Biederman if ((cfg->rc_via_family == AF_PACKET) && 318a2519929SEric W. Biederman (dev->addr_len != cfg->rc_via_alen)) 319a2519929SEric W. Biederman goto errout; 320a2519929SEric W. Biederman 321a2519929SEric W. Biederman /* Append makes no sense with mpls */ 322a2519929SEric W. Biederman err = -EINVAL; 323a2519929SEric W. Biederman if (cfg->rc_nlflags & NLM_F_APPEND) 324a2519929SEric W. Biederman goto errout; 325a2519929SEric W. Biederman 326a2519929SEric W. Biederman err = -EEXIST; 327a2519929SEric W. Biederman old = net->mpls.platform_label[index]; 328a2519929SEric W. Biederman if ((cfg->rc_nlflags & NLM_F_EXCL) && old) 329a2519929SEric W. Biederman goto errout; 330a2519929SEric W. Biederman 331a2519929SEric W. Biederman err = -EEXIST; 332a2519929SEric W. Biederman if (!(cfg->rc_nlflags & NLM_F_REPLACE) && old) 333a2519929SEric W. Biederman goto errout; 334a2519929SEric W. Biederman 335a2519929SEric W. Biederman err = -ENOENT; 336a2519929SEric W. Biederman if (!(cfg->rc_nlflags & NLM_F_CREATE) && !old) 337a2519929SEric W. Biederman goto errout; 338a2519929SEric W. Biederman 339a2519929SEric W. Biederman err = -ENOMEM; 340a2519929SEric W. Biederman rt = mpls_rt_alloc(cfg->rc_via_alen); 341a2519929SEric W. Biederman if (!rt) 342a2519929SEric W. Biederman goto errout; 343a2519929SEric W. Biederman 344a2519929SEric W. Biederman rt->rt_labels = cfg->rc_output_labels; 345a2519929SEric W. Biederman for (i = 0; i < rt->rt_labels; i++) 346a2519929SEric W. Biederman rt->rt_label[i] = cfg->rc_output_label[i]; 347a2519929SEric W. Biederman rt->rt_protocol = cfg->rc_protocol; 348a2519929SEric W. Biederman rt->rt_dev = dev; 349a2519929SEric W. Biederman rt->rt_via_family = cfg->rc_via_family; 350a2519929SEric W. Biederman memcpy(rt->rt_via, cfg->rc_via, cfg->rc_via_alen); 351a2519929SEric W. Biederman 352a2519929SEric W. Biederman mpls_route_update(net, index, NULL, rt, &cfg->rc_nlinfo); 353a2519929SEric W. Biederman 354a2519929SEric W. Biederman dev_put(dev); 355a2519929SEric W. Biederman return 0; 356a2519929SEric W. Biederman 357a2519929SEric W. Biederman errout: 358a2519929SEric W. Biederman if (dev) 359a2519929SEric W. Biederman dev_put(dev); 360a2519929SEric W. Biederman return err; 361a2519929SEric W. Biederman } 362a2519929SEric W. Biederman 363a2519929SEric W. Biederman static int mpls_route_del(struct mpls_route_config *cfg) 364a2519929SEric W. Biederman { 365a2519929SEric W. Biederman struct net *net = cfg->rc_nlinfo.nl_net; 366a2519929SEric W. Biederman unsigned index; 367a2519929SEric W. Biederman int err = -EINVAL; 368a2519929SEric W. Biederman 369a2519929SEric W. Biederman index = cfg->rc_label; 370a2519929SEric W. Biederman 371a2519929SEric W. Biederman /* The first 16 labels are reserved, and may not be removed */ 372a2519929SEric W. Biederman if (index < 16) 373a2519929SEric W. Biederman goto errout; 374a2519929SEric W. Biederman 375a2519929SEric W. Biederman /* The full 20 bit range may not be supported */ 376a2519929SEric W. Biederman if (index >= net->mpls.platform_labels) 377a2519929SEric W. Biederman goto errout; 378a2519929SEric W. Biederman 379a2519929SEric W. Biederman mpls_route_update(net, index, NULL, NULL, &cfg->rc_nlinfo); 380a2519929SEric W. Biederman 381a2519929SEric W. Biederman err = 0; 382a2519929SEric W. Biederman errout: 383a2519929SEric W. Biederman return err; 384a2519929SEric W. Biederman } 385a2519929SEric W. Biederman 3860189197fSEric W. Biederman static void mpls_ifdown(struct net_device *dev) 3870189197fSEric W. Biederman { 3880189197fSEric W. Biederman struct net *net = dev_net(dev); 3890189197fSEric W. Biederman unsigned index; 3900189197fSEric W. Biederman 3910189197fSEric W. Biederman for (index = 0; index < net->mpls.platform_labels; index++) { 3920189197fSEric W. Biederman struct mpls_route *rt = net->mpls.platform_label[index]; 3930189197fSEric W. Biederman if (!rt) 3940189197fSEric W. Biederman continue; 3950189197fSEric W. Biederman if (rt->rt_dev != dev) 3960189197fSEric W. Biederman continue; 3970189197fSEric W. Biederman rt->rt_dev = NULL; 3980189197fSEric W. Biederman } 3990189197fSEric W. Biederman } 4000189197fSEric W. Biederman 4010189197fSEric W. Biederman static int mpls_dev_notify(struct notifier_block *this, unsigned long event, 4020189197fSEric W. Biederman void *ptr) 4030189197fSEric W. Biederman { 4040189197fSEric W. Biederman struct net_device *dev = netdev_notifier_info_to_dev(ptr); 4050189197fSEric W. Biederman 4060189197fSEric W. Biederman switch(event) { 4070189197fSEric W. Biederman case NETDEV_UNREGISTER: 4080189197fSEric W. Biederman mpls_ifdown(dev); 4090189197fSEric W. Biederman break; 4100189197fSEric W. Biederman } 4110189197fSEric W. Biederman return NOTIFY_OK; 4120189197fSEric W. Biederman } 4130189197fSEric W. Biederman 4140189197fSEric W. Biederman static struct notifier_block mpls_dev_notifier = { 4150189197fSEric W. Biederman .notifier_call = mpls_dev_notify, 4160189197fSEric W. Biederman }; 4170189197fSEric W. Biederman 418*03c05665SEric W. Biederman static int nla_put_via(struct sk_buff *skb, 419*03c05665SEric W. Biederman u16 family, const void *addr, int alen) 420*03c05665SEric W. Biederman { 421*03c05665SEric W. Biederman struct nlattr *nla; 422*03c05665SEric W. Biederman struct rtvia *via; 423*03c05665SEric W. Biederman 424*03c05665SEric W. Biederman nla = nla_reserve(skb, RTA_VIA, alen + 2); 425*03c05665SEric W. Biederman if (!nla) 426*03c05665SEric W. Biederman return -EMSGSIZE; 427*03c05665SEric W. Biederman 428*03c05665SEric W. Biederman via = nla_data(nla); 429*03c05665SEric W. Biederman via->rtvia_family = family; 430*03c05665SEric W. Biederman memcpy(via->rtvia_addr, addr, alen); 431*03c05665SEric W. Biederman return 0; 432*03c05665SEric W. Biederman } 433*03c05665SEric W. Biederman 434966bae33SEric W. Biederman int nla_put_labels(struct sk_buff *skb, int attrtype, 435966bae33SEric W. Biederman u8 labels, const u32 label[]) 436966bae33SEric W. Biederman { 437966bae33SEric W. Biederman struct nlattr *nla; 438966bae33SEric W. Biederman struct mpls_shim_hdr *nla_label; 439966bae33SEric W. Biederman bool bos; 440966bae33SEric W. Biederman int i; 441966bae33SEric W. Biederman nla = nla_reserve(skb, attrtype, labels*4); 442966bae33SEric W. Biederman if (!nla) 443966bae33SEric W. Biederman return -EMSGSIZE; 444966bae33SEric W. Biederman 445966bae33SEric W. Biederman nla_label = nla_data(nla); 446966bae33SEric W. Biederman bos = true; 447966bae33SEric W. Biederman for (i = labels - 1; i >= 0; i--) { 448966bae33SEric W. Biederman nla_label[i] = mpls_entry_encode(label[i], 0, 0, bos); 449966bae33SEric W. Biederman bos = false; 450966bae33SEric W. Biederman } 451966bae33SEric W. Biederman 452966bae33SEric W. Biederman return 0; 453966bae33SEric W. Biederman } 454966bae33SEric W. Biederman 455966bae33SEric W. Biederman int nla_get_labels(const struct nlattr *nla, 456966bae33SEric W. Biederman u32 max_labels, u32 *labels, u32 label[]) 457966bae33SEric W. Biederman { 458966bae33SEric W. Biederman unsigned len = nla_len(nla); 459966bae33SEric W. Biederman unsigned nla_labels; 460966bae33SEric W. Biederman struct mpls_shim_hdr *nla_label; 461966bae33SEric W. Biederman bool bos; 462966bae33SEric W. Biederman int i; 463966bae33SEric W. Biederman 464966bae33SEric W. Biederman /* len needs to be an even multiple of 4 (the label size) */ 465966bae33SEric W. Biederman if (len & 3) 466966bae33SEric W. Biederman return -EINVAL; 467966bae33SEric W. Biederman 468966bae33SEric W. Biederman /* Limit the number of new labels allowed */ 469966bae33SEric W. Biederman nla_labels = len/4; 470966bae33SEric W. Biederman if (nla_labels > max_labels) 471966bae33SEric W. Biederman return -EINVAL; 472966bae33SEric W. Biederman 473966bae33SEric W. Biederman nla_label = nla_data(nla); 474966bae33SEric W. Biederman bos = true; 475966bae33SEric W. Biederman for (i = nla_labels - 1; i >= 0; i--, bos = false) { 476966bae33SEric W. Biederman struct mpls_entry_decoded dec; 477966bae33SEric W. Biederman dec = mpls_entry_decode(nla_label + i); 478966bae33SEric W. Biederman 479966bae33SEric W. Biederman /* Ensure the bottom of stack flag is properly set 480966bae33SEric W. Biederman * and ttl and tc are both clear. 481966bae33SEric W. Biederman */ 482966bae33SEric W. Biederman if ((dec.bos != bos) || dec.ttl || dec.tc) 483966bae33SEric W. Biederman return -EINVAL; 484966bae33SEric W. Biederman 485966bae33SEric W. Biederman label[i] = dec.label; 486966bae33SEric W. Biederman } 487966bae33SEric W. Biederman *labels = nla_labels; 488966bae33SEric W. Biederman return 0; 489966bae33SEric W. Biederman } 490966bae33SEric W. Biederman 491*03c05665SEric W. Biederman static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh, 492*03c05665SEric W. Biederman struct mpls_route_config *cfg) 493*03c05665SEric W. Biederman { 494*03c05665SEric W. Biederman struct rtmsg *rtm; 495*03c05665SEric W. Biederman struct nlattr *tb[RTA_MAX+1]; 496*03c05665SEric W. Biederman int index; 497*03c05665SEric W. Biederman int err; 498*03c05665SEric W. Biederman 499*03c05665SEric W. Biederman err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_mpls_policy); 500*03c05665SEric W. Biederman if (err < 0) 501*03c05665SEric W. Biederman goto errout; 502*03c05665SEric W. Biederman 503*03c05665SEric W. Biederman err = -EINVAL; 504*03c05665SEric W. Biederman rtm = nlmsg_data(nlh); 505*03c05665SEric W. Biederman memset(cfg, 0, sizeof(*cfg)); 506*03c05665SEric W. Biederman 507*03c05665SEric W. Biederman if (rtm->rtm_family != AF_MPLS) 508*03c05665SEric W. Biederman goto errout; 509*03c05665SEric W. Biederman if (rtm->rtm_dst_len != 20) 510*03c05665SEric W. Biederman goto errout; 511*03c05665SEric W. Biederman if (rtm->rtm_src_len != 0) 512*03c05665SEric W. Biederman goto errout; 513*03c05665SEric W. Biederman if (rtm->rtm_tos != 0) 514*03c05665SEric W. Biederman goto errout; 515*03c05665SEric W. Biederman if (rtm->rtm_table != RT_TABLE_MAIN) 516*03c05665SEric W. Biederman goto errout; 517*03c05665SEric W. Biederman /* Any value is acceptable for rtm_protocol */ 518*03c05665SEric W. Biederman 519*03c05665SEric W. Biederman /* As mpls uses destination specific addresses 520*03c05665SEric W. Biederman * (or source specific address in the case of multicast) 521*03c05665SEric W. Biederman * all addresses have universal scope. 522*03c05665SEric W. Biederman */ 523*03c05665SEric W. Biederman if (rtm->rtm_scope != RT_SCOPE_UNIVERSE) 524*03c05665SEric W. Biederman goto errout; 525*03c05665SEric W. Biederman if (rtm->rtm_type != RTN_UNICAST) 526*03c05665SEric W. Biederman goto errout; 527*03c05665SEric W. Biederman if (rtm->rtm_flags != 0) 528*03c05665SEric W. Biederman goto errout; 529*03c05665SEric W. Biederman 530*03c05665SEric W. Biederman cfg->rc_label = LABEL_NOT_SPECIFIED; 531*03c05665SEric W. Biederman cfg->rc_protocol = rtm->rtm_protocol; 532*03c05665SEric W. Biederman cfg->rc_nlflags = nlh->nlmsg_flags; 533*03c05665SEric W. Biederman cfg->rc_nlinfo.portid = NETLINK_CB(skb).portid; 534*03c05665SEric W. Biederman cfg->rc_nlinfo.nlh = nlh; 535*03c05665SEric W. Biederman cfg->rc_nlinfo.nl_net = sock_net(skb->sk); 536*03c05665SEric W. Biederman 537*03c05665SEric W. Biederman for (index = 0; index <= RTA_MAX; index++) { 538*03c05665SEric W. Biederman struct nlattr *nla = tb[index]; 539*03c05665SEric W. Biederman if (!nla) 540*03c05665SEric W. Biederman continue; 541*03c05665SEric W. Biederman 542*03c05665SEric W. Biederman switch(index) { 543*03c05665SEric W. Biederman case RTA_OIF: 544*03c05665SEric W. Biederman cfg->rc_ifindex = nla_get_u32(nla); 545*03c05665SEric W. Biederman break; 546*03c05665SEric W. Biederman case RTA_NEWDST: 547*03c05665SEric W. Biederman if (nla_get_labels(nla, MAX_NEW_LABELS, 548*03c05665SEric W. Biederman &cfg->rc_output_labels, 549*03c05665SEric W. Biederman cfg->rc_output_label)) 550*03c05665SEric W. Biederman goto errout; 551*03c05665SEric W. Biederman break; 552*03c05665SEric W. Biederman case RTA_DST: 553*03c05665SEric W. Biederman { 554*03c05665SEric W. Biederman u32 label_count; 555*03c05665SEric W. Biederman if (nla_get_labels(nla, 1, &label_count, 556*03c05665SEric W. Biederman &cfg->rc_label)) 557*03c05665SEric W. Biederman goto errout; 558*03c05665SEric W. Biederman 559*03c05665SEric W. Biederman /* The first 16 labels are reserved, and may not be set */ 560*03c05665SEric W. Biederman if (cfg->rc_label < 16) 561*03c05665SEric W. Biederman goto errout; 562*03c05665SEric W. Biederman 563*03c05665SEric W. Biederman break; 564*03c05665SEric W. Biederman } 565*03c05665SEric W. Biederman case RTA_VIA: 566*03c05665SEric W. Biederman { 567*03c05665SEric W. Biederman struct rtvia *via = nla_data(nla); 568*03c05665SEric W. Biederman cfg->rc_via_family = via->rtvia_family; 569*03c05665SEric W. Biederman cfg->rc_via_alen = nla_len(nla) - 2; 570*03c05665SEric W. Biederman if (cfg->rc_via_alen > MAX_VIA_ALEN) 571*03c05665SEric W. Biederman goto errout; 572*03c05665SEric W. Biederman 573*03c05665SEric W. Biederman /* Validate the address family */ 574*03c05665SEric W. Biederman switch(cfg->rc_via_family) { 575*03c05665SEric W. Biederman case AF_PACKET: 576*03c05665SEric W. Biederman break; 577*03c05665SEric W. Biederman case AF_INET: 578*03c05665SEric W. Biederman if (cfg->rc_via_alen != 4) 579*03c05665SEric W. Biederman goto errout; 580*03c05665SEric W. Biederman break; 581*03c05665SEric W. Biederman case AF_INET6: 582*03c05665SEric W. Biederman if (cfg->rc_via_alen != 16) 583*03c05665SEric W. Biederman goto errout; 584*03c05665SEric W. Biederman break; 585*03c05665SEric W. Biederman default: 586*03c05665SEric W. Biederman /* Unsupported address family */ 587*03c05665SEric W. Biederman goto errout; 588*03c05665SEric W. Biederman } 589*03c05665SEric W. Biederman 590*03c05665SEric W. Biederman memcpy(cfg->rc_via, via->rtvia_addr, cfg->rc_via_alen); 591*03c05665SEric W. Biederman break; 592*03c05665SEric W. Biederman } 593*03c05665SEric W. Biederman default: 594*03c05665SEric W. Biederman /* Unsupported attribute */ 595*03c05665SEric W. Biederman goto errout; 596*03c05665SEric W. Biederman } 597*03c05665SEric W. Biederman } 598*03c05665SEric W. Biederman 599*03c05665SEric W. Biederman err = 0; 600*03c05665SEric W. Biederman errout: 601*03c05665SEric W. Biederman return err; 602*03c05665SEric W. Biederman } 603*03c05665SEric W. Biederman 604*03c05665SEric W. Biederman static int mpls_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh) 605*03c05665SEric W. Biederman { 606*03c05665SEric W. Biederman struct mpls_route_config cfg; 607*03c05665SEric W. Biederman int err; 608*03c05665SEric W. Biederman 609*03c05665SEric W. Biederman err = rtm_to_route_config(skb, nlh, &cfg); 610*03c05665SEric W. Biederman if (err < 0) 611*03c05665SEric W. Biederman return err; 612*03c05665SEric W. Biederman 613*03c05665SEric W. Biederman return mpls_route_del(&cfg); 614*03c05665SEric W. Biederman } 615*03c05665SEric W. Biederman 616*03c05665SEric W. Biederman 617*03c05665SEric W. Biederman static int mpls_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh) 618*03c05665SEric W. Biederman { 619*03c05665SEric W. Biederman struct mpls_route_config cfg; 620*03c05665SEric W. Biederman int err; 621*03c05665SEric W. Biederman 622*03c05665SEric W. Biederman err = rtm_to_route_config(skb, nlh, &cfg); 623*03c05665SEric W. Biederman if (err < 0) 624*03c05665SEric W. Biederman return err; 625*03c05665SEric W. Biederman 626*03c05665SEric W. Biederman return mpls_route_add(&cfg); 627*03c05665SEric W. Biederman } 628*03c05665SEric W. Biederman 629*03c05665SEric W. Biederman static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event, 630*03c05665SEric W. Biederman u32 label, struct mpls_route *rt, int flags) 631*03c05665SEric W. Biederman { 632*03c05665SEric W. Biederman struct nlmsghdr *nlh; 633*03c05665SEric W. Biederman struct rtmsg *rtm; 634*03c05665SEric W. Biederman 635*03c05665SEric W. Biederman nlh = nlmsg_put(skb, portid, seq, event, sizeof(*rtm), flags); 636*03c05665SEric W. Biederman if (nlh == NULL) 637*03c05665SEric W. Biederman return -EMSGSIZE; 638*03c05665SEric W. Biederman 639*03c05665SEric W. Biederman rtm = nlmsg_data(nlh); 640*03c05665SEric W. Biederman rtm->rtm_family = AF_MPLS; 641*03c05665SEric W. Biederman rtm->rtm_dst_len = 20; 642*03c05665SEric W. Biederman rtm->rtm_src_len = 0; 643*03c05665SEric W. Biederman rtm->rtm_tos = 0; 644*03c05665SEric W. Biederman rtm->rtm_table = RT_TABLE_MAIN; 645*03c05665SEric W. Biederman rtm->rtm_protocol = rt->rt_protocol; 646*03c05665SEric W. Biederman rtm->rtm_scope = RT_SCOPE_UNIVERSE; 647*03c05665SEric W. Biederman rtm->rtm_type = RTN_UNICAST; 648*03c05665SEric W. Biederman rtm->rtm_flags = 0; 649*03c05665SEric W. Biederman 650*03c05665SEric W. Biederman if (rt->rt_labels && 651*03c05665SEric W. Biederman nla_put_labels(skb, RTA_NEWDST, rt->rt_labels, rt->rt_label)) 652*03c05665SEric W. Biederman goto nla_put_failure; 653*03c05665SEric W. Biederman if (nla_put_via(skb, rt->rt_via_family, rt->rt_via, rt->rt_via_alen)) 654*03c05665SEric W. Biederman goto nla_put_failure; 655*03c05665SEric W. Biederman if (rt->rt_dev && nla_put_u32(skb, RTA_OIF, rt->rt_dev->ifindex)) 656*03c05665SEric W. Biederman goto nla_put_failure; 657*03c05665SEric W. Biederman if (nla_put_labels(skb, RTA_DST, 1, &label)) 658*03c05665SEric W. Biederman goto nla_put_failure; 659*03c05665SEric W. Biederman 660*03c05665SEric W. Biederman nlmsg_end(skb, nlh); 661*03c05665SEric W. Biederman return 0; 662*03c05665SEric W. Biederman 663*03c05665SEric W. Biederman nla_put_failure: 664*03c05665SEric W. Biederman nlmsg_cancel(skb, nlh); 665*03c05665SEric W. Biederman return -EMSGSIZE; 666*03c05665SEric W. Biederman } 667*03c05665SEric W. Biederman 668*03c05665SEric W. Biederman static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb) 669*03c05665SEric W. Biederman { 670*03c05665SEric W. Biederman struct net *net = sock_net(skb->sk); 671*03c05665SEric W. Biederman unsigned int index; 672*03c05665SEric W. Biederman 673*03c05665SEric W. Biederman ASSERT_RTNL(); 674*03c05665SEric W. Biederman 675*03c05665SEric W. Biederman index = cb->args[0]; 676*03c05665SEric W. Biederman if (index < 16) 677*03c05665SEric W. Biederman index = 16; 678*03c05665SEric W. Biederman 679*03c05665SEric W. Biederman for (; index < net->mpls.platform_labels; index++) { 680*03c05665SEric W. Biederman struct mpls_route *rt; 681*03c05665SEric W. Biederman rt = net->mpls.platform_label[index]; 682*03c05665SEric W. Biederman if (!rt) 683*03c05665SEric W. Biederman continue; 684*03c05665SEric W. Biederman 685*03c05665SEric W. Biederman if (mpls_dump_route(skb, NETLINK_CB(cb->skb).portid, 686*03c05665SEric W. Biederman cb->nlh->nlmsg_seq, RTM_NEWROUTE, 687*03c05665SEric W. Biederman index, rt, NLM_F_MULTI) < 0) 688*03c05665SEric W. Biederman break; 689*03c05665SEric W. Biederman } 690*03c05665SEric W. Biederman cb->args[0] = index; 691*03c05665SEric W. Biederman 692*03c05665SEric W. Biederman return skb->len; 693*03c05665SEric W. Biederman } 694*03c05665SEric W. Biederman 6957720c01fSEric W. Biederman static int resize_platform_label_table(struct net *net, size_t limit) 6967720c01fSEric W. Biederman { 6977720c01fSEric W. Biederman size_t size = sizeof(struct mpls_route *) * limit; 6987720c01fSEric W. Biederman size_t old_limit; 6997720c01fSEric W. Biederman size_t cp_size; 7007720c01fSEric W. Biederman struct mpls_route __rcu **labels = NULL, **old; 7017720c01fSEric W. Biederman struct mpls_route *rt0 = NULL, *rt2 = NULL; 7027720c01fSEric W. Biederman unsigned index; 7037720c01fSEric W. Biederman 7047720c01fSEric W. Biederman if (size) { 7057720c01fSEric W. Biederman labels = kzalloc(size, GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY); 7067720c01fSEric W. Biederman if (!labels) 7077720c01fSEric W. Biederman labels = vzalloc(size); 7087720c01fSEric W. Biederman 7097720c01fSEric W. Biederman if (!labels) 7107720c01fSEric W. Biederman goto nolabels; 7117720c01fSEric W. Biederman } 7127720c01fSEric W. Biederman 7137720c01fSEric W. Biederman /* In case the predefined labels need to be populated */ 7147720c01fSEric W. Biederman if (limit > LABEL_IPV4_EXPLICIT_NULL) { 7157720c01fSEric W. Biederman struct net_device *lo = net->loopback_dev; 7167720c01fSEric W. Biederman rt0 = mpls_rt_alloc(lo->addr_len); 7177720c01fSEric W. Biederman if (!rt0) 7187720c01fSEric W. Biederman goto nort0; 7197720c01fSEric W. Biederman rt0->rt_dev = lo; 7207720c01fSEric W. Biederman rt0->rt_protocol = RTPROT_KERNEL; 7217720c01fSEric W. Biederman rt0->rt_via_family = AF_PACKET; 7227720c01fSEric W. Biederman memcpy(rt0->rt_via, lo->dev_addr, lo->addr_len); 7237720c01fSEric W. Biederman } 7247720c01fSEric W. Biederman if (limit > LABEL_IPV6_EXPLICIT_NULL) { 7257720c01fSEric W. Biederman struct net_device *lo = net->loopback_dev; 7267720c01fSEric W. Biederman rt2 = mpls_rt_alloc(lo->addr_len); 7277720c01fSEric W. Biederman if (!rt2) 7287720c01fSEric W. Biederman goto nort2; 7297720c01fSEric W. Biederman rt2->rt_dev = lo; 7307720c01fSEric W. Biederman rt2->rt_protocol = RTPROT_KERNEL; 7317720c01fSEric W. Biederman rt2->rt_via_family = AF_PACKET; 7327720c01fSEric W. Biederman memcpy(rt2->rt_via, lo->dev_addr, lo->addr_len); 7337720c01fSEric W. Biederman } 7347720c01fSEric W. Biederman 7357720c01fSEric W. Biederman rtnl_lock(); 7367720c01fSEric W. Biederman /* Remember the original table */ 7377720c01fSEric W. Biederman old = net->mpls.platform_label; 7387720c01fSEric W. Biederman old_limit = net->mpls.platform_labels; 7397720c01fSEric W. Biederman 7407720c01fSEric W. Biederman /* Free any labels beyond the new table */ 7417720c01fSEric W. Biederman for (index = limit; index < old_limit; index++) 7427720c01fSEric W. Biederman mpls_route_update(net, index, NULL, NULL, NULL); 7437720c01fSEric W. Biederman 7447720c01fSEric W. Biederman /* Copy over the old labels */ 7457720c01fSEric W. Biederman cp_size = size; 7467720c01fSEric W. Biederman if (old_limit < limit) 7477720c01fSEric W. Biederman cp_size = old_limit * sizeof(struct mpls_route *); 7487720c01fSEric W. Biederman 7497720c01fSEric W. Biederman memcpy(labels, old, cp_size); 7507720c01fSEric W. Biederman 7517720c01fSEric W. Biederman /* If needed set the predefined labels */ 7527720c01fSEric W. Biederman if ((old_limit <= LABEL_IPV6_EXPLICIT_NULL) && 7537720c01fSEric W. Biederman (limit > LABEL_IPV6_EXPLICIT_NULL)) { 7547720c01fSEric W. Biederman labels[LABEL_IPV6_EXPLICIT_NULL] = rt2; 7557720c01fSEric W. Biederman rt2 = NULL; 7567720c01fSEric W. Biederman } 7577720c01fSEric W. Biederman 7587720c01fSEric W. Biederman if ((old_limit <= LABEL_IPV4_EXPLICIT_NULL) && 7597720c01fSEric W. Biederman (limit > LABEL_IPV4_EXPLICIT_NULL)) { 7607720c01fSEric W. Biederman labels[LABEL_IPV4_EXPLICIT_NULL] = rt0; 7617720c01fSEric W. Biederman rt0 = NULL; 7627720c01fSEric W. Biederman } 7637720c01fSEric W. Biederman 7647720c01fSEric W. Biederman /* Update the global pointers */ 7657720c01fSEric W. Biederman net->mpls.platform_labels = limit; 7667720c01fSEric W. Biederman net->mpls.platform_label = labels; 7677720c01fSEric W. Biederman 7687720c01fSEric W. Biederman rtnl_unlock(); 7697720c01fSEric W. Biederman 7707720c01fSEric W. Biederman mpls_rt_free(rt2); 7717720c01fSEric W. Biederman mpls_rt_free(rt0); 7727720c01fSEric W. Biederman 7737720c01fSEric W. Biederman if (old) { 7747720c01fSEric W. Biederman synchronize_rcu(); 7757720c01fSEric W. Biederman kvfree(old); 7767720c01fSEric W. Biederman } 7777720c01fSEric W. Biederman return 0; 7787720c01fSEric W. Biederman 7797720c01fSEric W. Biederman nort2: 7807720c01fSEric W. Biederman mpls_rt_free(rt0); 7817720c01fSEric W. Biederman nort0: 7827720c01fSEric W. Biederman kvfree(labels); 7837720c01fSEric W. Biederman nolabels: 7847720c01fSEric W. Biederman return -ENOMEM; 7857720c01fSEric W. Biederman } 7867720c01fSEric W. Biederman 7877720c01fSEric W. Biederman static int mpls_platform_labels(struct ctl_table *table, int write, 7887720c01fSEric W. Biederman void __user *buffer, size_t *lenp, loff_t *ppos) 7897720c01fSEric W. Biederman { 7907720c01fSEric W. Biederman struct net *net = table->data; 7917720c01fSEric W. Biederman int platform_labels = net->mpls.platform_labels; 7927720c01fSEric W. Biederman int ret; 7937720c01fSEric W. Biederman struct ctl_table tmp = { 7947720c01fSEric W. Biederman .procname = table->procname, 7957720c01fSEric W. Biederman .data = &platform_labels, 7967720c01fSEric W. Biederman .maxlen = sizeof(int), 7977720c01fSEric W. Biederman .mode = table->mode, 7987720c01fSEric W. Biederman .extra1 = &zero, 7997720c01fSEric W. Biederman .extra2 = &label_limit, 8007720c01fSEric W. Biederman }; 8017720c01fSEric W. Biederman 8027720c01fSEric W. Biederman ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); 8037720c01fSEric W. Biederman 8047720c01fSEric W. Biederman if (write && ret == 0) 8057720c01fSEric W. Biederman ret = resize_platform_label_table(net, platform_labels); 8067720c01fSEric W. Biederman 8077720c01fSEric W. Biederman return ret; 8087720c01fSEric W. Biederman } 8097720c01fSEric W. Biederman 8107720c01fSEric W. Biederman static struct ctl_table mpls_table[] = { 8117720c01fSEric W. Biederman { 8127720c01fSEric W. Biederman .procname = "platform_labels", 8137720c01fSEric W. Biederman .data = NULL, 8147720c01fSEric W. Biederman .maxlen = sizeof(int), 8157720c01fSEric W. Biederman .mode = 0644, 8167720c01fSEric W. Biederman .proc_handler = mpls_platform_labels, 8177720c01fSEric W. Biederman }, 8187720c01fSEric W. Biederman { } 8197720c01fSEric W. Biederman }; 8207720c01fSEric W. Biederman 8210189197fSEric W. Biederman static int mpls_net_init(struct net *net) 8220189197fSEric W. Biederman { 8237720c01fSEric W. Biederman struct ctl_table *table; 8247720c01fSEric W. Biederman 8250189197fSEric W. Biederman net->mpls.platform_labels = 0; 8260189197fSEric W. Biederman net->mpls.platform_label = NULL; 8270189197fSEric W. Biederman 8287720c01fSEric W. Biederman table = kmemdup(mpls_table, sizeof(mpls_table), GFP_KERNEL); 8297720c01fSEric W. Biederman if (table == NULL) 8307720c01fSEric W. Biederman return -ENOMEM; 8317720c01fSEric W. Biederman 8327720c01fSEric W. Biederman table[0].data = net; 8337720c01fSEric W. Biederman net->mpls.ctl = register_net_sysctl(net, "net/mpls", table); 8347720c01fSEric W. Biederman if (net->mpls.ctl == NULL) 8357720c01fSEric W. Biederman return -ENOMEM; 8367720c01fSEric W. Biederman 8370189197fSEric W. Biederman return 0; 8380189197fSEric W. Biederman } 8390189197fSEric W. Biederman 8400189197fSEric W. Biederman static void mpls_net_exit(struct net *net) 8410189197fSEric W. Biederman { 8427720c01fSEric W. Biederman struct ctl_table *table; 8430189197fSEric W. Biederman unsigned int index; 8440189197fSEric W. Biederman 8457720c01fSEric W. Biederman table = net->mpls.ctl->ctl_table_arg; 8467720c01fSEric W. Biederman unregister_net_sysctl_table(net->mpls.ctl); 8477720c01fSEric W. Biederman kfree(table); 8487720c01fSEric W. Biederman 8490189197fSEric W. Biederman /* An rcu grace period haselapsed since there was a device in 8500189197fSEric W. Biederman * the network namespace (and thus the last in fqlight packet) 8510189197fSEric W. Biederman * left this network namespace. This is because 8520189197fSEric W. Biederman * unregister_netdevice_many and netdev_run_todo has completed 8530189197fSEric W. Biederman * for each network device that was in this network namespace. 8540189197fSEric W. Biederman * 8550189197fSEric W. Biederman * As such no additional rcu synchronization is necessary when 8560189197fSEric W. Biederman * freeing the platform_label table. 8570189197fSEric W. Biederman */ 8580189197fSEric W. Biederman rtnl_lock(); 8590189197fSEric W. Biederman for (index = 0; index < net->mpls.platform_labels; index++) { 8600189197fSEric W. Biederman struct mpls_route *rt = net->mpls.platform_label[index]; 8610189197fSEric W. Biederman rcu_assign_pointer(net->mpls.platform_label[index], NULL); 8620189197fSEric W. Biederman mpls_rt_free(rt); 8630189197fSEric W. Biederman } 8640189197fSEric W. Biederman rtnl_unlock(); 8650189197fSEric W. Biederman 8660189197fSEric W. Biederman kvfree(net->mpls.platform_label); 8670189197fSEric W. Biederman } 8680189197fSEric W. Biederman 8690189197fSEric W. Biederman static struct pernet_operations mpls_net_ops = { 8700189197fSEric W. Biederman .init = mpls_net_init, 8710189197fSEric W. Biederman .exit = mpls_net_exit, 8720189197fSEric W. Biederman }; 8730189197fSEric W. Biederman 8740189197fSEric W. Biederman static int __init mpls_init(void) 8750189197fSEric W. Biederman { 8760189197fSEric W. Biederman int err; 8770189197fSEric W. Biederman 8780189197fSEric W. Biederman BUILD_BUG_ON(sizeof(struct mpls_shim_hdr) != 4); 8790189197fSEric W. Biederman 8800189197fSEric W. Biederman err = register_pernet_subsys(&mpls_net_ops); 8810189197fSEric W. Biederman if (err) 8820189197fSEric W. Biederman goto out; 8830189197fSEric W. Biederman 8840189197fSEric W. Biederman err = register_netdevice_notifier(&mpls_dev_notifier); 8850189197fSEric W. Biederman if (err) 8860189197fSEric W. Biederman goto out_unregister_pernet; 8870189197fSEric W. Biederman 8880189197fSEric W. Biederman dev_add_pack(&mpls_packet_type); 8890189197fSEric W. Biederman 890*03c05665SEric W. Biederman rtnl_register(PF_MPLS, RTM_NEWROUTE, mpls_rtm_newroute, NULL, NULL); 891*03c05665SEric W. Biederman rtnl_register(PF_MPLS, RTM_DELROUTE, mpls_rtm_delroute, NULL, NULL); 892*03c05665SEric W. Biederman rtnl_register(PF_MPLS, RTM_GETROUTE, NULL, mpls_dump_routes, NULL); 8930189197fSEric W. Biederman err = 0; 8940189197fSEric W. Biederman out: 8950189197fSEric W. Biederman return err; 8960189197fSEric W. Biederman 8970189197fSEric W. Biederman out_unregister_pernet: 8980189197fSEric W. Biederman unregister_pernet_subsys(&mpls_net_ops); 8990189197fSEric W. Biederman goto out; 9000189197fSEric W. Biederman } 9010189197fSEric W. Biederman module_init(mpls_init); 9020189197fSEric W. Biederman 9030189197fSEric W. Biederman static void __exit mpls_exit(void) 9040189197fSEric W. Biederman { 905*03c05665SEric W. Biederman rtnl_unregister_all(PF_MPLS); 9060189197fSEric W. Biederman dev_remove_pack(&mpls_packet_type); 9070189197fSEric W. Biederman unregister_netdevice_notifier(&mpls_dev_notifier); 9080189197fSEric W. Biederman unregister_pernet_subsys(&mpls_net_ops); 9090189197fSEric W. Biederman } 9100189197fSEric W. Biederman module_exit(mpls_exit); 9110189197fSEric W. Biederman 9120189197fSEric W. Biederman MODULE_DESCRIPTION("MultiProtocol Label Switching"); 9130189197fSEric W. Biederman MODULE_LICENSE("GPL v2"); 9140189197fSEric W. Biederman MODULE_ALIAS_NETPROTO(PF_MPLS); 915