diff options
author | David Ahern <dsa@cumulusnetworks.com> | 2017-03-31 10:14:03 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-04-01 23:21:44 -0400 |
commit | a4ac8c986d3f72ccbaf6d6782511fb645e568306 (patch) | |
tree | 7b0a525484b6ed0a7adca3bc4f3848f5f3aa37d1 /net/mpls | |
parent | df1c631648c55bfb247339279f9bc573c7f283f4 (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.c | 103 | ||||
-rw-r--r-- | net/mpls/internal.h | 2 |
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 | ||
726 | static int mpls_nh_build(struct net *net, struct mpls_route *rt, | 726 | static 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 | ||
761 | static u8 mpls_count_nexthops(struct rtnexthop *rtnh, int len, | 761 | static 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 | ||
804 | static int mpls_nh_build_multi(struct mpls_route_config *cfg, | 809 | static 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, | |||
1531 | EXPORT_SYMBOL_GPL(nla_put_labels); | 1546 | EXPORT_SYMBOL_GPL(nla_put_labels); |
1532 | 1547 | ||
1533 | int nla_get_labels(const struct nlattr *nla, | 1548 | int 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 | } |
1595 | out: | ||
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 | ||
1732 | static int mpls_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh) | 1753 | static 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); |
1767 | out: | ||
1768 | kfree(cfg); | ||
1769 | |||
1770 | return err; | ||
1742 | } | 1771 | } |
1743 | 1772 | ||
1744 | 1773 | ||
1745 | static int mpls_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh) | 1774 | static 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); |
1788 | out: | ||
1789 | kfree(cfg); | ||
1790 | |||
1791 | return err; | ||
1755 | } | 1792 | } |
1756 | 1793 | ||
1757 | static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event, | 1794 | static 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 | ||
198 | int nla_put_labels(struct sk_buff *skb, int attrtype, u8 labels, | 198 | int nla_put_labels(struct sk_buff *skb, int attrtype, u8 labels, |
199 | const u32 label[]); | 199 | const u32 label[]); |
200 | int nla_get_labels(const struct nlattr *nla, u32 max_labels, u8 *labels, | 200 | int nla_get_labels(const struct nlattr *nla, u8 max_labels, u8 *labels, |
201 | u32 label[]); | 201 | u32 label[]); |
202 | int nla_get_via(const struct nlattr *nla, u8 *via_alen, u8 *via_table, | 202 | int nla_get_via(const struct nlattr *nla, u8 *via_alen, u8 *via_table, |
203 | u8 via[]); | 203 | u8 via[]); |