Blame view

net/mpls/mpls_iptunnel.c 7.78 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
2
3
4
5
6
  /*
   * mpls tunnels	An implementation mpls tunnels using the light weight tunnel
   *		infrastructure
   *
   * Authors:	Roopa Prabhu, <roopa@cumulusnetworks.com>
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
   */
  #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] = {
2f3f7d1fa   George Wilkie   mpls: fix warning...
26
  	[MPLS_IPTUNNEL_DST]	= { .len = sizeof(u32) },
a59166e47   Robert Shearman   mpls: allow TTL p...
27
  	[MPLS_IPTUNNEL_TTL]	= { .type = NLA_U8 },
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
28
29
30
31
32
33
34
  };
  
  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   Roopa Prabhu   net: lwtunnel: Ha...
35
  static int mpls_xmit(struct sk_buff *skb)
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
36
37
38
39
40
41
42
43
44
45
  {
  	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   Robert Shearman   mpls: Packet stats
46
  	struct mpls_dev *out_mdev;
a59166e47   Robert Shearman   mpls: allow TTL p...
47
  	struct net *net;
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
48
49
50
51
  	int err = 0;
  	bool bos;
  	int i;
  	unsigned int ttl;
27d691056   Robert Shearman   mpls: Packet stats
52
53
  	/* Find the output device */
  	out_dev = dst->dev;
a59166e47   Robert Shearman   mpls: allow TTL p...
54
  	net = dev_net(out_dev);
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
55
56
  
  	skb_orphan(skb);
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
57
  	if (!mpls_output_possible(out_dev) ||
61adedf3e   Jiri Benc   route: move lwtun...
58
  	    !dst->lwtstate || skb_warn_if_lro(skb))
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
59
60
61
  		goto drop;
  
  	skb_forward_csum(skb);
61adedf3e   Jiri Benc   route: move lwtun...
62
  	tun_encap_info = mpls_lwtunnel_encap(dst->lwtstate);
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
63

a59166e47   Robert Shearman   mpls: allow TTL p...
64
65
66
67
68
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
  	/* 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   Roopa Prabhu   mpls: ip tunnel s...
95
96
97
98
99
100
101
102
103
104
105
106
107
  	/* 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   David Ahern   net: mpls: Fixups...
108
109
  	skb_set_inner_protocol(skb, skb->protocol);
  	skb_reset_inner_network_header(skb);
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
110
  	skb_push(skb, new_header_size);
48d2ab609   David Ahern   net: mpls: Fixups...
111

e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
112
113
114
115
116
117
118
119
120
121
122
123
124
  	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   Robert Shearman   mpls: Packet stats
125
  	mpls_stats_inc_outucastpkts(out_dev, skb);
1550c1719   David Ahern   ipv4: Prepare rta...
126
  	if (rt) {
803f3e22a   Alexey Kodanev   ipv4: mpls: fix m...
127
  		if (rt->rt_gw_family == AF_INET6)
0f5f7d7bf   David Ahern   ipv4: Add support...
128
129
  			err = neigh_xmit(NEIGH_ND_TABLE, out_dev, &rt->rt_gw6,
  					 skb);
803f3e22a   Alexey Kodanev   ipv4: mpls: fix m...
130
131
132
  		else
  			err = neigh_xmit(NEIGH_ARP_TABLE, out_dev, &rt->rt_gw4,
  					 skb);
1550c1719   David Ahern   ipv4: Prepare rta...
133
  	} else if (rt6) {
f84532ce5   Vinay K Nallamothu   mpls: Fix 6PE for...
134
135
136
137
138
139
140
141
  		if (ipv6_addr_v4mapped(&rt6->rt6i_gateway)) {
  			/* 6PE (RFC 4798) */
  			err = neigh_xmit(NEIGH_ARP_TABLE, out_dev, &rt6->rt6i_gateway.s6_addr32[3],
  					 skb);
  		} else
  			err = neigh_xmit(NEIGH_ND_TABLE, out_dev, &rt6->rt6i_gateway,
  					 skb);
  	}
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
142
143
144
145
  	if (err)
  		net_dbg_ratelimited("%s: packet transmission failed: %d
  ",
  				    __func__, err);
14972cbd3   Roopa Prabhu   net: lwtunnel: Ha...
146
  	return LWTUNNEL_XMIT_DONE;
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
147
148
  
  drop:
27d691056   Robert Shearman   mpls: Packet stats
149
150
151
  	out_mdev = out_dev ? mpls_dev_get(out_dev) : NULL;
  	if (out_mdev)
  		MPLS_INC_STATS(out_mdev, tx_errors);
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
152
153
154
  	kfree_skb(skb);
  	return -EINVAL;
  }
faee67694   Alexander Aring   net: add net avai...
155
  static int mpls_build_state(struct net *net, struct nlattr *nla,
127eb7cd3   Tom Herbert   lwt: Add cfg argu...
156
  			    unsigned int family, const void *cfg,
9ae287274   David Ahern   net: add extack a...
157
158
  			    struct lwtunnel_state **ts,
  			    struct netlink_ext_ack *extack)
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
159
160
161
162
  {
  	struct mpls_iptunnel_encap *tun_encap_info;
  	struct nlattr *tb[MPLS_IPTUNNEL_MAX + 1];
  	struct lwtunnel_state *newts;
1511009cd   David Ahern   net: mpls: Increa...
163
  	u8 n_labels;
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
164
  	int ret;
8cb081746   Johannes Berg   netlink: make val...
165
166
  	ret = nla_parse_nested_deprecated(tb, MPLS_IPTUNNEL_MAX, nla,
  					  mpls_iptunnel_policy, extack);
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
167
168
  	if (ret < 0)
  		return ret;
a1f10abe1   David Ahern   net: Fill in exta...
169
170
  	if (!tb[MPLS_IPTUNNEL_DST]) {
  		NL_SET_ERR_MSG(extack, "MPLS_IPTUNNEL_DST attribute is missing");
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
171
  		return -EINVAL;
a1f10abe1   David Ahern   net: Fill in exta...
172
  	}
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
173

1511009cd   David Ahern   net: mpls: Increa...
174
  	/* determine number of labels */
a1f10abe1   David Ahern   net: Fill in exta...
175
176
  	if (nla_get_labels(tb[MPLS_IPTUNNEL_DST], MAX_NEW_LABELS,
  			   &n_labels, NULL, extack))
1511009cd   David Ahern   net: mpls: Increa...
177
  		return -EINVAL;
b4ba9354c   Gustavo A. R. Silva   mpls_iptunnel: us...
178
179
  	newts = lwtunnel_state_alloc(struct_size(tun_encap_info, label,
  						 n_labels));
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
180
181
  	if (!newts)
  		return -ENOMEM;
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
182
  	tun_encap_info = mpls_lwtunnel_encap(newts);
1511009cd   David Ahern   net: mpls: Increa...
183
  	ret = nla_get_labels(tb[MPLS_IPTUNNEL_DST], n_labels,
a1f10abe1   David Ahern   net: Fill in exta...
184
185
  			     &tun_encap_info->labels, tun_encap_info->label,
  			     extack);
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
186
187
  	if (ret)
  		goto errout;
a59166e47   Robert Shearman   mpls: allow TTL p...
188
189
190
191
192
193
194
195
196
197
  
  	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   Roopa Prabhu   mpls: ip tunnel s...
198
  	newts->type = LWTUNNEL_ENCAP_MPLS;
14972cbd3   Roopa Prabhu   net: lwtunnel: Ha...
199
200
  	newts->flags |= LWTUNNEL_STATE_XMIT_REDIRECT;
  	newts->headroom = mpls_encap_size(tun_encap_info);
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
  
  	*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;
04c6a3a40   Stephen Hemminger   mpls: remove trai...
217

e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
218
219
220
221
222
  	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   Robert Shearman   mpls: allow TTL p...
223
224
225
  	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   Roopa Prabhu   mpls: ip tunnel s...
226
227
228
229
230
231
232
233
234
  	return 0;
  
  nla_put_failure:
  	return -EMSGSIZE;
  }
  
  static int mpls_encap_nlsize(struct lwtunnel_state *lwtstate)
  {
  	struct mpls_iptunnel_encap *tun_encap_info;
a59166e47   Robert Shearman   mpls: allow TTL p...
235
  	int nlsize;
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
236
237
  
  	tun_encap_info = mpls_lwtunnel_encap(lwtstate);
a59166e47   Robert Shearman   mpls: allow TTL p...
238
239
240
241
242
243
  	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   Roopa Prabhu   mpls: ip tunnel s...
244
245
246
247
248
249
250
  }
  
  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   Robert Shearman   mpls: allow TTL p...
251
252
253
  	if (a_hdr->labels != b_hdr->labels ||
  	    a_hdr->ttl_propagate != b_hdr->ttl_propagate ||
  	    a_hdr->default_ttl != b_hdr->default_ttl)
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
254
  		return 1;
1511009cd   David Ahern   net: mpls: Increa...
255
  	for (l = 0; l < a_hdr->labels; l++)
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
256
257
258
259
260
261
262
  		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   Roopa Prabhu   net: lwtunnel: Ha...
263
  	.xmit = mpls_xmit,
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
264
265
266
  	.fill_encap = mpls_fill_encap_info,
  	.get_encap_size = mpls_encap_nlsize,
  	.cmp_encap = mpls_encap_cmp,
88ff7334f   Robert Shearman   net: Specify the ...
267
  	.owner = THIS_MODULE,
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
268
269
270
271
272
273
274
275
276
277
278
279
280
  };
  
  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   Robert Shearman   mpls: autoload lw...
281
  MODULE_ALIAS_RTNL_LWT(MPLS);
b7c24497b   Alexander Ovechkin   mpls: load mpls_g...
282
  MODULE_SOFTDEP("post: mpls_gso");
e3e4712ec   Roopa Prabhu   mpls: ip tunnel s...
283
284
  MODULE_DESCRIPTION("MultiProtocol Label Switching IP Tunnels");
  MODULE_LICENSE("GPL v2");