|
@@ -111,6 +111,7 @@ static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
|
|
{
|
|
{
|
|
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];
|
|
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);
|
|
@@ -128,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;
|
|
@@ -145,9 +151,11 @@ static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
done:
|
|
done:
|
|
|
|
+ if (index >= 0)
|
|
|
|
+ cb->args[0] = index + 1;
|
|
|
|
+
|
|
spin_unlock_bh(&hinfo->lock);
|
|
spin_unlock_bh(&hinfo->lock);
|
|
if (n_i) {
|
|
if (n_i) {
|
|
- cb->args[0] += n_i;
|
|
|
|
if (act_flags & TCA_FLAG_LARGE_DUMP_ON)
|
|
if (act_flags & TCA_FLAG_LARGE_DUMP_ON)
|
|
cb->args[1] = n_i;
|
|
cb->args[1] = n_i;
|
|
}
|
|
}
|
|
@@ -1077,6 +1085,7 @@ static u32 tcaa_root_flags_allowed = TCA_FLAG_LARGE_DUMP_ON;
|
|
static const struct nla_policy tcaa_policy[TCA_ROOT_MAX + 1] = {
|
|
static const struct nla_policy tcaa_policy[TCA_ROOT_MAX + 1] = {
|
|
[TCA_ROOT_FLAGS] = { .type = NLA_BITFIELD32,
|
|
[TCA_ROOT_FLAGS] = { .type = NLA_BITFIELD32,
|
|
.validation_data = &tcaa_root_flags_allowed },
|
|
.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,
|
|
@@ -1166,8 +1175,10 @@ static int tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
|
|
struct tcamsg *t = (struct tcamsg *) nlmsg_data(cb->nlh);
|
|
struct tcamsg *t = (struct tcamsg *) nlmsg_data(cb->nlh);
|
|
struct nlattr *tb[TCA_ROOT_MAX + 1];
|
|
struct nlattr *tb[TCA_ROOT_MAX + 1];
|
|
struct nlattr *count_attr = NULL;
|
|
struct nlattr *count_attr = NULL;
|
|
|
|
+ unsigned long jiffy_since = 0;
|
|
struct nlattr *kind = NULL;
|
|
struct nlattr *kind = NULL;
|
|
struct nla_bitfield32 bf;
|
|
struct nla_bitfield32 bf;
|
|
|
|
+ u32 msecs_since = 0;
|
|
u32 act_count = 0;
|
|
u32 act_count = 0;
|
|
|
|
|
|
ret = nlmsg_parse(cb->nlh, sizeof(struct tcamsg), tb, TCA_ROOT_MAX,
|
|
ret = nlmsg_parse(cb->nlh, sizeof(struct tcamsg), tb, TCA_ROOT_MAX,
|
|
@@ -1191,15 +1202,23 @@ static int tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
|
|
cb->args[2] = bf.value;
|
|
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));
|
|
count_attr = nla_reserve(skb, TCA_ROOT_COUNT, sizeof(u32));
|
|
if (!count_attr)
|
|
if (!count_attr)
|
|
goto out_module_put;
|
|
goto out_module_put;
|