Blame view
net/mpls/mpls_iptunnel.c
7.65 KB
e3e4712ec mpls: ip tunnel s... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
/* * mpls tunnels An implementation mpls tunnels using the light weight tunnel * infrastructure * * Authors: Roopa Prabhu, <roopa@cumulusnetworks.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * */ #include <linux/types.h> #include <linux/skbuff.h> #include <linux/net.h> #include <linux/module.h> #include <linux/mpls.h> #include <linux/vmalloc.h> #include <net/ip.h> #include <net/dst.h> #include <net/lwtunnel.h> #include <net/netevent.h> #include <net/netns/generic.h> #include <net/ip6_fib.h> #include <net/route.h> #include <net/mpls_iptunnel.h> #include <linux/mpls_iptunnel.h> #include "internal.h" static const struct nla_policy mpls_iptunnel_policy[MPLS_IPTUNNEL_MAX + 1] = { [MPLS_IPTUNNEL_DST] = { .type = NLA_U32 }, |
a59166e47 mpls: allow TTL p... |
32 |
[MPLS_IPTUNNEL_TTL] = { .type = NLA_U8 }, |
e3e4712ec mpls: ip tunnel s... |
33 34 35 36 37 38 39 |
}; static unsigned int mpls_encap_size(struct mpls_iptunnel_encap *en) { /* The size of the layer 2.5 labels to be added for this route */ return en->labels * sizeof(struct mpls_shim_hdr); } |
14972cbd3 net: lwtunnel: Ha... |
40 |
static int mpls_xmit(struct sk_buff *skb) |
e3e4712ec mpls: ip tunnel s... |
41 42 43 44 45 46 47 48 49 50 |
{ struct mpls_iptunnel_encap *tun_encap_info; struct mpls_shim_hdr *hdr; struct net_device *out_dev; unsigned int hh_len; unsigned int new_header_size; unsigned int mtu; struct dst_entry *dst = skb_dst(skb); struct rtable *rt = NULL; struct rt6_info *rt6 = NULL; |
27d691056 mpls: Packet stats |
51 |
struct mpls_dev *out_mdev; |
a59166e47 mpls: allow TTL p... |
52 |
struct net *net; |
e3e4712ec mpls: ip tunnel s... |
53 54 55 56 |
int err = 0; bool bos; int i; unsigned int ttl; |
27d691056 mpls: Packet stats |
57 58 |
/* Find the output device */ out_dev = dst->dev; |
a59166e47 mpls: allow TTL p... |
59 |
net = dev_net(out_dev); |
e3e4712ec mpls: ip tunnel s... |
60 61 |
skb_orphan(skb); |
e3e4712ec mpls: ip tunnel s... |
62 |
if (!mpls_output_possible(out_dev) || |
61adedf3e route: move lwtun... |
63 |
!dst->lwtstate || skb_warn_if_lro(skb)) |
e3e4712ec mpls: ip tunnel s... |
64 65 66 |
goto drop; skb_forward_csum(skb); |
61adedf3e route: move lwtun... |
67 |
tun_encap_info = mpls_lwtunnel_encap(dst->lwtstate); |
e3e4712ec mpls: ip tunnel s... |
68 |
|
a59166e47 mpls: allow TTL p... |
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
/* Obtain the ttl using the following set of rules. * * LWT ttl propagation setting: * - disabled => use default TTL value from LWT * - enabled => use TTL value from IPv4/IPv6 header * - default => * Global ttl propagation setting: * - disabled => use default TTL value from global setting * - enabled => use TTL value from IPv4/IPv6 header */ if (dst->ops->family == AF_INET) { if (tun_encap_info->ttl_propagate == MPLS_TTL_PROP_DISABLED) ttl = tun_encap_info->default_ttl; else if (tun_encap_info->ttl_propagate == MPLS_TTL_PROP_DEFAULT && !net->mpls.ip_ttl_propagate) ttl = net->mpls.default_ttl; else ttl = ip_hdr(skb)->ttl; rt = (struct rtable *)dst; } else if (dst->ops->family == AF_INET6) { if (tun_encap_info->ttl_propagate == MPLS_TTL_PROP_DISABLED) ttl = tun_encap_info->default_ttl; else if (tun_encap_info->ttl_propagate == MPLS_TTL_PROP_DEFAULT && !net->mpls.ip_ttl_propagate) ttl = net->mpls.default_ttl; else ttl = ipv6_hdr(skb)->hop_limit; rt6 = (struct rt6_info *)dst; } else { goto drop; } |
e3e4712ec mpls: ip tunnel s... |
100 101 102 103 104 105 106 107 108 109 110 111 112 |
/* Verify the destination can hold the packet */ new_header_size = mpls_encap_size(tun_encap_info); mtu = mpls_dev_mtu(out_dev); if (mpls_pkt_too_big(skb, mtu - new_header_size)) goto drop; hh_len = LL_RESERVED_SPACE(out_dev); if (!out_dev->header_ops) hh_len = 0; /* Ensure there is enough space for the headers in the skb */ if (skb_cow(skb, hh_len + new_header_size)) goto drop; |
48d2ab609 net: mpls: Fixups... |
113 114 |
skb_set_inner_protocol(skb, skb->protocol); skb_reset_inner_network_header(skb); |
e3e4712ec mpls: ip tunnel s... |
115 |
skb_push(skb, new_header_size); |
48d2ab609 net: mpls: Fixups... |
116 |
|
e3e4712ec mpls: ip tunnel s... |
117 118 119 120 121 122 123 124 125 126 127 128 129 |
skb_reset_network_header(skb); skb->dev = out_dev; skb->protocol = htons(ETH_P_MPLS_UC); /* Push the new labels */ hdr = mpls_hdr(skb); bos = true; for (i = tun_encap_info->labels - 1; i >= 0; i--) { hdr[i] = mpls_entry_encode(tun_encap_info->label[i], ttl, 0, bos); bos = false; } |
27d691056 mpls: Packet stats |
130 |
mpls_stats_inc_outucastpkts(out_dev, skb); |
e3e4712ec mpls: ip tunnel s... |
131 132 133 134 135 136 137 138 139 140 |
if (rt) err = neigh_xmit(NEIGH_ARP_TABLE, out_dev, &rt->rt_gateway, skb); else if (rt6) err = neigh_xmit(NEIGH_ND_TABLE, out_dev, &rt6->rt6i_gateway, skb); if (err) net_dbg_ratelimited("%s: packet transmission failed: %d ", __func__, err); |
14972cbd3 net: lwtunnel: Ha... |
141 |
return LWTUNNEL_XMIT_DONE; |
e3e4712ec mpls: ip tunnel s... |
142 143 |
drop: |
27d691056 mpls: Packet stats |
144 145 146 |
out_mdev = out_dev ? mpls_dev_get(out_dev) : NULL; if (out_mdev) MPLS_INC_STATS(out_mdev, tx_errors); |
e3e4712ec mpls: ip tunnel s... |
147 148 149 |
kfree_skb(skb); return -EINVAL; } |
30357d7d8 lwtunnel: remove ... |
150 |
static int mpls_build_state(struct nlattr *nla, |
127eb7cd3 lwt: Add cfg argu... |
151 |
unsigned int family, const void *cfg, |
9ae287274 net: add extack a... |
152 153 |
struct lwtunnel_state **ts, struct netlink_ext_ack *extack) |
e3e4712ec mpls: ip tunnel s... |
154 155 156 157 |
{ struct mpls_iptunnel_encap *tun_encap_info; struct nlattr *tb[MPLS_IPTUNNEL_MAX + 1]; struct lwtunnel_state *newts; |
1511009cd net: mpls: Increa... |
158 |
u8 n_labels; |
e3e4712ec mpls: ip tunnel s... |
159 160 161 |
int ret; ret = nla_parse_nested(tb, MPLS_IPTUNNEL_MAX, nla, |
9ae287274 net: add extack a... |
162 |
mpls_iptunnel_policy, extack); |
e3e4712ec mpls: ip tunnel s... |
163 164 |
if (ret < 0) return ret; |
a1f10abe1 net: Fill in exta... |
165 166 |
if (!tb[MPLS_IPTUNNEL_DST]) { NL_SET_ERR_MSG(extack, "MPLS_IPTUNNEL_DST attribute is missing"); |
e3e4712ec mpls: ip tunnel s... |
167 |
return -EINVAL; |
a1f10abe1 net: Fill in exta... |
168 |
} |
e3e4712ec mpls: ip tunnel s... |
169 |
|
1511009cd net: mpls: Increa... |
170 |
/* determine number of labels */ |
a1f10abe1 net: Fill in exta... |
171 172 |
if (nla_get_labels(tb[MPLS_IPTUNNEL_DST], MAX_NEW_LABELS, &n_labels, NULL, extack)) |
1511009cd net: mpls: Increa... |
173 174 175 176 |
return -EINVAL; newts = lwtunnel_state_alloc(sizeof(*tun_encap_info) + n_labels * sizeof(u32)); |
e3e4712ec mpls: ip tunnel s... |
177 178 |
if (!newts) return -ENOMEM; |
e3e4712ec mpls: ip tunnel s... |
179 |
tun_encap_info = mpls_lwtunnel_encap(newts); |
1511009cd net: mpls: Increa... |
180 |
ret = nla_get_labels(tb[MPLS_IPTUNNEL_DST], n_labels, |
a1f10abe1 net: Fill in exta... |
181 182 |
&tun_encap_info->labels, tun_encap_info->label, extack); |
e3e4712ec mpls: ip tunnel s... |
183 184 |
if (ret) goto errout; |
a59166e47 mpls: allow TTL p... |
185 186 187 188 189 190 191 192 193 194 |
tun_encap_info->ttl_propagate = MPLS_TTL_PROP_DEFAULT; if (tb[MPLS_IPTUNNEL_TTL]) { tun_encap_info->default_ttl = nla_get_u8(tb[MPLS_IPTUNNEL_TTL]); /* TTL 0 implies propagate from IP header */ tun_encap_info->ttl_propagate = tun_encap_info->default_ttl ? MPLS_TTL_PROP_DISABLED : MPLS_TTL_PROP_ENABLED; } |
e3e4712ec mpls: ip tunnel s... |
195 |
newts->type = LWTUNNEL_ENCAP_MPLS; |
14972cbd3 net: lwtunnel: Ha... |
196 197 |
newts->flags |= LWTUNNEL_STATE_XMIT_REDIRECT; newts->headroom = mpls_encap_size(tun_encap_info); |
e3e4712ec mpls: ip tunnel s... |
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
*ts = newts; return 0; errout: kfree(newts); *ts = NULL; return ret; } static int mpls_fill_encap_info(struct sk_buff *skb, struct lwtunnel_state *lwtstate) { struct mpls_iptunnel_encap *tun_encap_info; tun_encap_info = mpls_lwtunnel_encap(lwtstate); if (nla_put_labels(skb, MPLS_IPTUNNEL_DST, tun_encap_info->labels, tun_encap_info->label)) goto nla_put_failure; |
a59166e47 mpls: allow TTL p... |
220 221 222 |
if (tun_encap_info->ttl_propagate != MPLS_TTL_PROP_DEFAULT && nla_put_u8(skb, MPLS_IPTUNNEL_TTL, tun_encap_info->default_ttl)) goto nla_put_failure; |
e3e4712ec mpls: ip tunnel s... |
223 224 225 226 227 228 229 230 231 |
return 0; nla_put_failure: return -EMSGSIZE; } static int mpls_encap_nlsize(struct lwtunnel_state *lwtstate) { struct mpls_iptunnel_encap *tun_encap_info; |
a59166e47 mpls: allow TTL p... |
232 |
int nlsize; |
e3e4712ec mpls: ip tunnel s... |
233 234 |
tun_encap_info = mpls_lwtunnel_encap(lwtstate); |
a59166e47 mpls: allow TTL p... |
235 236 237 238 239 240 |
nlsize = nla_total_size(tun_encap_info->labels * 4); if (tun_encap_info->ttl_propagate != MPLS_TTL_PROP_DEFAULT) nlsize += nla_total_size(1); return nlsize; |
e3e4712ec mpls: ip tunnel s... |
241 242 243 244 245 246 247 |
} static int mpls_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b) { struct mpls_iptunnel_encap *a_hdr = mpls_lwtunnel_encap(a); struct mpls_iptunnel_encap *b_hdr = mpls_lwtunnel_encap(b); int l; |
a59166e47 mpls: allow TTL p... |
248 249 250 |
if (a_hdr->labels != b_hdr->labels || a_hdr->ttl_propagate != b_hdr->ttl_propagate || a_hdr->default_ttl != b_hdr->default_ttl) |
e3e4712ec mpls: ip tunnel s... |
251 |
return 1; |
1511009cd net: mpls: Increa... |
252 |
for (l = 0; l < a_hdr->labels; l++) |
e3e4712ec mpls: ip tunnel s... |
253 254 255 256 257 258 259 |
if (a_hdr->label[l] != b_hdr->label[l]) return 1; return 0; } static const struct lwtunnel_encap_ops mpls_iptun_ops = { .build_state = mpls_build_state, |
14972cbd3 net: lwtunnel: Ha... |
260 |
.xmit = mpls_xmit, |
e3e4712ec mpls: ip tunnel s... |
261 262 263 |
.fill_encap = mpls_fill_encap_info, .get_encap_size = mpls_encap_nlsize, .cmp_encap = mpls_encap_cmp, |
88ff7334f net: Specify the ... |
264 |
.owner = THIS_MODULE, |
e3e4712ec mpls: ip tunnel s... |
265 266 267 268 269 270 271 272 273 274 275 276 277 |
}; static int __init mpls_iptunnel_init(void) { return lwtunnel_encap_add_ops(&mpls_iptun_ops, LWTUNNEL_ENCAP_MPLS); } module_init(mpls_iptunnel_init); static void __exit mpls_iptunnel_exit(void) { lwtunnel_encap_del_ops(&mpls_iptun_ops, LWTUNNEL_ENCAP_MPLS); } module_exit(mpls_iptunnel_exit); |
b2b04edce mpls: autoload lw... |
278 |
MODULE_ALIAS_RTNL_LWT(MPLS); |
e3e4712ec mpls: ip tunnel s... |
279 280 |
MODULE_DESCRIPTION("MultiProtocol Label Switching IP Tunnels"); MODULE_LICENSE("GPL v2"); |