aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Shearman <rshearma@brocade.com>2015-10-26 20:37:36 -0400
committerDavid S. Miller <davem@davemloft.net>2015-10-27 22:52:59 -0400
commitcf4b24f0024fc2e3fbc653a659356d224b5b9172 (patch)
tree131a351e670f5d86c725c9e140acee1c93b11ce9
parentb4e04fc7357b6cef0856cb14b42306af1af990e5 (diff)
mpls: reduce memory usage of routes
Nexthops for MPLS routes have a via address field sized for the largest via address that is expected, which is 32 bytes. This means that in the most common case of having ipv4 via addresses, 28 bytes of memory more than required are used per nexthop. In the other common case of an ipv6 nexthop then 16 bytes more than required are used. With large numbers of MPLS routes this extra memory usage could start to become significant. To avoid allocating memory for a maximum length via address when not all of it is required and to allow for ease of iterating over nexthops, then the via addresses are changed to be stored in the same memory block as the route and nexthops, but in an array after the end of the array of nexthops. New accessors are provided to retrieve a pointer to the via address. To allow for O(1) access without having to store a pointer or offset per nh, the via address for each nexthop is sized according to the maximum via address for any nexthop in the route, which is stored in a new route field, rt_max_alen, but this is in an existing hole in struct mpls_route so it doesn't increase the size of the structure. Each via address is ensured to be aligned to VIA_ALEN_ALIGN to account for architectures that don't allow unaligned accesses. Signed-off-by: Robert Shearman <rshearma@brocade.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/mpls/af_mpls.c121
-rw-r--r--net/mpls/internal.h28
2 files changed, 111 insertions, 38 deletions
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index 1c58662db4b2..c70d750148b6 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -57,6 +57,20 @@ bool mpls_output_possible(const struct net_device *dev)
57} 57}
58EXPORT_SYMBOL_GPL(mpls_output_possible); 58EXPORT_SYMBOL_GPL(mpls_output_possible);
59 59
60static u8 *__mpls_nh_via(struct mpls_route *rt, struct mpls_nh *nh)
61{
62 u8 *nh0_via = PTR_ALIGN((u8 *)&rt->rt_nh[rt->rt_nhn], VIA_ALEN_ALIGN);
63 int nh_index = nh - rt->rt_nh;
64
65 return nh0_via + rt->rt_max_alen * nh_index;
66}
67
68static const u8 *mpls_nh_via(const struct mpls_route *rt,
69 const struct mpls_nh *nh)
70{
71 return __mpls_nh_via((struct mpls_route *)rt, (struct mpls_nh *)nh);
72}
73
60static unsigned int mpls_nh_header_size(const struct mpls_nh *nh) 74static unsigned int mpls_nh_header_size(const struct mpls_nh *nh)
61{ 75{
62 /* The size of the layer 2.5 labels to be added for this route */ 76 /* The size of the layer 2.5 labels to be added for this route */
@@ -303,7 +317,7 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
303 } 317 }
304 } 318 }
305 319
306 err = neigh_xmit(nh->nh_via_table, out_dev, nh->nh_via, skb); 320 err = neigh_xmit(nh->nh_via_table, out_dev, mpls_nh_via(rt, nh), skb);
307 if (err) 321 if (err)
308 net_dbg_ratelimited("%s: packet transmission failed: %d\n", 322 net_dbg_ratelimited("%s: packet transmission failed: %d\n",
309 __func__, err); 323 __func__, err);
@@ -340,14 +354,19 @@ struct mpls_route_config {
340 int rc_mp_len; 354 int rc_mp_len;
341}; 355};
342 356
343static struct mpls_route *mpls_rt_alloc(int num_nh) 357static struct mpls_route *mpls_rt_alloc(int num_nh, u8 max_alen)
344{ 358{
359 u8 max_alen_aligned = ALIGN(max_alen, VIA_ALEN_ALIGN);
345 struct mpls_route *rt; 360 struct mpls_route *rt;
346 361
347 rt = kzalloc(sizeof(*rt) + (num_nh * sizeof(struct mpls_nh)), 362 rt = kzalloc(ALIGN(sizeof(*rt) + num_nh * sizeof(*rt->rt_nh),
363 VIA_ALEN_ALIGN) +
364 num_nh * max_alen_aligned,
348 GFP_KERNEL); 365 GFP_KERNEL);
349 if (rt) 366 if (rt) {
350 rt->rt_nhn = num_nh; 367 rt->rt_nhn = num_nh;
368 rt->rt_max_alen = max_alen_aligned;
369 }
351 370
352 return rt; 371 return rt;
353} 372}
@@ -408,7 +427,8 @@ static unsigned find_free_label(struct net *net)
408} 427}
409 428
410#if IS_ENABLED(CONFIG_INET) 429#if IS_ENABLED(CONFIG_INET)
411static struct net_device *inet_fib_lookup_dev(struct net *net, void *addr) 430static struct net_device *inet_fib_lookup_dev(struct net *net,
431 const void *addr)
412{ 432{
413 struct net_device *dev; 433 struct net_device *dev;
414 struct rtable *rt; 434 struct rtable *rt;
@@ -427,14 +447,16 @@ static struct net_device *inet_fib_lookup_dev(struct net *net, void *addr)
427 return dev; 447 return dev;
428} 448}
429#else 449#else
430static struct net_device *inet_fib_lookup_dev(struct net *net, void *addr) 450static struct net_device *inet_fib_lookup_dev(struct net *net,
451 const void *addr)
431{ 452{
432 return ERR_PTR(-EAFNOSUPPORT); 453 return ERR_PTR(-EAFNOSUPPORT);
433} 454}
434#endif 455#endif
435 456
436#if IS_ENABLED(CONFIG_IPV6) 457#if IS_ENABLED(CONFIG_IPV6)
437static struct net_device *inet6_fib_lookup_dev(struct net *net, void *addr) 458static struct net_device *inet6_fib_lookup_dev(struct net *net,
459 const void *addr)
438{ 460{
439 struct net_device *dev; 461 struct net_device *dev;
440 struct dst_entry *dst; 462 struct dst_entry *dst;
@@ -457,13 +479,15 @@ static struct net_device *inet6_fib_lookup_dev(struct net *net, void *addr)
457 return dev; 479 return dev;
458} 480}
459#else 481#else
460static struct net_device *inet6_fib_lookup_dev(struct net *net, void *addr) 482static struct net_device *inet6_fib_lookup_dev(struct net *net,
483 const void *addr)
461{ 484{
462 return ERR_PTR(-EAFNOSUPPORT); 485 return ERR_PTR(-EAFNOSUPPORT);
463} 486}
464#endif 487#endif
465 488
466static struct net_device *find_outdev(struct net *net, 489static struct net_device *find_outdev(struct net *net,
490 struct mpls_route *rt,
467 struct mpls_nh *nh, int oif) 491 struct mpls_nh *nh, int oif)
468{ 492{
469 struct net_device *dev = NULL; 493 struct net_device *dev = NULL;
@@ -471,10 +495,10 @@ static struct net_device *find_outdev(struct net *net,
471 if (!oif) { 495 if (!oif) {
472 switch (nh->nh_via_table) { 496 switch (nh->nh_via_table) {
473 case NEIGH_ARP_TABLE: 497 case NEIGH_ARP_TABLE:
474 dev = inet_fib_lookup_dev(net, nh->nh_via); 498 dev = inet_fib_lookup_dev(net, mpls_nh_via(rt, nh));
475 break; 499 break;
476 case NEIGH_ND_TABLE: 500 case NEIGH_ND_TABLE:
477 dev = inet6_fib_lookup_dev(net, nh->nh_via); 501 dev = inet6_fib_lookup_dev(net, mpls_nh_via(rt, nh));
478 break; 502 break;
479 case NEIGH_LINK_TABLE: 503 case NEIGH_LINK_TABLE:
480 break; 504 break;
@@ -492,12 +516,13 @@ static struct net_device *find_outdev(struct net *net,
492 return dev; 516 return dev;
493} 517}
494 518
495static int mpls_nh_assign_dev(struct net *net, struct mpls_nh *nh, int oif) 519static int mpls_nh_assign_dev(struct net *net, struct mpls_route *rt,
520 struct mpls_nh *nh, int oif)
496{ 521{
497 struct net_device *dev = NULL; 522 struct net_device *dev = NULL;
498 int err = -ENODEV; 523 int err = -ENODEV;
499 524
500 dev = find_outdev(net, nh, oif); 525 dev = find_outdev(net, rt, nh, oif);
501 if (IS_ERR(dev)) { 526 if (IS_ERR(dev)) {
502 err = PTR_ERR(dev); 527 err = PTR_ERR(dev);
503 dev = NULL; 528 dev = NULL;
@@ -538,10 +563,10 @@ static int mpls_nh_build_from_cfg(struct mpls_route_config *cfg,
538 nh->nh_label[i] = cfg->rc_output_label[i]; 563 nh->nh_label[i] = cfg->rc_output_label[i];
539 564
540 nh->nh_via_table = cfg->rc_via_table; 565 nh->nh_via_table = cfg->rc_via_table;
541 memcpy(nh->nh_via, cfg->rc_via, cfg->rc_via_alen); 566 memcpy(__mpls_nh_via(rt, nh), cfg->rc_via, cfg->rc_via_alen);
542 nh->nh_via_alen = cfg->rc_via_alen; 567 nh->nh_via_alen = cfg->rc_via_alen;
543 568
544 err = mpls_nh_assign_dev(net, nh, cfg->rc_ifindex); 569 err = mpls_nh_assign_dev(net, rt, nh, cfg->rc_ifindex);
545 if (err) 570 if (err)
546 goto errout; 571 goto errout;
547 572
@@ -551,8 +576,9 @@ errout:
551 return err; 576 return err;
552} 577}
553 578
554static int mpls_nh_build(struct net *net, struct mpls_nh *nh, 579static int mpls_nh_build(struct net *net, struct mpls_route *rt,
555 int oif, struct nlattr *via, struct nlattr *newdst) 580 struct mpls_nh *nh, int oif,
581 struct nlattr *via, struct nlattr *newdst)
556{ 582{
557 int err = -ENOMEM; 583 int err = -ENOMEM;
558 584
@@ -567,11 +593,11 @@ static int mpls_nh_build(struct net *net, struct mpls_nh *nh,
567 } 593 }
568 594
569 err = nla_get_via(via, &nh->nh_via_alen, &nh->nh_via_table, 595 err = nla_get_via(via, &nh->nh_via_alen, &nh->nh_via_table,
570 nh->nh_via); 596 __mpls_nh_via(rt, nh));
571 if (err) 597 if (err)
572 goto errout; 598 goto errout;
573 599
574 err = mpls_nh_assign_dev(net, nh, oif); 600 err = mpls_nh_assign_dev(net, rt, nh, oif);
575 if (err) 601 if (err)
576 goto errout; 602 goto errout;
577 603
@@ -581,12 +607,35 @@ errout:
581 return err; 607 return err;
582} 608}
583 609
584static int mpls_count_nexthops(struct rtnexthop *rtnh, int len) 610static int mpls_count_nexthops(struct rtnexthop *rtnh, int len,
611 u8 cfg_via_alen, u8 *max_via_alen)
585{ 612{
586 int nhs = 0; 613 int nhs = 0;
587 int remaining = len; 614 int remaining = len;
588 615
616 if (!rtnh) {
617 *max_via_alen = cfg_via_alen;
618 return 1;
619 }
620
621 *max_via_alen = 0;
622
589 while (rtnh_ok(rtnh, remaining)) { 623 while (rtnh_ok(rtnh, remaining)) {
624 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
625 int attrlen;
626
627 attrlen = rtnh_attrlen(rtnh);
628 nla = nla_find(attrs, attrlen, RTA_VIA);
629 if (nla && nla_len(nla) >=
630 offsetof(struct rtvia, rtvia_addr)) {
631 int via_alen = nla_len(nla) -
632 offsetof(struct rtvia, rtvia_addr);
633
634 if (via_alen <= MAX_VIA_ALEN)
635 *max_via_alen = max_t(u16, *max_via_alen,
636 via_alen);
637 }
638
590 nhs++; 639 nhs++;
591 rtnh = rtnh_next(rtnh, &remaining); 640 rtnh = rtnh_next(rtnh, &remaining);
592 } 641 }
@@ -631,7 +680,7 @@ static int mpls_nh_build_multi(struct mpls_route_config *cfg,
631 if (!nla_via) 680 if (!nla_via)
632 goto errout; 681 goto errout;
633 682
634 err = mpls_nh_build(cfg->rc_nlinfo.nl_net, nh, 683 err = mpls_nh_build(cfg->rc_nlinfo.nl_net, rt, nh,
635 rtnh->rtnh_ifindex, nla_via, 684 rtnh->rtnh_ifindex, nla_via,
636 nla_newdst); 685 nla_newdst);
637 if (err) 686 if (err)
@@ -655,8 +704,9 @@ static int mpls_route_add(struct mpls_route_config *cfg)
655 struct net *net = cfg->rc_nlinfo.nl_net; 704 struct net *net = cfg->rc_nlinfo.nl_net;
656 struct mpls_route *rt, *old; 705 struct mpls_route *rt, *old;
657 int err = -EINVAL; 706 int err = -EINVAL;
707 u8 max_via_alen;
658 unsigned index; 708 unsigned index;
659 int nhs = 1; /* default to one nexthop */ 709 int nhs;
660 710
661 index = cfg->rc_label; 711 index = cfg->rc_label;
662 712
@@ -693,15 +743,14 @@ static int mpls_route_add(struct mpls_route_config *cfg)
693 if (!(cfg->rc_nlflags & NLM_F_CREATE) && !old) 743 if (!(cfg->rc_nlflags & NLM_F_CREATE) && !old)
694 goto errout; 744 goto errout;
695 745
696 if (cfg->rc_mp) { 746 err = -EINVAL;
697 err = -EINVAL; 747 nhs = mpls_count_nexthops(cfg->rc_mp, cfg->rc_mp_len,
698 nhs = mpls_count_nexthops(cfg->rc_mp, cfg->rc_mp_len); 748 cfg->rc_via_alen, &max_via_alen);
699 if (nhs == 0) 749 if (nhs == 0)
700 goto errout; 750 goto errout;
701 }
702 751
703 err = -ENOMEM; 752 err = -ENOMEM;
704 rt = mpls_rt_alloc(nhs); 753 rt = mpls_rt_alloc(nhs, max_via_alen);
705 if (!rt) 754 if (!rt)
706 goto errout; 755 goto errout;
707 756
@@ -1176,13 +1225,13 @@ static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
1176 if (nla_put_labels(skb, RTA_DST, 1, &label)) 1225 if (nla_put_labels(skb, RTA_DST, 1, &label))
1177 goto nla_put_failure; 1226 goto nla_put_failure;
1178 if (rt->rt_nhn == 1) { 1227 if (rt->rt_nhn == 1) {
1179 struct mpls_nh *nh = rt->rt_nh; 1228 const struct mpls_nh *nh = rt->rt_nh;
1180 1229
1181 if (nh->nh_labels && 1230 if (nh->nh_labels &&
1182 nla_put_labels(skb, RTA_NEWDST, nh->nh_labels, 1231 nla_put_labels(skb, RTA_NEWDST, nh->nh_labels,
1183 nh->nh_label)) 1232 nh->nh_label))
1184 goto nla_put_failure; 1233 goto nla_put_failure;
1185 if (nla_put_via(skb, nh->nh_via_table, nh->nh_via, 1234 if (nla_put_via(skb, nh->nh_via_table, mpls_nh_via(rt, nh),
1186 nh->nh_via_alen)) 1235 nh->nh_via_alen))
1187 goto nla_put_failure; 1236 goto nla_put_failure;
1188 dev = rtnl_dereference(nh->nh_dev); 1237 dev = rtnl_dereference(nh->nh_dev);
@@ -1209,7 +1258,7 @@ static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
1209 nh->nh_label)) 1258 nh->nh_label))
1210 goto nla_put_failure; 1259 goto nla_put_failure;
1211 if (nla_put_via(skb, nh->nh_via_table, 1260 if (nla_put_via(skb, nh->nh_via_table,
1212 nh->nh_via, 1261 mpls_nh_via(rt, nh),
1213 nh->nh_via_alen)) 1262 nh->nh_via_alen))
1214 goto nla_put_failure; 1263 goto nla_put_failure;
1215 1264
@@ -1338,7 +1387,7 @@ static int resize_platform_label_table(struct net *net, size_t limit)
1338 /* In case the predefined labels need to be populated */ 1387 /* In case the predefined labels need to be populated */
1339 if (limit > MPLS_LABEL_IPV4NULL) { 1388 if (limit > MPLS_LABEL_IPV4NULL) {
1340 struct net_device *lo = net->loopback_dev; 1389 struct net_device *lo = net->loopback_dev;
1341 rt0 = mpls_rt_alloc(1); 1390 rt0 = mpls_rt_alloc(1, lo->addr_len);
1342 if (!rt0) 1391 if (!rt0)
1343 goto nort0; 1392 goto nort0;
1344 RCU_INIT_POINTER(rt0->rt_nh->nh_dev, lo); 1393 RCU_INIT_POINTER(rt0->rt_nh->nh_dev, lo);
@@ -1346,11 +1395,12 @@ static int resize_platform_label_table(struct net *net, size_t limit)
1346 rt0->rt_payload_type = MPT_IPV4; 1395 rt0->rt_payload_type = MPT_IPV4;
1347 rt0->rt_nh->nh_via_table = NEIGH_LINK_TABLE; 1396 rt0->rt_nh->nh_via_table = NEIGH_LINK_TABLE;
1348 rt0->rt_nh->nh_via_alen = lo->addr_len; 1397 rt0->rt_nh->nh_via_alen = lo->addr_len;
1349 memcpy(rt0->rt_nh->nh_via, lo->dev_addr, lo->addr_len); 1398 memcpy(__mpls_nh_via(rt0, rt0->rt_nh), lo->dev_addr,
1399 lo->addr_len);
1350 } 1400 }
1351 if (limit > MPLS_LABEL_IPV6NULL) { 1401 if (limit > MPLS_LABEL_IPV6NULL) {
1352 struct net_device *lo = net->loopback_dev; 1402 struct net_device *lo = net->loopback_dev;
1353 rt2 = mpls_rt_alloc(1); 1403 rt2 = mpls_rt_alloc(1, lo->addr_len);
1354 if (!rt2) 1404 if (!rt2)
1355 goto nort2; 1405 goto nort2;
1356 RCU_INIT_POINTER(rt2->rt_nh->nh_dev, lo); 1406 RCU_INIT_POINTER(rt2->rt_nh->nh_dev, lo);
@@ -1358,7 +1408,8 @@ static int resize_platform_label_table(struct net *net, size_t limit)
1358 rt2->rt_payload_type = MPT_IPV6; 1408 rt2->rt_payload_type = MPT_IPV6;
1359 rt2->rt_nh->nh_via_table = NEIGH_LINK_TABLE; 1409 rt2->rt_nh->nh_via_table = NEIGH_LINK_TABLE;
1360 rt2->rt_nh->nh_via_alen = lo->addr_len; 1410 rt2->rt_nh->nh_via_alen = lo->addr_len;
1361 memcpy(rt2->rt_nh->nh_via, lo->dev_addr, lo->addr_len); 1411 memcpy(__mpls_nh_via(rt2, rt2->rt_nh), lo->dev_addr,
1412 lo->addr_len);
1362 } 1413 }
1363 1414
1364 rtnl_lock(); 1415 rtnl_lock();
diff --git a/net/mpls/internal.h b/net/mpls/internal.h
index d7757be39877..bde52ce88c94 100644
--- a/net/mpls/internal.h
+++ b/net/mpls/internal.h
@@ -25,7 +25,8 @@ struct sk_buff;
25#define MAX_NEW_LABELS 2 25#define MAX_NEW_LABELS 2
26 26
27/* This maximum ha length copied from the definition of struct neighbour */ 27/* This maximum ha length copied from the definition of struct neighbour */
28#define MAX_VIA_ALEN (ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))) 28#define VIA_ALEN_ALIGN sizeof(unsigned long)
29#define MAX_VIA_ALEN (ALIGN(MAX_ADDR_LEN, VIA_ALEN_ALIGN))
29 30
30enum mpls_payload_type { 31enum mpls_payload_type {
31 MPT_UNSPEC, /* IPv4 or IPv6 */ 32 MPT_UNSPEC, /* IPv4 or IPv6 */
@@ -44,14 +45,35 @@ struct mpls_nh { /* next hop label forwarding entry */
44 u8 nh_labels; 45 u8 nh_labels;
45 u8 nh_via_alen; 46 u8 nh_via_alen;
46 u8 nh_via_table; 47 u8 nh_via_table;
47 u8 nh_via[MAX_VIA_ALEN];
48}; 48};
49 49
50/* The route, nexthops and vias are stored together in the same memory
51 * block:
52 *
53 * +----------------------+
54 * | mpls_route |
55 * +----------------------+
56 * | mpls_nh 0 |
57 * +----------------------+
58 * | ... |
59 * +----------------------+
60 * | mpls_nh n-1 |
61 * +----------------------+
62 * | alignment padding |
63 * +----------------------+
64 * | via[rt_max_alen] 0 |
65 * +----------------------+
66 * | ... |
67 * +----------------------+
68 * | via[rt_max_alen] n-1 |
69 * +----------------------+
70 */
50struct mpls_route { /* next hop label forwarding entry */ 71struct mpls_route { /* next hop label forwarding entry */
51 struct rcu_head rt_rcu; 72 struct rcu_head rt_rcu;
52 u8 rt_protocol; 73 u8 rt_protocol;
53 u8 rt_payload_type; 74 u8 rt_payload_type;
54 int rt_nhn; 75 u8 rt_max_alen;
76 unsigned int rt_nhn;
55 struct mpls_nh rt_nh[0]; 77 struct mpls_nh rt_nh[0];
56}; 78};
57 79