Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mpls: ip tunnel support

This implementation uses lwtunnel infrastructure to register
hooks for mpls tunnel encaps.

It picks cues from iptunnel_encaps infrastructure and previous
mpls iptunnel RFC patches from Eric W. Biederman and Robert Shearman

Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Roopa Prabhu and committed by
David S. Miller
e3e4712e face0188

+304 -1
+6
include/linux/mpls_iptunnel.h
··· 1 + #ifndef _LINUX_MPLS_IPTUNNEL_H 2 + #define _LINUX_MPLS_IPTUNNEL_H 3 + 4 + #include <uapi/linux/mpls_iptunnel.h> 5 + 6 + #endif /* _LINUX_MPLS_IPTUNNEL_H */
+29
include/net/mpls_iptunnel.h
··· 1 + /* 2 + * Copyright (c) 2015 Cumulus Networks, Inc. 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of version 2 of the GNU General Public 6 + * License as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, but 9 + * WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 + * General Public License for more details. 12 + */ 13 + 14 + #ifndef _NET_MPLS_IPTUNNEL_H 15 + #define _NET_MPLS_IPTUNNEL_H 1 16 + 17 + #define MAX_NEW_LABELS 2 18 + 19 + struct mpls_iptunnel_encap { 20 + u32 label[MAX_NEW_LABELS]; 21 + u32 labels; 22 + }; 23 + 24 + static inline struct mpls_iptunnel_encap *mpls_lwtunnel_encap(struct lwtunnel_state *lwtstate) 25 + { 26 + return (struct mpls_iptunnel_encap *)lwtstate->data; 27 + } 28 + 29 + #endif
+28
include/uapi/linux/mpls_iptunnel.h
··· 1 + /* 2 + * mpls tunnel api 3 + * 4 + * Authors: 5 + * Roopa Prabhu <roopa@cumulusnetworks.com> 6 + * 7 + * This program is free software; you can redistribute it and/or 8 + * modify it under the terms of the GNU General Public License 9 + * as published by the Free Software Foundation; either version 10 + * 2 of the License, or (at your option) any later version. 11 + */ 12 + 13 + #ifndef _UAPI_LINUX_MPLS_IPTUNNEL_H 14 + #define _UAPI_LINUX_MPLS_IPTUNNEL_H 15 + 16 + /* MPLS tunnel attributes 17 + * [RTA_ENCAP] = { 18 + * [MPLS_IPTUNNEL_DST] 19 + * } 20 + */ 21 + enum { 22 + MPLS_IPTUNNEL_UNSPEC, 23 + MPLS_IPTUNNEL_DST, 24 + __MPLS_IPTUNNEL_MAX, 25 + }; 26 + #define MPLS_IPTUNNEL_MAX (__MPLS_IPTUNNEL_MAX - 1) 27 + 28 + #endif /* _UAPI_LINUX_MPLS_IPTUNNEL_H */
+7 -1
net/mpls/Kconfig
··· 24 24 25 25 config MPLS_ROUTING 26 26 tristate "MPLS: routing support" 27 - help 27 + ---help--- 28 28 Add support for forwarding of mpls packets. 29 + 30 + config MPLS_IPTUNNEL 31 + tristate "MPLS: IP over MPLS tunnel support" 32 + depends on LWTUNNEL && MPLS_ROUTING 33 + ---help--- 34 + mpls ip tunnel support. 29 35 30 36 endif # MPLS
+1
net/mpls/Makefile
··· 3 3 # 4 4 obj-$(CONFIG_NET_MPLS_GSO) += mpls_gso.o 5 5 obj-$(CONFIG_MPLS_ROUTING) += mpls_router.o 6 + obj-$(CONFIG_MPLS_IPTUNNEL) += mpls_iptunnel.o 6 7 7 8 mpls_router-y := af_mpls.o
+233
net/mpls/mpls_iptunnel.c
··· 1 + /* 2 + * mpls tunnels An implementation mpls tunnels using the light weight tunnel 3 + * infrastructure 4 + * 5 + * Authors: Roopa Prabhu, <roopa@cumulusnetworks.com> 6 + * 7 + * This program is free software; you can redistribute it and/or 8 + * modify it under the terms of the GNU General Public License 9 + * as published by the Free Software Foundation; either version 10 + * 2 of the License, or (at your option) any later version. 11 + * 12 + */ 13 + #include <linux/types.h> 14 + #include <linux/skbuff.h> 15 + #include <linux/net.h> 16 + #include <linux/module.h> 17 + #include <linux/mpls.h> 18 + #include <linux/vmalloc.h> 19 + #include <net/ip.h> 20 + #include <net/dst.h> 21 + #include <net/lwtunnel.h> 22 + #include <net/netevent.h> 23 + #include <net/netns/generic.h> 24 + #include <net/ip6_fib.h> 25 + #include <net/route.h> 26 + #include <net/mpls_iptunnel.h> 27 + #include <linux/mpls_iptunnel.h> 28 + #include "internal.h" 29 + 30 + static const struct nla_policy mpls_iptunnel_policy[MPLS_IPTUNNEL_MAX + 1] = { 31 + [MPLS_IPTUNNEL_DST] = { .type = NLA_U32 }, 32 + }; 33 + 34 + static unsigned int mpls_encap_size(struct mpls_iptunnel_encap *en) 35 + { 36 + /* The size of the layer 2.5 labels to be added for this route */ 37 + return en->labels * sizeof(struct mpls_shim_hdr); 38 + } 39 + 40 + int mpls_output(struct sock *sk, struct sk_buff *skb) 41 + { 42 + struct mpls_iptunnel_encap *tun_encap_info; 43 + struct mpls_shim_hdr *hdr; 44 + struct net_device *out_dev; 45 + unsigned int hh_len; 46 + unsigned int new_header_size; 47 + unsigned int mtu; 48 + struct dst_entry *dst = skb_dst(skb); 49 + struct rtable *rt = NULL; 50 + struct rt6_info *rt6 = NULL; 51 + struct lwtunnel_state *lwtstate = NULL; 52 + int err = 0; 53 + bool bos; 54 + int i; 55 + unsigned int ttl; 56 + 57 + /* Obtain the ttl */ 58 + if (skb->protocol == htons(ETH_P_IP)) { 59 + ttl = ip_hdr(skb)->ttl; 60 + rt = (struct rtable *)dst; 61 + lwtstate = rt->rt_lwtstate; 62 + } else if (skb->protocol == htons(ETH_P_IPV6)) { 63 + ttl = ipv6_hdr(skb)->hop_limit; 64 + rt6 = (struct rt6_info *)dst; 65 + lwtstate = rt6->rt6i_lwtstate; 66 + } else { 67 + goto drop; 68 + } 69 + 70 + skb_orphan(skb); 71 + 72 + /* Find the output device */ 73 + out_dev = rcu_dereference(dst->dev); 74 + if (!mpls_output_possible(out_dev) || 75 + !lwtstate || skb_warn_if_lro(skb)) 76 + goto drop; 77 + 78 + skb_forward_csum(skb); 79 + 80 + tun_encap_info = mpls_lwtunnel_encap(lwtstate); 81 + 82 + /* Verify the destination can hold the packet */ 83 + new_header_size = mpls_encap_size(tun_encap_info); 84 + mtu = mpls_dev_mtu(out_dev); 85 + if (mpls_pkt_too_big(skb, mtu - new_header_size)) 86 + goto drop; 87 + 88 + hh_len = LL_RESERVED_SPACE(out_dev); 89 + if (!out_dev->header_ops) 90 + hh_len = 0; 91 + 92 + /* Ensure there is enough space for the headers in the skb */ 93 + if (skb_cow(skb, hh_len + new_header_size)) 94 + goto drop; 95 + 96 + skb_push(skb, new_header_size); 97 + skb_reset_network_header(skb); 98 + 99 + skb->dev = out_dev; 100 + skb->protocol = htons(ETH_P_MPLS_UC); 101 + 102 + /* Push the new labels */ 103 + hdr = mpls_hdr(skb); 104 + bos = true; 105 + for (i = tun_encap_info->labels - 1; i >= 0; i--) { 106 + hdr[i] = mpls_entry_encode(tun_encap_info->label[i], 107 + ttl, 0, bos); 108 + bos = false; 109 + } 110 + 111 + if (rt) 112 + err = neigh_xmit(NEIGH_ARP_TABLE, out_dev, &rt->rt_gateway, 113 + skb); 114 + else if (rt6) 115 + err = neigh_xmit(NEIGH_ND_TABLE, out_dev, &rt6->rt6i_gateway, 116 + skb); 117 + if (err) 118 + net_dbg_ratelimited("%s: packet transmission failed: %d\n", 119 + __func__, err); 120 + 121 + return 0; 122 + 123 + drop: 124 + kfree_skb(skb); 125 + return -EINVAL; 126 + } 127 + 128 + static int mpls_build_state(struct net_device *dev, struct nlattr *nla, 129 + struct lwtunnel_state **ts) 130 + { 131 + struct mpls_iptunnel_encap *tun_encap_info; 132 + struct nlattr *tb[MPLS_IPTUNNEL_MAX + 1]; 133 + struct lwtunnel_state *newts; 134 + int tun_encap_info_len; 135 + int ret; 136 + 137 + ret = nla_parse_nested(tb, MPLS_IPTUNNEL_MAX, nla, 138 + mpls_iptunnel_policy); 139 + if (ret < 0) 140 + return ret; 141 + 142 + if (!tb[MPLS_IPTUNNEL_DST]) 143 + return -EINVAL; 144 + 145 + tun_encap_info_len = sizeof(*tun_encap_info); 146 + 147 + newts = lwtunnel_state_alloc(tun_encap_info_len); 148 + if (!newts) 149 + return -ENOMEM; 150 + 151 + newts->len = tun_encap_info_len; 152 + tun_encap_info = mpls_lwtunnel_encap(newts); 153 + ret = nla_get_labels(tb[MPLS_IPTUNNEL_DST], MAX_NEW_LABELS, 154 + &tun_encap_info->labels, tun_encap_info->label); 155 + if (ret) 156 + goto errout; 157 + newts->type = LWTUNNEL_ENCAP_MPLS; 158 + newts->flags |= LWTUNNEL_STATE_OUTPUT_REDIRECT; 159 + 160 + *ts = newts; 161 + 162 + return 0; 163 + 164 + errout: 165 + kfree(newts); 166 + *ts = NULL; 167 + 168 + return ret; 169 + } 170 + 171 + static int mpls_fill_encap_info(struct sk_buff *skb, 172 + struct lwtunnel_state *lwtstate) 173 + { 174 + struct mpls_iptunnel_encap *tun_encap_info; 175 + 176 + tun_encap_info = mpls_lwtunnel_encap(lwtstate); 177 + 178 + if (nla_put_labels(skb, MPLS_IPTUNNEL_DST, tun_encap_info->labels, 179 + tun_encap_info->label)) 180 + goto nla_put_failure; 181 + 182 + return 0; 183 + 184 + nla_put_failure: 185 + return -EMSGSIZE; 186 + } 187 + 188 + static int mpls_encap_nlsize(struct lwtunnel_state *lwtstate) 189 + { 190 + struct mpls_iptunnel_encap *tun_encap_info; 191 + 192 + tun_encap_info = mpls_lwtunnel_encap(lwtstate); 193 + 194 + return nla_total_size(tun_encap_info->labels * 4); 195 + } 196 + 197 + static int mpls_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b) 198 + { 199 + struct mpls_iptunnel_encap *a_hdr = mpls_lwtunnel_encap(a); 200 + struct mpls_iptunnel_encap *b_hdr = mpls_lwtunnel_encap(b); 201 + int l; 202 + 203 + if (a_hdr->labels != b_hdr->labels) 204 + return 1; 205 + 206 + for (l = 0; l < MAX_NEW_LABELS; l++) 207 + if (a_hdr->label[l] != b_hdr->label[l]) 208 + return 1; 209 + return 0; 210 + } 211 + 212 + static const struct lwtunnel_encap_ops mpls_iptun_ops = { 213 + .build_state = mpls_build_state, 214 + .output = mpls_output, 215 + .fill_encap = mpls_fill_encap_info, 216 + .get_encap_size = mpls_encap_nlsize, 217 + .cmp_encap = mpls_encap_cmp, 218 + }; 219 + 220 + static int __init mpls_iptunnel_init(void) 221 + { 222 + return lwtunnel_encap_add_ops(&mpls_iptun_ops, LWTUNNEL_ENCAP_MPLS); 223 + } 224 + module_init(mpls_iptunnel_init); 225 + 226 + static void __exit mpls_iptunnel_exit(void) 227 + { 228 + lwtunnel_encap_del_ops(&mpls_iptun_ops, LWTUNNEL_ENCAP_MPLS); 229 + } 230 + module_exit(mpls_iptunnel_exit); 231 + 232 + MODULE_DESCRIPTION("MultiProtocol Label Switching IP Tunnels"); 233 + MODULE_LICENSE("GPL v2");