aboutsummaryrefslogtreecommitdiffstats
path: root/net/mpls
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2015-03-03 20:12:40 -0500
committerDavid S. Miller <davem@davemloft.net>2015-03-04 00:26:06 -0500
commita2519929aba78e8cec7955d2c2a0c1e230d1f6e6 (patch)
tree3e27a41694e69fef7edc45647cb80cd96742de65 /net/mpls
parent7720c01f3f590116882e251f13c7e1d5602f8643 (diff)
mpls: Basic support for adding and removing routes
mpls_route_add and mpls_route_del implement the basic logic for adding and removing Next Hop Label Forwarding Entries from the MPLS input label map. The addition and subtraction is done in a way that is consistent with how the existing routing table in Linux are maintained. Thus all of the work to deal with NLM_F_APPEND, NLM_F_EXCL, NLM_F_REPLACE, and NLM_F_CREATE. Cases that are not clearly defined such as changing the interpretation of the mpls reserved labels is not allowed. Because it seems like the right thing to do adding an MPLS route without specifying an input label and allowing the kernel to pick a free label table entry is supported. The implementation is currently less than optimal but that can be changed. As I don't have anything else to test with only ethernet and the loopback device are the only two device types currently supported for forwarding MPLS over. Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mpls')
-rw-r--r--net/mpls/af_mpls.c133
1 files changed, 133 insertions, 0 deletions
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index b097125dfa33..e432f092f2fb 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -16,6 +16,7 @@
16#include <net/netns/generic.h> 16#include <net/netns/generic.h>
17#include "internal.h" 17#include "internal.h"
18 18
19#define LABEL_NOT_SPECIFIED (1<<20)
19#define MAX_NEW_LABELS 2 20#define MAX_NEW_LABELS 2
20 21
21/* This maximum ha length copied from the definition of struct neighbour */ 22/* This maximum ha length copied from the definition of struct neighbour */
@@ -211,6 +212,19 @@ static struct packet_type mpls_packet_type __read_mostly = {
211 .func = mpls_forward, 212 .func = mpls_forward,
212}; 213};
213 214
215struct mpls_route_config {
216 u32 rc_protocol;
217 u32 rc_ifindex;
218 u16 rc_via_family;
219 u16 rc_via_alen;
220 u8 rc_via[MAX_VIA_ALEN];
221 u32 rc_label;
222 u32 rc_output_labels;
223 u32 rc_output_label[MAX_NEW_LABELS];
224 u32 rc_nlflags;
225 struct nl_info rc_nlinfo;
226};
227
214static struct mpls_route *mpls_rt_alloc(size_t alen) 228static struct mpls_route *mpls_rt_alloc(size_t alen)
215{ 229{
216 struct mpls_route *rt; 230 struct mpls_route *rt;
@@ -245,6 +259,125 @@ static void mpls_route_update(struct net *net, unsigned index,
245 mpls_rt_free(old); 259 mpls_rt_free(old);
246} 260}
247 261
262static unsigned find_free_label(struct net *net)
263{
264 unsigned index;
265 for (index = 16; index < net->mpls.platform_labels; index++) {
266 if (!net->mpls.platform_label[index])
267 return index;
268 }
269 return LABEL_NOT_SPECIFIED;
270}
271
272static int mpls_route_add(struct mpls_route_config *cfg)
273{
274 struct net *net = cfg->rc_nlinfo.nl_net;
275 struct net_device *dev = NULL;
276 struct mpls_route *rt, *old;
277 unsigned index;
278 int i;
279 int err = -EINVAL;
280
281 index = cfg->rc_label;
282
283 /* If a label was not specified during insert pick one */
284 if ((index == LABEL_NOT_SPECIFIED) &&
285 (cfg->rc_nlflags & NLM_F_CREATE)) {
286 index = find_free_label(net);
287 }
288
289 /* The first 16 labels are reserved, and may not be set */
290 if (index < 16)
291 goto errout;
292
293 /* The full 20 bit range may not be supported. */
294 if (index >= net->mpls.platform_labels)
295 goto errout;
296
297 /* Ensure only a supported number of labels are present */
298 if (cfg->rc_output_labels > MAX_NEW_LABELS)
299 goto errout;
300
301 err = -ENODEV;
302 dev = dev_get_by_index(net, cfg->rc_ifindex);
303 if (!dev)
304 goto errout;
305
306 /* For now just support ethernet devices */
307 err = -EINVAL;
308 if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK))
309 goto errout;
310
311 err = -EINVAL;
312 if ((cfg->rc_via_family == AF_PACKET) &&
313 (dev->addr_len != cfg->rc_via_alen))
314 goto errout;
315
316 /* Append makes no sense with mpls */
317 err = -EINVAL;
318 if (cfg->rc_nlflags & NLM_F_APPEND)
319 goto errout;
320
321 err = -EEXIST;
322 old = net->mpls.platform_label[index];
323 if ((cfg->rc_nlflags & NLM_F_EXCL) && old)
324 goto errout;
325
326 err = -EEXIST;
327 if (!(cfg->rc_nlflags & NLM_F_REPLACE) && old)
328 goto errout;
329
330 err = -ENOENT;
331 if (!(cfg->rc_nlflags & NLM_F_CREATE) && !old)
332 goto errout;
333
334 err = -ENOMEM;
335 rt = mpls_rt_alloc(cfg->rc_via_alen);
336 if (!rt)
337 goto errout;
338
339 rt->rt_labels = cfg->rc_output_labels;
340 for (i = 0; i < rt->rt_labels; i++)
341 rt->rt_label[i] = cfg->rc_output_label[i];
342 rt->rt_protocol = cfg->rc_protocol;
343 rt->rt_dev = dev;
344 rt->rt_via_family = cfg->rc_via_family;
345 memcpy(rt->rt_via, cfg->rc_via, cfg->rc_via_alen);
346
347 mpls_route_update(net, index, NULL, rt, &cfg->rc_nlinfo);
348
349 dev_put(dev);
350 return 0;
351
352errout:
353 if (dev)
354 dev_put(dev);
355 return err;
356}
357
358static int mpls_route_del(struct mpls_route_config *cfg)
359{
360 struct net *net = cfg->rc_nlinfo.nl_net;
361 unsigned index;
362 int err = -EINVAL;
363
364 index = cfg->rc_label;
365
366 /* The first 16 labels are reserved, and may not be removed */
367 if (index < 16)
368 goto errout;
369
370 /* The full 20 bit range may not be supported */
371 if (index >= net->mpls.platform_labels)
372 goto errout;
373
374 mpls_route_update(net, index, NULL, NULL, &cfg->rc_nlinfo);
375
376 err = 0;
377errout:
378 return err;
379}
380
248static void mpls_ifdown(struct net_device *dev) 381static void mpls_ifdown(struct net_device *dev)
249{ 382{
250 struct net *net = dev_net(dev); 383 struct net *net = dev_net(dev);