summaryrefslogtreecommitdiffstats
path: root/net/mpls
diff options
context:
space:
mode:
authorDavid Ahern <dsa@cumulusnetworks.com>2017-03-31 10:14:03 -0400
committerDavid S. Miller <davem@davemloft.net>2017-04-01 23:21:44 -0400
commita4ac8c986d3f72ccbaf6d6782511fb645e568306 (patch)
tree7b0a525484b6ed0a7adca3bc4f3848f5f3aa37d1 /net/mpls
parentdf1c631648c55bfb247339279f9bc573c7f283f4 (diff)
net: mpls: bump maximum number of labels
Allow users to push down more labels per MPLS route. With the previous patches, no memory allocations are based on MAX_NEW_LABELS; the limit is only used to keep userspace in check. At this point MAX_NEW_LABELS is only used for mpls_route_config (copying route data from userspace) and processing nexthops looking for the max number of labels across the route spec. Signed-off-by: David Ahern <dsa@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mpls')
-rw-r--r--net/mpls/af_mpls.c103
-rw-r--r--net/mpls/internal.h2
2 files changed, 71 insertions, 34 deletions
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index f84c52b6eafc..10daefd7f938 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -24,7 +24,10 @@
24#include <net/nexthop.h> 24#include <net/nexthop.h>
25#include "internal.h" 25#include "internal.h"
26 26
27#define MAX_NEW_LABELS 2 27/* put a reasonable limit on the number of labels
28 * we will accept from userspace
29 */
30#define MAX_NEW_LABELS 30
28 31
29/* max memory we will use for mpls_route */ 32/* max memory we will use for mpls_route */
30#define MAX_MPLS_ROUTE_MEM 4096 33#define MAX_MPLS_ROUTE_MEM 4096
@@ -698,9 +701,6 @@ static int mpls_nh_build_from_cfg(struct mpls_route_config *cfg,
698 return -ENOMEM; 701 return -ENOMEM;
699 702
700 err = -EINVAL; 703 err = -EINVAL;
701 /* Ensure only a supported number of labels are present */
702 if (cfg->rc_output_labels > MAX_NEW_LABELS)
703 goto errout;
704 704
705 nh->nh_labels = cfg->rc_output_labels; 705 nh->nh_labels = cfg->rc_output_labels;
706 for (i = 0; i < nh->nh_labels; i++) 706 for (i = 0; i < nh->nh_labels; i++)
@@ -725,7 +725,7 @@ errout:
725 725
726static int mpls_nh_build(struct net *net, struct mpls_route *rt, 726static int mpls_nh_build(struct net *net, struct mpls_route *rt,
727 struct mpls_nh *nh, int oif, struct nlattr *via, 727 struct mpls_nh *nh, int oif, struct nlattr *via,
728 struct nlattr *newdst) 728 struct nlattr *newdst, u8 max_labels)
729{ 729{
730 int err = -ENOMEM; 730 int err = -ENOMEM;
731 731
@@ -733,7 +733,7 @@ static int mpls_nh_build(struct net *net, struct mpls_route *rt,
733 goto errout; 733 goto errout;
734 734
735 if (newdst) { 735 if (newdst) {
736 err = nla_get_labels(newdst, MAX_NEW_LABELS, 736 err = nla_get_labels(newdst, max_labels,
737 &nh->nh_labels, nh->nh_label); 737 &nh->nh_labels, nh->nh_label);
738 if (err) 738 if (err)
739 goto errout; 739 goto errout;
@@ -759,21 +759,19 @@ errout:
759} 759}
760 760
761static u8 mpls_count_nexthops(struct rtnexthop *rtnh, int len, 761static u8 mpls_count_nexthops(struct rtnexthop *rtnh, int len,
762 u8 cfg_via_alen, u8 *max_via_alen) 762 u8 cfg_via_alen, u8 *max_via_alen,
763 u8 *max_labels)
763{ 764{
764 int remaining = len; 765 int remaining = len;
765 u8 nhs = 0; 766 u8 nhs = 0;
766 767
767 if (!rtnh) {
768 *max_via_alen = cfg_via_alen;
769 return 1;
770 }
771
772 *max_via_alen = 0; 768 *max_via_alen = 0;
769 *max_labels = 0;
773 770
774 while (rtnh_ok(rtnh, remaining)) { 771 while (rtnh_ok(rtnh, remaining)) {
775 struct nlattr *nla, *attrs = rtnh_attrs(rtnh); 772 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
776 int attrlen; 773 int attrlen;
774 u8 n_labels = 0;
777 775
778 attrlen = rtnh_attrlen(rtnh); 776 attrlen = rtnh_attrlen(rtnh);
779 nla = nla_find(attrs, attrlen, RTA_VIA); 777 nla = nla_find(attrs, attrlen, RTA_VIA);
@@ -787,6 +785,13 @@ static u8 mpls_count_nexthops(struct rtnexthop *rtnh, int len,
787 via_alen); 785 via_alen);
788 } 786 }
789 787
788 nla = nla_find(attrs, attrlen, RTA_NEWDST);
789 if (nla &&
790 nla_get_labels(nla, MAX_NEW_LABELS, &n_labels, NULL) != 0)
791 return 0;
792
793 *max_labels = max_t(u8, *max_labels, n_labels);
794
790 /* number of nexthops is tracked by a u8. 795 /* number of nexthops is tracked by a u8.
791 * Check for overflow. 796 * Check for overflow.
792 */ 797 */
@@ -802,7 +807,7 @@ static u8 mpls_count_nexthops(struct rtnexthop *rtnh, int len,
802} 807}
803 808
804static int mpls_nh_build_multi(struct mpls_route_config *cfg, 809static int mpls_nh_build_multi(struct mpls_route_config *cfg,
805 struct mpls_route *rt) 810 struct mpls_route *rt, u8 max_labels)
806{ 811{
807 struct rtnexthop *rtnh = cfg->rc_mp; 812 struct rtnexthop *rtnh = cfg->rc_mp;
808 struct nlattr *nla_via, *nla_newdst; 813 struct nlattr *nla_via, *nla_newdst;
@@ -835,7 +840,8 @@ static int mpls_nh_build_multi(struct mpls_route_config *cfg,
835 } 840 }
836 841
837 err = mpls_nh_build(cfg->rc_nlinfo.nl_net, rt, nh, 842 err = mpls_nh_build(cfg->rc_nlinfo.nl_net, rt, nh,
838 rtnh->rtnh_ifindex, nla_via, nla_newdst); 843 rtnh->rtnh_ifindex, nla_via, nla_newdst,
844 max_labels);
839 if (err) 845 if (err)
840 goto errout; 846 goto errout;
841 847
@@ -862,6 +868,7 @@ static int mpls_route_add(struct mpls_route_config *cfg)
862 int err = -EINVAL; 868 int err = -EINVAL;
863 u8 max_via_alen; 869 u8 max_via_alen;
864 unsigned index; 870 unsigned index;
871 u8 max_labels;
865 u8 nhs; 872 u8 nhs;
866 873
867 index = cfg->rc_label; 874 index = cfg->rc_label;
@@ -900,13 +907,21 @@ static int mpls_route_add(struct mpls_route_config *cfg)
900 goto errout; 907 goto errout;
901 908
902 err = -EINVAL; 909 err = -EINVAL;
903 nhs = mpls_count_nexthops(cfg->rc_mp, cfg->rc_mp_len, 910 if (cfg->rc_mp) {
904 cfg->rc_via_alen, &max_via_alen); 911 nhs = mpls_count_nexthops(cfg->rc_mp, cfg->rc_mp_len,
912 cfg->rc_via_alen, &max_via_alen,
913 &max_labels);
914 } else {
915 max_via_alen = cfg->rc_via_alen;
916 max_labels = cfg->rc_output_labels;
917 nhs = 1;
918 }
919
905 if (nhs == 0) 920 if (nhs == 0)
906 goto errout; 921 goto errout;
907 922
908 err = -ENOMEM; 923 err = -ENOMEM;
909 rt = mpls_rt_alloc(nhs, max_via_alen, MAX_NEW_LABELS); 924 rt = mpls_rt_alloc(nhs, max_via_alen, max_labels);
910 if (IS_ERR(rt)) { 925 if (IS_ERR(rt)) {
911 err = PTR_ERR(rt); 926 err = PTR_ERR(rt);
912 goto errout; 927 goto errout;
@@ -917,7 +932,7 @@ static int mpls_route_add(struct mpls_route_config *cfg)
917 rt->rt_ttl_propagate = cfg->rc_ttl_propagate; 932 rt->rt_ttl_propagate = cfg->rc_ttl_propagate;
918 933
919 if (cfg->rc_mp) 934 if (cfg->rc_mp)
920 err = mpls_nh_build_multi(cfg, rt); 935 err = mpls_nh_build_multi(cfg, rt, max_labels);
921 else 936 else
922 err = mpls_nh_build_from_cfg(cfg, rt); 937 err = mpls_nh_build_from_cfg(cfg, rt);
923 if (err) 938 if (err)
@@ -1531,16 +1546,18 @@ int nla_put_labels(struct sk_buff *skb, int attrtype,
1531EXPORT_SYMBOL_GPL(nla_put_labels); 1546EXPORT_SYMBOL_GPL(nla_put_labels);
1532 1547
1533int nla_get_labels(const struct nlattr *nla, 1548int nla_get_labels(const struct nlattr *nla,
1534 u32 max_labels, u8 *labels, u32 label[]) 1549 u8 max_labels, u8 *labels, u32 label[])
1535{ 1550{
1536 unsigned len = nla_len(nla); 1551 unsigned len = nla_len(nla);
1537 unsigned nla_labels;
1538 struct mpls_shim_hdr *nla_label; 1552 struct mpls_shim_hdr *nla_label;
1553 u8 nla_labels;
1539 bool bos; 1554 bool bos;
1540 int i; 1555 int i;
1541 1556
1542 /* len needs to be an even multiple of 4 (the label size) */ 1557 /* len needs to be an even multiple of 4 (the label size). Number
1543 if (len & 3) 1558 * of labels is a u8 so check for overflow.
1559 */
1560 if (len & 3 || len / 4 > 255)
1544 return -EINVAL; 1561 return -EINVAL;
1545 1562
1546 /* Limit the number of new labels allowed */ 1563 /* Limit the number of new labels allowed */
@@ -1548,6 +1565,10 @@ int nla_get_labels(const struct nlattr *nla,
1548 if (nla_labels > max_labels) 1565 if (nla_labels > max_labels)
1549 return -EINVAL; 1566 return -EINVAL;
1550 1567
1568 /* when label == NULL, caller wants number of labels */
1569 if (!label)
1570 goto out;
1571
1551 nla_label = nla_data(nla); 1572 nla_label = nla_data(nla);
1552 bos = true; 1573 bos = true;
1553 for (i = nla_labels - 1; i >= 0; i--, bos = false) { 1574 for (i = nla_labels - 1; i >= 0; i--, bos = false) {
@@ -1571,6 +1592,7 @@ int nla_get_labels(const struct nlattr *nla,
1571 1592
1572 label[i] = dec.label; 1593 label[i] = dec.label;
1573 } 1594 }
1595out:
1574 *labels = nla_labels; 1596 *labels = nla_labels;
1575 return 0; 1597 return 0;
1576} 1598}
@@ -1632,7 +1654,6 @@ static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh,
1632 1654
1633 err = -EINVAL; 1655 err = -EINVAL;
1634 rtm = nlmsg_data(nlh); 1656 rtm = nlmsg_data(nlh);
1635 memset(cfg, 0, sizeof(*cfg));
1636 1657
1637 if (rtm->rtm_family != AF_MPLS) 1658 if (rtm->rtm_family != AF_MPLS)
1638 goto errout; 1659 goto errout;
@@ -1731,27 +1752,43 @@ errout:
1731 1752
1732static int mpls_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh) 1753static int mpls_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
1733{ 1754{
1734 struct mpls_route_config cfg; 1755 struct mpls_route_config *cfg;
1735 int err; 1756 int err;
1736 1757
1737 err = rtm_to_route_config(skb, nlh, &cfg); 1758 cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
1759 if (!cfg)
1760 return -ENOMEM;
1761
1762 err = rtm_to_route_config(skb, nlh, cfg);
1738 if (err < 0) 1763 if (err < 0)
1739 return err; 1764 goto out;
1740 1765
1741 return mpls_route_del(&cfg); 1766 err = mpls_route_del(cfg);
1767out:
1768 kfree(cfg);
1769
1770 return err;
1742} 1771}
1743 1772
1744 1773
1745static int mpls_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh) 1774static int mpls_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
1746{ 1775{
1747 struct mpls_route_config cfg; 1776 struct mpls_route_config *cfg;
1748 int err; 1777 int err;
1749 1778
1750 err = rtm_to_route_config(skb, nlh, &cfg); 1779 cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
1780 if (!cfg)
1781 return -ENOMEM;
1782
1783 err = rtm_to_route_config(skb, nlh, cfg);
1751 if (err < 0) 1784 if (err < 0)
1752 return err; 1785 goto out;
1753 1786
1754 return mpls_route_add(&cfg); 1787 err = mpls_route_add(cfg);
1788out:
1789 kfree(cfg);
1790
1791 return err;
1755} 1792}
1756 1793
1757static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event, 1794static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
@@ -1980,7 +2017,7 @@ static int resize_platform_label_table(struct net *net, size_t limit)
1980 /* In case the predefined labels need to be populated */ 2017 /* In case the predefined labels need to be populated */
1981 if (limit > MPLS_LABEL_IPV4NULL) { 2018 if (limit > MPLS_LABEL_IPV4NULL) {
1982 struct net_device *lo = net->loopback_dev; 2019 struct net_device *lo = net->loopback_dev;
1983 rt0 = mpls_rt_alloc(1, lo->addr_len, MAX_NEW_LABELS); 2020 rt0 = mpls_rt_alloc(1, lo->addr_len, 0);
1984 if (IS_ERR(rt0)) 2021 if (IS_ERR(rt0))
1985 goto nort0; 2022 goto nort0;
1986 RCU_INIT_POINTER(rt0->rt_nh->nh_dev, lo); 2023 RCU_INIT_POINTER(rt0->rt_nh->nh_dev, lo);
@@ -1994,7 +2031,7 @@ static int resize_platform_label_table(struct net *net, size_t limit)
1994 } 2031 }
1995 if (limit > MPLS_LABEL_IPV6NULL) { 2032 if (limit > MPLS_LABEL_IPV6NULL) {
1996 struct net_device *lo = net->loopback_dev; 2033 struct net_device *lo = net->loopback_dev;
1997 rt2 = mpls_rt_alloc(1, lo->addr_len, MAX_NEW_LABELS); 2034 rt2 = mpls_rt_alloc(1, lo->addr_len, 0);
1998 if (IS_ERR(rt2)) 2035 if (IS_ERR(rt2))
1999 goto nort2; 2036 goto nort2;
2000 RCU_INIT_POINTER(rt2->rt_nh->nh_dev, lo); 2037 RCU_INIT_POINTER(rt2->rt_nh->nh_dev, lo);
diff --git a/net/mpls/internal.h b/net/mpls/internal.h
index cc324c022049..c5d2f5bc37ec 100644
--- a/net/mpls/internal.h
+++ b/net/mpls/internal.h
@@ -197,7 +197,7 @@ static inline struct mpls_dev *mpls_dev_get(const struct net_device *dev)
197 197
198int nla_put_labels(struct sk_buff *skb, int attrtype, u8 labels, 198int nla_put_labels(struct sk_buff *skb, int attrtype, u8 labels,
199 const u32 label[]); 199 const u32 label[]);
200int nla_get_labels(const struct nlattr *nla, u32 max_labels, u8 *labels, 200int nla_get_labels(const struct nlattr *nla, u8 max_labels, u8 *labels,
201 u32 label[]); 201 u32 label[]);
202int nla_get_via(const struct nlattr *nla, u8 *via_alen, u8 *via_table, 202int nla_get_via(const struct nlattr *nla, u8 *via_alen, u8 *via_table,
203 u8 via[]); 203 u8 via[]);