|
@@ -110,6 +110,8 @@ static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
|
|
struct netlink_callback *cb)
|
|
struct netlink_callback *cb)
|
|
{
|
|
{
|
|
int err = 0, index = -1, i = 0, s_i = 0, n_i = 0;
|
|
int err = 0, index = -1, i = 0, s_i = 0, n_i = 0;
|
|
|
|
+ u32 act_flags = cb->args[2];
|
|
|
|
+ unsigned long jiffy_since = cb->args[3];
|
|
struct nlattr *nest;
|
|
struct nlattr *nest;
|
|
|
|
|
|
spin_lock_bh(&hinfo->lock);
|
|
spin_lock_bh(&hinfo->lock);
|
|
@@ -127,6 +129,11 @@ static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
|
|
if (index < s_i)
|
|
if (index < s_i)
|
|
continue;
|
|
continue;
|
|
|
|
|
|
|
|
+ if (jiffy_since &&
|
|
|
|
+ time_after(jiffy_since,
|
|
|
|
+ (unsigned long)p->tcfa_tm.lastuse))
|
|
|
|
+ continue;
|
|
|
|
+
|
|
nest = nla_nest_start(skb, n_i);
|
|
nest = nla_nest_start(skb, n_i);
|
|
if (nest == NULL)
|
|
if (nest == NULL)
|
|
goto nla_put_failure;
|
|
goto nla_put_failure;
|
|
@@ -138,14 +145,20 @@ static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
|
|
}
|
|
}
|
|
nla_nest_end(skb, nest);
|
|
nla_nest_end(skb, nest);
|
|
n_i++;
|
|
n_i++;
|
|
- if (n_i >= TCA_ACT_MAX_PRIO)
|
|
|
|
|
|
+ if (!(act_flags & TCA_FLAG_LARGE_DUMP_ON) &&
|
|
|
|
+ n_i >= TCA_ACT_MAX_PRIO)
|
|
goto done;
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
done:
|
|
done:
|
|
|
|
+ if (index >= 0)
|
|
|
|
+ cb->args[0] = index + 1;
|
|
|
|
+
|
|
spin_unlock_bh(&hinfo->lock);
|
|
spin_unlock_bh(&hinfo->lock);
|
|
- if (n_i)
|
|
|
|
- cb->args[0] += n_i;
|
|
|
|
|
|
+ if (n_i) {
|
|
|
|
+ if (act_flags & TCA_FLAG_LARGE_DUMP_ON)
|
|
|
|
+ cb->args[1] = n_i;
|
|
|
|
+ }
|
|
return n_i;
|
|
return n_i;
|
|
|
|
|
|
nla_put_failure:
|
|
nla_put_failure:
|
|
@@ -1068,11 +1081,18 @@ static int tcf_action_add(struct net *net, struct nlattr *nla,
|
|
return tcf_add_notify(net, n, &actions, portid);
|
|
return tcf_add_notify(net, n, &actions, portid);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static u32 tcaa_root_flags_allowed = TCA_FLAG_LARGE_DUMP_ON;
|
|
|
|
+static const struct nla_policy tcaa_policy[TCA_ROOT_MAX + 1] = {
|
|
|
|
+ [TCA_ROOT_FLAGS] = { .type = NLA_BITFIELD32,
|
|
|
|
+ .validation_data = &tcaa_root_flags_allowed },
|
|
|
|
+ [TCA_ROOT_TIME_DELTA] = { .type = NLA_U32 },
|
|
|
|
+};
|
|
|
|
+
|
|
static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n,
|
|
static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n,
|
|
struct netlink_ext_ack *extack)
|
|
struct netlink_ext_ack *extack)
|
|
{
|
|
{
|
|
struct net *net = sock_net(skb->sk);
|
|
struct net *net = sock_net(skb->sk);
|
|
- struct nlattr *tca[TCA_ACT_MAX + 1];
|
|
|
|
|
|
+ struct nlattr *tca[TCA_ROOT_MAX + 1];
|
|
u32 portid = skb ? NETLINK_CB(skb).portid : 0;
|
|
u32 portid = skb ? NETLINK_CB(skb).portid : 0;
|
|
int ret = 0, ovr = 0;
|
|
int ret = 0, ovr = 0;
|
|
|
|
|
|
@@ -1080,7 +1100,7 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n,
|
|
!netlink_capable(skb, CAP_NET_ADMIN))
|
|
!netlink_capable(skb, CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
return -EPERM;
|
|
|
|
|
|
- ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ACT_MAX, NULL,
|
|
|
|
|
|
+ ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ROOT_MAX, NULL,
|
|
extack);
|
|
extack);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
return ret;
|
|
return ret;
|
|
@@ -1121,16 +1141,12 @@ replay:
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
-static struct nlattr *find_dump_kind(const struct nlmsghdr *n)
|
|
|
|
|
|
+static struct nlattr *find_dump_kind(struct nlattr **nla)
|
|
{
|
|
{
|
|
struct nlattr *tb1, *tb2[TCA_ACT_MAX + 1];
|
|
struct nlattr *tb1, *tb2[TCA_ACT_MAX + 1];
|
|
struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
|
|
struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
|
|
- struct nlattr *nla[TCAA_MAX + 1];
|
|
|
|
struct nlattr *kind;
|
|
struct nlattr *kind;
|
|
|
|
|
|
- if (nlmsg_parse(n, sizeof(struct tcamsg), nla, TCAA_MAX,
|
|
|
|
- NULL, NULL) < 0)
|
|
|
|
- return NULL;
|
|
|
|
tb1 = nla[TCA_ACT_TAB];
|
|
tb1 = nla[TCA_ACT_TAB];
|
|
if (tb1 == NULL)
|
|
if (tb1 == NULL)
|
|
return NULL;
|
|
return NULL;
|
|
@@ -1157,8 +1173,20 @@ static int tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
|
|
struct tc_action_ops *a_o;
|
|
struct tc_action_ops *a_o;
|
|
int ret = 0;
|
|
int ret = 0;
|
|
struct tcamsg *t = (struct tcamsg *) nlmsg_data(cb->nlh);
|
|
struct tcamsg *t = (struct tcamsg *) nlmsg_data(cb->nlh);
|
|
- struct nlattr *kind = find_dump_kind(cb->nlh);
|
|
|
|
|
|
+ struct nlattr *tb[TCA_ROOT_MAX + 1];
|
|
|
|
+ struct nlattr *count_attr = NULL;
|
|
|
|
+ unsigned long jiffy_since = 0;
|
|
|
|
+ struct nlattr *kind = NULL;
|
|
|
|
+ struct nla_bitfield32 bf;
|
|
|
|
+ u32 msecs_since = 0;
|
|
|
|
+ u32 act_count = 0;
|
|
|
|
+
|
|
|
|
+ ret = nlmsg_parse(cb->nlh, sizeof(struct tcamsg), tb, TCA_ROOT_MAX,
|
|
|
|
+ tcaa_policy, NULL);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ return ret;
|
|
|
|
|
|
|
|
+ kind = find_dump_kind(tb);
|
|
if (kind == NULL) {
|
|
if (kind == NULL) {
|
|
pr_info("tc_dump_action: action bad kind\n");
|
|
pr_info("tc_dump_action: action bad kind\n");
|
|
return 0;
|
|
return 0;
|
|
@@ -1168,14 +1196,32 @@ static int tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
|
|
if (a_o == NULL)
|
|
if (a_o == NULL)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
|
|
+ cb->args[2] = 0;
|
|
|
|
+ if (tb[TCA_ROOT_FLAGS]) {
|
|
|
|
+ bf = nla_get_bitfield32(tb[TCA_ROOT_FLAGS]);
|
|
|
|
+ cb->args[2] = bf.value;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (tb[TCA_ROOT_TIME_DELTA]) {
|
|
|
|
+ msecs_since = nla_get_u32(tb[TCA_ROOT_TIME_DELTA]);
|
|
|
|
+ }
|
|
|
|
+
|
|
nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
|
|
nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
|
|
cb->nlh->nlmsg_type, sizeof(*t), 0);
|
|
cb->nlh->nlmsg_type, sizeof(*t), 0);
|
|
if (!nlh)
|
|
if (!nlh)
|
|
goto out_module_put;
|
|
goto out_module_put;
|
|
|
|
+
|
|
|
|
+ if (msecs_since)
|
|
|
|
+ jiffy_since = jiffies - msecs_to_jiffies(msecs_since);
|
|
|
|
+
|
|
t = nlmsg_data(nlh);
|
|
t = nlmsg_data(nlh);
|
|
t->tca_family = AF_UNSPEC;
|
|
t->tca_family = AF_UNSPEC;
|
|
t->tca__pad1 = 0;
|
|
t->tca__pad1 = 0;
|
|
t->tca__pad2 = 0;
|
|
t->tca__pad2 = 0;
|
|
|
|
+ cb->args[3] = jiffy_since;
|
|
|
|
+ count_attr = nla_reserve(skb, TCA_ROOT_COUNT, sizeof(u32));
|
|
|
|
+ if (!count_attr)
|
|
|
|
+ goto out_module_put;
|
|
|
|
|
|
nest = nla_nest_start(skb, TCA_ACT_TAB);
|
|
nest = nla_nest_start(skb, TCA_ACT_TAB);
|
|
if (nest == NULL)
|
|
if (nest == NULL)
|
|
@@ -1188,6 +1234,9 @@ static int tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
|
|
if (ret > 0) {
|
|
if (ret > 0) {
|
|
nla_nest_end(skb, nest);
|
|
nla_nest_end(skb, nest);
|
|
ret = skb->len;
|
|
ret = skb->len;
|
|
|
|
+ act_count = cb->args[1];
|
|
|
|
+ memcpy(nla_data(count_attr), &act_count, sizeof(u32));
|
|
|
|
+ cb->args[1] = 0;
|
|
} else
|
|
} else
|
|
nlmsg_trim(skb, b);
|
|
nlmsg_trim(skb, b);
|
|
|
|
|