net: add extack arg to lwtunnel build state
authorDavid Ahern <dsahern@gmail.com>
Sat, 27 May 2017 22:19:28 +0000 (16:19 -0600)
committerDavid S. Miller <davem@davemloft.net>
Tue, 30 May 2017 15:55:32 +0000 (11:55 -0400)
Pass extack arg down to lwtunnel_build_state and the build_state callbacks.
Add messages for failures in lwtunnel_build_state, and add the extarg to
nla_parse where possible in the build_state callbacks.

Signed-off-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
12 files changed:
include/linux/netlink.h
include/net/lwtunnel.h
net/core/lwt_bpf.c
net/core/lwtunnel.c
net/ipv4/fib_lookup.h
net/ipv4/fib_semantics.c
net/ipv4/fib_trie.c
net/ipv4/ip_tunnel_core.c
net/ipv6/ila/ila_lwt.c
net/ipv6/route.c
net/ipv6/seg6_iptunnel.c
net/mpls/mpls_iptunnel.c

index a68aad484c69a4ba0f692e11269d54b774ced596..8664fd26eb5d0c4a7896dc7c63200e5b3ee1569e 100644 (file)
@@ -102,6 +102,16 @@ struct netlink_ext_ack {
                (extack)->bad_attr = (attr);            \
 } while (0)
 
+#define NL_SET_ERR_MSG_ATTR(extack, attr, msg) do {    \
+       static const char __msg[] = (msg);              \
+       struct netlink_ext_ack *__extack = (extack);    \
+                                                       \
+       if (__extack) {                                 \
+               __extack->_msg = __msg;                 \
+               __extack->bad_attr = (attr);            \
+       }                                               \
+} while (0)
+
 extern void netlink_kernel_release(struct sock *sk);
 extern int __netlink_change_ngroups(struct sock *sk, unsigned int groups);
 extern int netlink_change_ngroups(struct sock *sk, unsigned int groups);
index ca6f002774ef6bfbb89eeb5d401b3d6e78e83c7c..7c26863b8cf4f51b31e95ed5e873688cf79d315b 100644 (file)
@@ -35,7 +35,8 @@ struct lwtunnel_state {
 struct lwtunnel_encap_ops {
        int (*build_state)(struct nlattr *encap,
                           unsigned int family, const void *cfg,
-                          struct lwtunnel_state **ts);
+                          struct lwtunnel_state **ts,
+                          struct netlink_ext_ack *extack);
        void (*destroy_state)(struct lwtunnel_state *lws);
        int (*output)(struct net *net, struct sock *sk, struct sk_buff *skb);
        int (*input)(struct sk_buff *skb);
@@ -114,7 +115,8 @@ int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len,
 int lwtunnel_build_state(u16 encap_type,
                         struct nlattr *encap,
                         unsigned int family, const void *cfg,
-                        struct lwtunnel_state **lws);
+                        struct lwtunnel_state **lws,
+                        struct netlink_ext_ack *extack);
 int lwtunnel_fill_encap(struct sk_buff *skb,
                        struct lwtunnel_state *lwtstate);
 int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate);
@@ -192,7 +194,8 @@ static inline int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len,
 static inline int lwtunnel_build_state(u16 encap_type,
                                       struct nlattr *encap,
                                       unsigned int family, const void *cfg,
-                                      struct lwtunnel_state **lws)
+                                      struct lwtunnel_state **lws,
+                                      struct netlink_ext_ack *extack)
 {
        return -EOPNOTSUPP;
 }
index b3bc0a31af9f3bd2d21fd12b9b2885d9b1573a4d..1307731ddfe4aa8889d63eab13d0145ca3432f31 100644 (file)
@@ -240,7 +240,8 @@ static const struct nla_policy bpf_nl_policy[LWT_BPF_MAX + 1] = {
 
 static int bpf_build_state(struct nlattr *nla,
                           unsigned int family, const void *cfg,
-                          struct lwtunnel_state **ts)
+                          struct lwtunnel_state **ts,
+                          struct netlink_ext_ack *extack)
 {
        struct nlattr *tb[LWT_BPF_MAX + 1];
        struct lwtunnel_state *newts;
@@ -250,7 +251,7 @@ static int bpf_build_state(struct nlattr *nla,
        if (family != AF_INET && family != AF_INET6)
                return -EAFNOSUPPORT;
 
-       ret = nla_parse_nested(tb, LWT_BPF_MAX, nla, bpf_nl_policy, NULL);
+       ret = nla_parse_nested(tb, LWT_BPF_MAX, nla, bpf_nl_policy, extack);
        if (ret < 0)
                return ret;
 
index ab840386a74df66c62eaa861b0fc5adbc1abc06d..d9cb3532f1ddc85ead8e14cba075d72a2b6c47df 100644 (file)
@@ -103,25 +103,39 @@ EXPORT_SYMBOL(lwtunnel_encap_del_ops);
 
 int lwtunnel_build_state(u16 encap_type,
                         struct nlattr *encap, unsigned int family,
-                        const void *cfg, struct lwtunnel_state **lws)
+                        const void *cfg, struct lwtunnel_state **lws,
+                        struct netlink_ext_ack *extack)
 {
        const struct lwtunnel_encap_ops *ops;
+       bool found = false;
        int ret = -EINVAL;
 
        if (encap_type == LWTUNNEL_ENCAP_NONE ||
-           encap_type > LWTUNNEL_ENCAP_MAX)
+           encap_type > LWTUNNEL_ENCAP_MAX) {
+               NL_SET_ERR_MSG_ATTR(extack, encap,
+                                   "Unknown LWT encapsulation type");
                return ret;
+       }
 
        ret = -EOPNOTSUPP;
        rcu_read_lock();
        ops = rcu_dereference(lwtun_encaps[encap_type]);
        if (likely(ops && ops->build_state && try_module_get(ops->owner))) {
-               ret = ops->build_state(encap, family, cfg, lws);
+               found = true;
+               ret = ops->build_state(encap, family, cfg, lws, extack);
                if (ret)
                        module_put(ops->owner);
        }
        rcu_read_unlock();
 
+       /* don't rely on -EOPNOTSUPP to detect match as build_state
+        * handlers could return it
+        */
+       if (!found) {
+               NL_SET_ERR_MSG_ATTR(extack, encap,
+                                   "LWT encapsulation type not supported");
+       }
+
        return ret;
 }
 EXPORT_SYMBOL(lwtunnel_build_state);
index 2704e08545dabb2cde38988462faf487ceb4409b..769ab87ebc4ba07204c285fe26d6cd20220f1076 100644 (file)
@@ -30,7 +30,8 @@ static inline void fib_alias_accessed(struct fib_alias *fa)
 void fib_release_info(struct fib_info *);
 struct fib_info *fib_create_info(struct fib_config *cfg,
                                 struct netlink_ext_ack *extack);
-int fib_nh_match(struct fib_config *cfg, struct fib_info *fi);
+int fib_nh_match(struct fib_config *cfg, struct fib_info *fi,
+                struct netlink_ext_ack *extack);
 int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, u32 tb_id,
                  u8 type, __be32 dst, int dst_len, u8 tos, struct fib_info *fi,
                  unsigned int);
index de9484658232b9caeba86fb0e7c7ce5d551129de..2157dc08c407aca7dddeab2d8da7b0703ec3acac 100644 (file)
@@ -532,7 +532,7 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
                                ret = lwtunnel_build_state(nla_get_u16(
                                                           nla_entype),
                                                           nla,  AF_INET, cfg,
-                                                          &lwtstate);
+                                                          &lwtstate, extack);
                                if (ret)
                                        goto errout;
                                nexthop_nh->nh_lwtstate =
@@ -614,7 +614,8 @@ static inline void fib_add_weight(struct fib_info *fi,
 static int fib_encap_match(u16 encap_type,
                           struct nlattr *encap,
                           const struct fib_nh *nh,
-                          const struct fib_config *cfg)
+                          const struct fib_config *cfg,
+                          struct netlink_ext_ack *extack)
 {
        struct lwtunnel_state *lwtstate;
        int ret, result = 0;
@@ -622,8 +623,8 @@ static int fib_encap_match(u16 encap_type,
        if (encap_type == LWTUNNEL_ENCAP_NONE)
                return 0;
 
-       ret = lwtunnel_build_state(encap_type, encap,
-                                  AF_INET, cfg, &lwtstate);
+       ret = lwtunnel_build_state(encap_type, encap, AF_INET,
+                                  cfg, &lwtstate, extack);
        if (!ret) {
                result = lwtunnel_cmp_encap(lwtstate, nh->nh_lwtstate);
                lwtstate_free(lwtstate);
@@ -632,7 +633,8 @@ static int fib_encap_match(u16 encap_type,
        return result;
 }
 
-int fib_nh_match(struct fib_config *cfg, struct fib_info *fi)
+int fib_nh_match(struct fib_config *cfg, struct fib_info *fi,
+                struct netlink_ext_ack *extack)
 {
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
        struct rtnexthop *rtnh;
@@ -644,9 +646,9 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi)
 
        if (cfg->fc_oif || cfg->fc_gw) {
                if (cfg->fc_encap) {
-                       if (fib_encap_match(cfg->fc_encap_type,
-                                           cfg->fc_encap, fi->fib_nh, cfg))
-                           return 1;
+                       if (fib_encap_match(cfg->fc_encap_type, cfg->fc_encap,
+                                           fi->fib_nh, cfg, extack))
+                               return 1;
                }
                if ((!cfg->fc_oif || cfg->fc_oif == fi->fib_nh->nh_oif) &&
                    (!cfg->fc_gw  || cfg->fc_gw == fi->fib_nh->nh_gw))
@@ -1148,7 +1150,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg,
                        }
                        err = lwtunnel_build_state(cfg->fc_encap_type,
                                                   cfg->fc_encap, AF_INET, cfg,
-                                                  &lwtstate);
+                                                  &lwtstate, extack);
                        if (err)
                                goto failure;
 
index a624d380c81ddc43349f4f9a7c04d94a752d6904..d56659e97a6e65da9486c35e848d180da108f6c2 100644 (file)
@@ -1562,7 +1562,7 @@ int fib_table_delete(struct net *net, struct fib_table *tb,
                     fi->fib_prefsrc == cfg->fc_prefsrc) &&
                    (!cfg->fc_protocol ||
                     fi->fib_protocol == cfg->fc_protocol) &&
-                   fib_nh_match(cfg, fi) == 0) {
+                   fib_nh_match(cfg, fi, extack) == 0) {
                        fa_to_delete = fa;
                        break;
                }
index baf196eaf1d81809a9264fb94daa58eae51f1bff..90e11479c725dbed365b154f721214ad8ec3251c 100644 (file)
@@ -228,14 +228,16 @@ static const struct nla_policy ip_tun_policy[LWTUNNEL_IP_MAX + 1] = {
 
 static int ip_tun_build_state(struct nlattr *attr,
                              unsigned int family, const void *cfg,
-                             struct lwtunnel_state **ts)
+                             struct lwtunnel_state **ts,
+                             struct netlink_ext_ack *extack)
 {
        struct ip_tunnel_info *tun_info;
        struct lwtunnel_state *new_state;
        struct nlattr *tb[LWTUNNEL_IP_MAX + 1];
        int err;
 
-       err = nla_parse_nested(tb, LWTUNNEL_IP_MAX, attr, ip_tun_policy, NULL);
+       err = nla_parse_nested(tb, LWTUNNEL_IP_MAX, attr, ip_tun_policy,
+                              extack);
        if (err < 0)
                return err;
 
@@ -325,7 +327,8 @@ static const struct nla_policy ip6_tun_policy[LWTUNNEL_IP6_MAX + 1] = {
 
 static int ip6_tun_build_state(struct nlattr *attr,
                               unsigned int family, const void *cfg,
-                              struct lwtunnel_state **ts)
+                              struct lwtunnel_state **ts,
+                              struct netlink_ext_ack *extack)
 {
        struct ip_tunnel_info *tun_info;
        struct lwtunnel_state *new_state;
@@ -333,7 +336,7 @@ static int ip6_tun_build_state(struct nlattr *attr,
        int err;
 
        err = nla_parse_nested(tb, LWTUNNEL_IP6_MAX, attr, ip6_tun_policy,
-                              NULL);
+                              extack);
        if (err < 0)
                return err;
 
index f4a413aba423488a20085e9f5b4910e68a692796..0c02a09bc3514c0860aa9ff4a56066f31a37a78a 100644 (file)
@@ -117,7 +117,8 @@ static const struct nla_policy ila_nl_policy[ILA_ATTR_MAX + 1] = {
 
 static int ila_build_state(struct nlattr *nla,
                           unsigned int family, const void *cfg,
-                          struct lwtunnel_state **ts)
+                          struct lwtunnel_state **ts,
+                          struct netlink_ext_ack *extack)
 {
        struct ila_lwt *ilwt;
        struct ila_params *p;
@@ -146,7 +147,7 @@ static int ila_build_state(struct nlattr *nla,
                return -EINVAL;
        }
 
-       ret = nla_parse_nested(tb, ILA_ATTR_MAX, nla, ila_nl_policy, NULL);
+       ret = nla_parse_nested(tb, ILA_ATTR_MAX, nla, ila_nl_policy, extack);
        if (ret < 0)
                return ret;
 
index 524a76b5206e2e5742aab554010d13b9edb4cc9e..9d9b5bbea153b2a0e60537f0578d78f33ed317ba 100644 (file)
@@ -1939,7 +1939,7 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
 
                err = lwtunnel_build_state(cfg->fc_encap_type,
                                           cfg->fc_encap, AF_INET6, cfg,
-                                          &lwtstate);
+                                          &lwtstate, extack);
                if (err)
                        goto out;
                rt->dst.lwtstate = lwtstate_get(lwtstate);
index 6a495490d43e1018206e628b917840d7ae8f9085..264d772d3c7d303bd0cc0520702a54e3b3e8671e 100644 (file)
@@ -326,7 +326,8 @@ drop:
 
 static int seg6_build_state(struct nlattr *nla,
                            unsigned int family, const void *cfg,
-                           struct lwtunnel_state **ts)
+                           struct lwtunnel_state **ts,
+                           struct netlink_ext_ack *extack)
 {
        struct nlattr *tb[SEG6_IPTUNNEL_MAX + 1];
        struct seg6_iptunnel_encap *tuninfo;
@@ -336,7 +337,7 @@ static int seg6_build_state(struct nlattr *nla,
        int err;
 
        err = nla_parse_nested(tb, SEG6_IPTUNNEL_MAX, nla,
-                              seg6_iptunnel_policy, NULL);
+                              seg6_iptunnel_policy, extack);
 
        if (err < 0)
                return err;
index 369c7a23c86c1407702917488c90e0f3e7f8ee1a..15e1aa708e5007f81fbe1cd1bee49dd40525c0c2 100644 (file)
@@ -159,7 +159,8 @@ drop:
 
 static int mpls_build_state(struct nlattr *nla,
                            unsigned int family, const void *cfg,
-                           struct lwtunnel_state **ts)
+                           struct lwtunnel_state **ts,
+                           struct netlink_ext_ack *extack)
 {
        struct mpls_iptunnel_encap *tun_encap_info;
        struct nlattr *tb[MPLS_IPTUNNEL_MAX + 1];
@@ -168,7 +169,7 @@ static int mpls_build_state(struct nlattr *nla,
        int ret;
 
        ret = nla_parse_nested(tb, MPLS_IPTUNNEL_MAX, nla,
-                              mpls_iptunnel_policy, NULL);
+                              mpls_iptunnel_policy, extack);
        if (ret < 0)
                return ret;