Commit effe6792 authored by David Ahern's avatar David Ahern Committed by David S. Miller

net: Enable kernel side filtering of route dumps

Update parsing of route dump request to enable kernel side filtering.
Allow filtering results by protocol (e.g., which routing daemon installed
the route), route type (e.g., unicast), table id and nexthop device. These
amount to the low hanging fruit, yet a huge improvement, for dumping
routes.

ip_valid_fib_dump_req is called with RTNL held, so __dev_get_by_index can
be used to look up the device index without taking a reference. From
there filter->dev is only used during dump loops with the lock still held.

Set NLM_F_DUMP_FILTERED in the answer_flags so the user knows the results
have been filtered should no entries be returned.
Signed-off-by: default avatarDavid Ahern <dsahern@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cb167893
......@@ -465,5 +465,5 @@ u32 ip_mtu_from_fib_result(struct fib_result *res, __be32 daddr);
int ip_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
struct fib_dump_filter *filter,
struct netlink_ext_ack *extack);
struct netlink_callback *cb);
#endif /* _NET_FIB_H */
......@@ -804,9 +804,14 @@ static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
int ip_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
struct fib_dump_filter *filter,
struct netlink_ext_ack *extack)
struct netlink_callback *cb)
{
struct netlink_ext_ack *extack = cb->extack;
struct nlattr *tb[RTA_MAX + 1];
struct rtmsg *rtm;
int err, i;
ASSERT_RTNL();
if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) {
NL_SET_ERR_MSG(extack, "Invalid header for FIB dump request");
......@@ -815,8 +820,7 @@ int ip_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
rtm = nlmsg_data(nlh);
if (rtm->rtm_dst_len || rtm->rtm_src_len || rtm->rtm_tos ||
rtm->rtm_table || rtm->rtm_protocol || rtm->rtm_scope ||
rtm->rtm_type) {
rtm->rtm_scope) {
NL_SET_ERR_MSG(extack, "Invalid values in header for FIB dump request");
return -EINVAL;
}
......@@ -825,9 +829,42 @@ int ip_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
return -EINVAL;
}
if (nlmsg_attrlen(nlh, sizeof(*rtm))) {
NL_SET_ERR_MSG(extack, "Invalid data after header in FIB dump request");
return -EINVAL;
filter->flags = rtm->rtm_flags;
filter->protocol = rtm->rtm_protocol;
filter->rt_type = rtm->rtm_type;
filter->table_id = rtm->rtm_table;
err = nlmsg_parse_strict(nlh, sizeof(*rtm), tb, RTA_MAX,
rtm_ipv4_policy, extack);
if (err < 0)
return err;
for (i = 0; i <= RTA_MAX; ++i) {
int ifindex;
if (!tb[i])
continue;
switch (i) {
case RTA_TABLE:
filter->table_id = nla_get_u32(tb[i]);
break;
case RTA_OIF:
ifindex = nla_get_u32(tb[i]);
filter->dev = __dev_get_by_index(net, ifindex);
if (!filter->dev)
return -ENODEV;
break;
default:
NL_SET_ERR_MSG(extack, "Unsupported attribute in dump request");
return -EINVAL;
}
}
if (filter->flags || filter->protocol || filter->rt_type ||
filter->table_id || filter->dev) {
filter->filter_set = 1;
cb->answer_flags = NLM_F_DUMP_FILTERED;
}
return 0;
......@@ -846,7 +883,7 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
int dumped = 0, err;
if (cb->strict_check) {
err = ip_valid_fib_dump_req(net, nlh, &filter, cb->extack);
err = ip_valid_fib_dump_req(net, nlh, &filter, cb);
if (err < 0)
return err;
}
......
......@@ -2532,7 +2532,7 @@ static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
if (cb->strict_check) {
err = ip_valid_fib_dump_req(sock_net(skb->sk), cb->nlh,
&filter, cb->extack);
&filter, cb);
if (err < 0)
return err;
}
......
......@@ -580,7 +580,7 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
if (cb->strict_check) {
int err;
err = ip_valid_fib_dump_req(net, nlh, &arg.filter, cb->extack);
err = ip_valid_fib_dump_req(net, nlh, &arg.filter, cb);
if (err < 0)
return err;
} else if (nlmsg_len(nlh) >= sizeof(struct rtmsg)) {
......
......@@ -2463,7 +2463,7 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
if (cb->strict_check) {
err = ip_valid_fib_dump_req(sock_net(skb->sk), nlh,
&filter, cb->extack);
&filter, cb);
if (err < 0)
return err;
}
......
......@@ -2034,15 +2034,16 @@ static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
#if IS_ENABLED(CONFIG_INET)
static int mpls_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
struct fib_dump_filter *filter,
struct netlink_ext_ack *extack)
struct netlink_callback *cb)
{
return ip_valid_fib_dump_req(net, nlh, filter, extack);
return ip_valid_fib_dump_req(net, nlh, filter, cb);
}
#else
static int mpls_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
struct fib_dump_filter *filter,
struct netlink_ext_ack *extack)
struct netlink_callback *cb)
{
struct netlink_ext_ack *extack = cb->extack;
struct rtmsg *rtm;
if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) {
......@@ -2104,7 +2105,7 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
if (cb->strict_check) {
int err;
err = mpls_valid_fib_dump_req(net, nlh, &filter, cb->extack);
err = mpls_valid_fib_dump_req(net, nlh, &filter, cb);
if (err < 0)
return err;
......
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