Commit b16fb418 authored by Roopa Prabhu's avatar Roopa Prabhu Committed by David S. Miller

net: fib_rules: add extack support

Signed-off-by: default avatarRoopa Prabhu <roopa@cumulusnetworks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f9d4b0c1
...@@ -75,7 +75,8 @@ struct fib_rules_ops { ...@@ -75,7 +75,8 @@ struct fib_rules_ops {
int (*configure)(struct fib_rule *, int (*configure)(struct fib_rule *,
struct sk_buff *, struct sk_buff *,
struct fib_rule_hdr *, struct fib_rule_hdr *,
struct nlattr **); struct nlattr **,
struct netlink_ext_ack *);
int (*delete)(struct fib_rule *); int (*delete)(struct fib_rule *);
int (*compare)(struct fib_rule *, int (*compare)(struct fib_rule *,
struct fib_rule_hdr *, struct fib_rule_hdr *,
......
...@@ -469,14 +469,18 @@ static int fib_nl2rule(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -469,14 +469,18 @@ static int fib_nl2rule(struct sk_buff *skb, struct nlmsghdr *nlh,
if (frh->src_len) if (frh->src_len)
if (!tb[FRA_SRC] || if (!tb[FRA_SRC] ||
frh->src_len > (ops->addr_size * 8) || frh->src_len > (ops->addr_size * 8) ||
nla_len(tb[FRA_SRC]) != ops->addr_size) nla_len(tb[FRA_SRC]) != ops->addr_size) {
NL_SET_ERR_MSG(extack, "Invalid source address");
goto errout; goto errout;
}
if (frh->dst_len) if (frh->dst_len)
if (!tb[FRA_DST] || if (!tb[FRA_DST] ||
frh->dst_len > (ops->addr_size * 8) || frh->dst_len > (ops->addr_size * 8) ||
nla_len(tb[FRA_DST]) != ops->addr_size) nla_len(tb[FRA_DST]) != ops->addr_size) {
NL_SET_ERR_MSG(extack, "Invalid dst address");
goto errout; goto errout;
}
nlrule = kzalloc(ops->rule_size, GFP_KERNEL); nlrule = kzalloc(ops->rule_size, GFP_KERNEL);
if (!nlrule) { if (!nlrule) {
...@@ -537,6 +541,7 @@ static int fib_nl2rule(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -537,6 +541,7 @@ static int fib_nl2rule(struct sk_buff *skb, struct nlmsghdr *nlh,
nlrule->l3mdev = nla_get_u8(tb[FRA_L3MDEV]); nlrule->l3mdev = nla_get_u8(tb[FRA_L3MDEV]);
if (nlrule->l3mdev != 1) if (nlrule->l3mdev != 1)
#endif #endif
NL_SET_ERR_MSG(extack, "Invalid l3mdev");
goto errout_free; goto errout_free;
} }
...@@ -554,31 +559,41 @@ static int fib_nl2rule(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -554,31 +559,41 @@ static int fib_nl2rule(struct sk_buff *skb, struct nlmsghdr *nlh,
nlrule->suppress_ifgroup = -1; nlrule->suppress_ifgroup = -1;
if (tb[FRA_GOTO]) { if (tb[FRA_GOTO]) {
if (nlrule->action != FR_ACT_GOTO) if (nlrule->action != FR_ACT_GOTO) {
NL_SET_ERR_MSG(extack, "Unexpected goto");
goto errout_free; goto errout_free;
}
nlrule->target = nla_get_u32(tb[FRA_GOTO]); nlrule->target = nla_get_u32(tb[FRA_GOTO]);
/* Backward jumps are prohibited to avoid endless loops */ /* Backward jumps are prohibited to avoid endless loops */
if (nlrule->target <= nlrule->pref) if (nlrule->target <= nlrule->pref) {
NL_SET_ERR_MSG(extack, "Backward goto not supported");
goto errout_free; goto errout_free;
}
} else if (nlrule->action == FR_ACT_GOTO) { } else if (nlrule->action == FR_ACT_GOTO) {
NL_SET_ERR_MSG(extack, "Missing goto target for action goto");
goto errout_free; goto errout_free;
} }
if (nlrule->l3mdev && nlrule->table) if (nlrule->l3mdev && nlrule->table) {
NL_SET_ERR_MSG(extack, "l3mdev and table are mutually exclusive");
goto errout_free; goto errout_free;
}
if (tb[FRA_UID_RANGE]) { if (tb[FRA_UID_RANGE]) {
if (current_user_ns() != net->user_ns) { if (current_user_ns() != net->user_ns) {
err = -EPERM; err = -EPERM;
NL_SET_ERR_MSG(extack, "No permission to set uid");
goto errout_free; goto errout_free;
} }
nlrule->uid_range = nla_get_kuid_range(tb); nlrule->uid_range = nla_get_kuid_range(tb);
if (!uid_range_set(&nlrule->uid_range) || if (!uid_range_set(&nlrule->uid_range) ||
!uid_lte(nlrule->uid_range.start, nlrule->uid_range.end)) !uid_lte(nlrule->uid_range.start, nlrule->uid_range.end)) {
NL_SET_ERR_MSG(extack, "Invalid uid range");
goto errout_free; goto errout_free;
}
} else { } else {
nlrule->uid_range = fib_kuid_range_unset; nlrule->uid_range = fib_kuid_range_unset;
} }
...@@ -589,15 +604,19 @@ static int fib_nl2rule(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -589,15 +604,19 @@ static int fib_nl2rule(struct sk_buff *skb, struct nlmsghdr *nlh,
if (tb[FRA_SPORT_RANGE]) { if (tb[FRA_SPORT_RANGE]) {
err = nla_get_port_range(tb[FRA_SPORT_RANGE], err = nla_get_port_range(tb[FRA_SPORT_RANGE],
&nlrule->sport_range); &nlrule->sport_range);
if (err) if (err) {
NL_SET_ERR_MSG(extack, "Invalid sport range");
goto errout_free; goto errout_free;
}
} }
if (tb[FRA_DPORT_RANGE]) { if (tb[FRA_DPORT_RANGE]) {
err = nla_get_port_range(tb[FRA_DPORT_RANGE], err = nla_get_port_range(tb[FRA_DPORT_RANGE],
&nlrule->dport_range); &nlrule->dport_range);
if (err) if (err) {
NL_SET_ERR_MSG(extack, "Invalid dport range");
goto errout_free; goto errout_free;
}
} }
*rule = nlrule; *rule = nlrule;
...@@ -621,18 +640,23 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -621,18 +640,23 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh,
int err = -EINVAL, unresolved = 0; int err = -EINVAL, unresolved = 0;
bool user_priority = false; bool user_priority = false;
if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh))) if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh))) {
NL_SET_ERR_MSG(extack, "Invalid msg length");
goto errout; goto errout;
}
ops = lookup_rules_ops(net, frh->family); ops = lookup_rules_ops(net, frh->family);
if (!ops) { if (!ops) {
err = -EAFNOSUPPORT; err = -EAFNOSUPPORT;
NL_SET_ERR_MSG(extack, "Rule family not supported");
goto errout; goto errout;
} }
err = nlmsg_parse(nlh, sizeof(*frh), tb, FRA_MAX, ops->policy, extack); err = nlmsg_parse(nlh, sizeof(*frh), tb, FRA_MAX, ops->policy, extack);
if (err < 0) if (err < 0) {
NL_SET_ERR_MSG(extack, "Error parsing msg");
goto errout; goto errout;
}
err = fib_nl2rule(skb, nlh, extack, ops, tb, &rule, &user_priority); err = fib_nl2rule(skb, nlh, extack, ops, tb, &rule, &user_priority);
if (err) if (err)
...@@ -644,7 +668,7 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -644,7 +668,7 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh,
goto errout_free; goto errout_free;
} }
err = ops->configure(rule, skb, frh, tb); err = ops->configure(rule, skb, frh, tb, extack);
if (err < 0) if (err < 0)
goto errout_free; goto errout_free;
...@@ -723,18 +747,23 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -723,18 +747,23 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh,
int err = -EINVAL; int err = -EINVAL;
bool user_priority = false; bool user_priority = false;
if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh))) if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh))) {
NL_SET_ERR_MSG(extack, "Invalid msg length");
goto errout; goto errout;
}
ops = lookup_rules_ops(net, frh->family); ops = lookup_rules_ops(net, frh->family);
if (ops == NULL) { if (ops == NULL) {
err = -EAFNOSUPPORT; err = -EAFNOSUPPORT;
NL_SET_ERR_MSG(extack, "Rule family not supported");
goto errout; goto errout;
} }
err = nlmsg_parse(nlh, sizeof(*frh), tb, FRA_MAX, ops->policy, extack); err = nlmsg_parse(nlh, sizeof(*frh), tb, FRA_MAX, ops->policy, extack);
if (err < 0) if (err < 0) {
NL_SET_ERR_MSG(extack, "Error parsing msg");
goto errout; goto errout;
}
err = fib_nl2rule(skb, nlh, extack, ops, tb, &nlrule, &user_priority); err = fib_nl2rule(skb, nlh, extack, ops, tb, &nlrule, &user_priority);
if (err) if (err)
......
...@@ -121,13 +121,16 @@ static int dn_fib_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) ...@@ -121,13 +121,16 @@ static int dn_fib_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
static int dn_fib_rule_configure(struct fib_rule *rule, struct sk_buff *skb, static int dn_fib_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
struct fib_rule_hdr *frh, struct fib_rule_hdr *frh,
struct nlattr **tb) struct nlattr **tb,
struct netlink_ext_ack *extack)
{ {
int err = -EINVAL; int err = -EINVAL;
struct dn_fib_rule *r = (struct dn_fib_rule *)rule; struct dn_fib_rule *r = (struct dn_fib_rule *)rule;
if (frh->tos) if (frh->tos) {
NL_SET_ERR_MSG(extack, "Invalid tos value");
goto errout; goto errout;
}
if (rule->table == RT_TABLE_UNSPEC) { if (rule->table == RT_TABLE_UNSPEC) {
if (rule->action == FR_ACT_TO_TBL) { if (rule->action == FR_ACT_TO_TBL) {
......
...@@ -213,14 +213,17 @@ static const struct nla_policy fib4_rule_policy[FRA_MAX+1] = { ...@@ -213,14 +213,17 @@ static const struct nla_policy fib4_rule_policy[FRA_MAX+1] = {
static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
struct fib_rule_hdr *frh, struct fib_rule_hdr *frh,
struct nlattr **tb) struct nlattr **tb,
struct netlink_ext_ack *extack)
{ {
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
int err = -EINVAL; int err = -EINVAL;
struct fib4_rule *rule4 = (struct fib4_rule *) rule; struct fib4_rule *rule4 = (struct fib4_rule *) rule;
if (frh->tos & ~IPTOS_TOS_MASK) if (frh->tos & ~IPTOS_TOS_MASK) {
NL_SET_ERR_MSG(extack, "Invalid tos");
goto errout; goto errout;
}
/* split local/main if they are not already split */ /* split local/main if they are not already split */
err = fib_unmerge(net); err = fib_unmerge(net);
......
...@@ -201,7 +201,8 @@ static const struct nla_policy ipmr_rule_policy[FRA_MAX + 1] = { ...@@ -201,7 +201,8 @@ static const struct nla_policy ipmr_rule_policy[FRA_MAX + 1] = {
}; };
static int ipmr_rule_configure(struct fib_rule *rule, struct sk_buff *skb, static int ipmr_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
struct fib_rule_hdr *frh, struct nlattr **tb) struct fib_rule_hdr *frh, struct nlattr **tb,
struct netlink_ext_ack *extack)
{ {
return 0; return 0;
} }
......
...@@ -245,15 +245,18 @@ static const struct nla_policy fib6_rule_policy[FRA_MAX+1] = { ...@@ -245,15 +245,18 @@ static const struct nla_policy fib6_rule_policy[FRA_MAX+1] = {
static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
struct fib_rule_hdr *frh, struct fib_rule_hdr *frh,
struct nlattr **tb) struct nlattr **tb,
struct netlink_ext_ack *extack)
{ {
int err = -EINVAL; int err = -EINVAL;
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
struct fib6_rule *rule6 = (struct fib6_rule *) rule; struct fib6_rule *rule6 = (struct fib6_rule *) rule;
if (rule->action == FR_ACT_TO_TBL && !rule->l3mdev) { if (rule->action == FR_ACT_TO_TBL && !rule->l3mdev) {
if (rule->table == RT6_TABLE_UNSPEC) if (rule->table == RT6_TABLE_UNSPEC) {
NL_SET_ERR_MSG(extack, "Invalid table");
goto errout; goto errout;
}
if (fib6_new_table(net, rule->table) == NULL) { if (fib6_new_table(net, rule->table) == NULL) {
err = -ENOBUFS; err = -ENOBUFS;
......
...@@ -180,7 +180,8 @@ static const struct nla_policy ip6mr_rule_policy[FRA_MAX + 1] = { ...@@ -180,7 +180,8 @@ static const struct nla_policy ip6mr_rule_policy[FRA_MAX + 1] = {
}; };
static int ip6mr_rule_configure(struct fib_rule *rule, struct sk_buff *skb, static int ip6mr_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
struct fib_rule_hdr *frh, struct nlattr **tb) struct fib_rule_hdr *frh, struct nlattr **tb,
struct netlink_ext_ack *extack)
{ {
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment