aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/lwtunnel.h11
-rw-r--r--net/core/lwtunnel.c62
-rw-r--r--net/ipv4/fib_frontend.c8
-rw-r--r--net/ipv6/route.c12
4 files changed, 86 insertions, 7 deletions
diff --git a/include/net/lwtunnel.h b/include/net/lwtunnel.h
index d4c1c75b8862..0b585f1fd340 100644
--- a/include/net/lwtunnel.h
+++ b/include/net/lwtunnel.h
@@ -105,6 +105,8 @@ int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *op,
105 unsigned int num); 105 unsigned int num);
106int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op, 106int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op,
107 unsigned int num); 107 unsigned int num);
108int lwtunnel_valid_encap_type(u16 encap_type);
109int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len);
108int lwtunnel_build_state(struct net_device *dev, u16 encap_type, 110int lwtunnel_build_state(struct net_device *dev, u16 encap_type,
109 struct nlattr *encap, 111 struct nlattr *encap,
110 unsigned int family, const void *cfg, 112 unsigned int family, const void *cfg,
@@ -168,6 +170,15 @@ static inline int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op,
168 return -EOPNOTSUPP; 170 return -EOPNOTSUPP;
169} 171}
170 172
173static inline int lwtunnel_valid_encap_type(u16 encap_type)
174{
175 return -EOPNOTSUPP;
176}
177static inline int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len)
178{
179 return -EOPNOTSUPP;
180}
181
171static inline int lwtunnel_build_state(struct net_device *dev, u16 encap_type, 182static inline int lwtunnel_build_state(struct net_device *dev, u16 encap_type,
172 struct nlattr *encap, 183 struct nlattr *encap,
173 unsigned int family, const void *cfg, 184 unsigned int family, const void *cfg,
diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c
index a5d4e866ce88..47b1dd65947b 100644
--- a/net/core/lwtunnel.c
+++ b/net/core/lwtunnel.c
@@ -26,6 +26,7 @@
26#include <net/lwtunnel.h> 26#include <net/lwtunnel.h>
27#include <net/rtnetlink.h> 27#include <net/rtnetlink.h>
28#include <net/ip6_fib.h> 28#include <net/ip6_fib.h>
29#include <net/nexthop.h>
29 30
30#ifdef CONFIG_MODULES 31#ifdef CONFIG_MODULES
31 32
@@ -114,25 +115,74 @@ int lwtunnel_build_state(struct net_device *dev, u16 encap_type,
114 ret = -EOPNOTSUPP; 115 ret = -EOPNOTSUPP;
115 rcu_read_lock(); 116 rcu_read_lock();
116 ops = rcu_dereference(lwtun_encaps[encap_type]); 117 ops = rcu_dereference(lwtun_encaps[encap_type]);
118 if (likely(ops && ops->build_state))
119 ret = ops->build_state(dev, encap, family, cfg, lws);
120 rcu_read_unlock();
121
122 return ret;
123}
124EXPORT_SYMBOL(lwtunnel_build_state);
125
126int lwtunnel_valid_encap_type(u16 encap_type)
127{
128 const struct lwtunnel_encap_ops *ops;
129 int ret = -EINVAL;
130
131 if (encap_type == LWTUNNEL_ENCAP_NONE ||
132 encap_type > LWTUNNEL_ENCAP_MAX)
133 return ret;
134
135 rcu_read_lock();
136 ops = rcu_dereference(lwtun_encaps[encap_type]);
137 rcu_read_unlock();
117#ifdef CONFIG_MODULES 138#ifdef CONFIG_MODULES
118 if (!ops) { 139 if (!ops) {
119 const char *encap_type_str = lwtunnel_encap_str(encap_type); 140 const char *encap_type_str = lwtunnel_encap_str(encap_type);
120 141
121 if (encap_type_str) { 142 if (encap_type_str) {
122 rcu_read_unlock(); 143 __rtnl_unlock();
123 request_module("rtnl-lwt-%s", encap_type_str); 144 request_module("rtnl-lwt-%s", encap_type_str);
145 rtnl_lock();
146
124 rcu_read_lock(); 147 rcu_read_lock();
125 ops = rcu_dereference(lwtun_encaps[encap_type]); 148 ops = rcu_dereference(lwtun_encaps[encap_type]);
149 rcu_read_unlock();
126 } 150 }
127 } 151 }
128#endif 152#endif
129 if (likely(ops && ops->build_state)) 153 return ops ? 0 : -EOPNOTSUPP;
130 ret = ops->build_state(dev, encap, family, cfg, lws); 154}
131 rcu_read_unlock(); 155EXPORT_SYMBOL(lwtunnel_valid_encap_type);
132 156
133 return ret; 157int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int remaining)
158{
159 struct rtnexthop *rtnh = (struct rtnexthop *)attr;
160 struct nlattr *nla_entype;
161 struct nlattr *attrs;
162 struct nlattr *nla;
163 u16 encap_type;
164 int attrlen;
165
166 while (rtnh_ok(rtnh, remaining)) {
167 attrlen = rtnh_attrlen(rtnh);
168 if (attrlen > 0) {
169 attrs = rtnh_attrs(rtnh);
170 nla = nla_find(attrs, attrlen, RTA_ENCAP);
171 nla_entype = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
172
173 if (nla_entype) {
174 encap_type = nla_get_u16(nla_entype);
175
176 if (lwtunnel_valid_encap_type(encap_type) != 0)
177 return -EOPNOTSUPP;
178 }
179 }
180 rtnh = rtnh_next(rtnh, &remaining);
181 }
182
183 return 0;
134} 184}
135EXPORT_SYMBOL(lwtunnel_build_state); 185EXPORT_SYMBOL(lwtunnel_valid_encap_type_attr);
136 186
137void lwtstate_free(struct lwtunnel_state *lws) 187void lwtstate_free(struct lwtunnel_state *lws)
138{ 188{
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index eae0332b0e8c..7db2ad2e82d3 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -46,6 +46,7 @@
46#include <net/rtnetlink.h> 46#include <net/rtnetlink.h>
47#include <net/xfrm.h> 47#include <net/xfrm.h>
48#include <net/l3mdev.h> 48#include <net/l3mdev.h>
49#include <net/lwtunnel.h>
49#include <trace/events/fib.h> 50#include <trace/events/fib.h>
50 51
51#ifndef CONFIG_IP_MULTIPLE_TABLES 52#ifndef CONFIG_IP_MULTIPLE_TABLES
@@ -677,6 +678,10 @@ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
677 cfg->fc_mx_len = nla_len(attr); 678 cfg->fc_mx_len = nla_len(attr);
678 break; 679 break;
679 case RTA_MULTIPATH: 680 case RTA_MULTIPATH:
681 err = lwtunnel_valid_encap_type_attr(nla_data(attr),
682 nla_len(attr));
683 if (err < 0)
684 goto errout;
680 cfg->fc_mp = nla_data(attr); 685 cfg->fc_mp = nla_data(attr);
681 cfg->fc_mp_len = nla_len(attr); 686 cfg->fc_mp_len = nla_len(attr);
682 break; 687 break;
@@ -691,6 +696,9 @@ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
691 break; 696 break;
692 case RTA_ENCAP_TYPE: 697 case RTA_ENCAP_TYPE:
693 cfg->fc_encap_type = nla_get_u16(attr); 698 cfg->fc_encap_type = nla_get_u16(attr);
699 err = lwtunnel_valid_encap_type(cfg->fc_encap_type);
700 if (err < 0)
701 goto errout;
694 break; 702 break;
695 } 703 }
696 } 704 }
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 4f6b067c8753..7ea85370c11c 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2896,6 +2896,11 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
2896 if (tb[RTA_MULTIPATH]) { 2896 if (tb[RTA_MULTIPATH]) {
2897 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]); 2897 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
2898 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]); 2898 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
2899
2900 err = lwtunnel_valid_encap_type_attr(cfg->fc_mp,
2901 cfg->fc_mp_len);
2902 if (err < 0)
2903 goto errout;
2899 } 2904 }
2900 2905
2901 if (tb[RTA_PREF]) { 2906 if (tb[RTA_PREF]) {
@@ -2909,9 +2914,14 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
2909 if (tb[RTA_ENCAP]) 2914 if (tb[RTA_ENCAP])
2910 cfg->fc_encap = tb[RTA_ENCAP]; 2915 cfg->fc_encap = tb[RTA_ENCAP];
2911 2916
2912 if (tb[RTA_ENCAP_TYPE]) 2917 if (tb[RTA_ENCAP_TYPE]) {
2913 cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]); 2918 cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
2914 2919
2920 err = lwtunnel_valid_encap_type(cfg->fc_encap_type);
2921 if (err < 0)
2922 goto errout;
2923 }
2924
2915 if (tb[RTA_EXPIRES]) { 2925 if (tb[RTA_EXPIRES]) {
2916 unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ); 2926 unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ);
2917 2927