mirror of
https://github.com/openvswitch/ovs
synced 2025-09-03 07:45:30 +00:00
tc: Support new terse dump kernel API
When dumping flows in terse mode set TCA_DUMP_FLAGS attribute to TCA_DUMP_FLAGS_TERSE flag to prevent unnecessary copying of data between kernel and user spaces. Only expect kernel to provide cookie, stats and flags when dumping filters in terse mode. Signed-off-by: Vlad Buslov <vladbu@mellanox.com> Reviewed-by: Roi Dayan <roid@mellanox.com> Signed-off-by: Simon Horman <simon.horman@netronome.com>
This commit is contained in:
committed by
Simon Horman
parent
191536574e
commit
5db012c4ac
@@ -390,7 +390,7 @@ netdev_tc_flow_dump_create(struct netdev *netdev,
|
|||||||
dump->terse = terse;
|
dump->terse = terse;
|
||||||
|
|
||||||
id = tc_make_tcf_id(ifindex, block_id, prio, hook);
|
id = tc_make_tcf_id(ifindex, block_id, prio, hook);
|
||||||
tc_dump_flower_start(&id, dump->nl_dump);
|
tc_dump_flower_start(&id, dump->nl_dump, terse);
|
||||||
|
|
||||||
*dump_out = dump;
|
*dump_out = dump;
|
||||||
|
|
||||||
@@ -951,7 +951,7 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump,
|
|||||||
while (nl_dump_next(dump->nl_dump, &nl_flow, rbuffer)) {
|
while (nl_dump_next(dump->nl_dump, &nl_flow, rbuffer)) {
|
||||||
struct tc_flower flower;
|
struct tc_flower flower;
|
||||||
|
|
||||||
if (parse_netlink_to_tc_flower(&nl_flow, &id, &flower)) {
|
if (parse_netlink_to_tc_flower(&nl_flow, &id, &flower, dump->terse)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
59
lib/tc.c
59
lib/tc.c
@@ -51,9 +51,14 @@
|
|||||||
#define TCM_IFINDEX_MAGIC_BLOCK (0xFFFFFFFFU)
|
#define TCM_IFINDEX_MAGIC_BLOCK (0xFFFFFFFFU)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if TCA_MAX < 14
|
#ifndef TCA_DUMP_FLAGS_TERSE
|
||||||
|
#define TCA_DUMP_FLAGS_TERSE (1 << 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if TCA_MAX < 15
|
||||||
#define TCA_CHAIN 11
|
#define TCA_CHAIN 11
|
||||||
#define TCA_INGRESS_BLOCK 13
|
#define TCA_INGRESS_BLOCK 13
|
||||||
|
#define TCA_DUMP_FLAGS 15
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VLOG_DEFINE_THIS_MODULE(tc);
|
VLOG_DEFINE_THIS_MODULE(tc);
|
||||||
@@ -417,6 +422,11 @@ static const struct nl_policy tca_flower_policy[] = {
|
|||||||
.optional = true, },
|
.optional = true, },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct nl_policy tca_flower_terse_policy[] = {
|
||||||
|
[TCA_FLOWER_FLAGS] = { .type = NL_A_U32, .optional = false, },
|
||||||
|
[TCA_FLOWER_ACT] = { .type = NL_A_NESTED, .optional = false, },
|
||||||
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nl_parse_flower_eth(struct nlattr **attrs, struct tc_flower *flower)
|
nl_parse_flower_eth(struct nlattr **attrs, struct tc_flower *flower)
|
||||||
{
|
{
|
||||||
@@ -1595,7 +1605,7 @@ nl_parse_act_csum(struct nlattr *options, struct tc_flower *flower)
|
|||||||
static const struct nl_policy act_policy[] = {
|
static const struct nl_policy act_policy[] = {
|
||||||
[TCA_ACT_KIND] = { .type = NL_A_STRING, .optional = false, },
|
[TCA_ACT_KIND] = { .type = NL_A_STRING, .optional = false, },
|
||||||
[TCA_ACT_COOKIE] = { .type = NL_A_UNSPEC, .optional = true, },
|
[TCA_ACT_COOKIE] = { .type = NL_A_UNSPEC, .optional = true, },
|
||||||
[TCA_ACT_OPTIONS] = { .type = NL_A_NESTED, .optional = false, },
|
[TCA_ACT_OPTIONS] = { .type = NL_A_NESTED, .optional = true, },
|
||||||
[TCA_ACT_STATS] = { .type = NL_A_NESTED, .optional = false, },
|
[TCA_ACT_STATS] = { .type = NL_A_NESTED, .optional = false, },
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1606,7 +1616,8 @@ static const struct nl_policy stats_policy[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nl_parse_single_action(struct nlattr *action, struct tc_flower *flower)
|
nl_parse_single_action(struct nlattr *action, struct tc_flower *flower,
|
||||||
|
bool terse)
|
||||||
{
|
{
|
||||||
struct nlattr *act_options;
|
struct nlattr *act_options;
|
||||||
struct nlattr *act_stats;
|
struct nlattr *act_stats;
|
||||||
@@ -1619,7 +1630,8 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower)
|
|||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if (!nl_parse_nested(action, act_policy, action_attrs,
|
if (!nl_parse_nested(action, act_policy, action_attrs,
|
||||||
ARRAY_SIZE(act_policy))) {
|
ARRAY_SIZE(act_policy)) ||
|
||||||
|
(!terse && !action_attrs[TCA_ACT_OPTIONS])) {
|
||||||
VLOG_ERR_RL(&error_rl, "failed to parse single action options");
|
VLOG_ERR_RL(&error_rl, "failed to parse single action options");
|
||||||
return EPROTO;
|
return EPROTO;
|
||||||
}
|
}
|
||||||
@@ -1628,7 +1640,9 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower)
|
|||||||
act_options = action_attrs[TCA_ACT_OPTIONS];
|
act_options = action_attrs[TCA_ACT_OPTIONS];
|
||||||
act_cookie = action_attrs[TCA_ACT_COOKIE];
|
act_cookie = action_attrs[TCA_ACT_COOKIE];
|
||||||
|
|
||||||
if (!strcmp(act_kind, "gact")) {
|
if (terse) {
|
||||||
|
/* Terse dump doesn't provide act options attribute. */
|
||||||
|
} else if (!strcmp(act_kind, "gact")) {
|
||||||
err = nl_parse_act_gact(act_options, flower);
|
err = nl_parse_act_gact(act_options, flower);
|
||||||
} else if (!strcmp(act_kind, "mirred")) {
|
} else if (!strcmp(act_kind, "mirred")) {
|
||||||
err = nl_parse_act_mirred(act_options, flower);
|
err = nl_parse_act_mirred(act_options, flower);
|
||||||
@@ -1678,7 +1692,8 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower)
|
|||||||
#define TCA_ACT_MIN_PRIO 1
|
#define TCA_ACT_MIN_PRIO 1
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nl_parse_flower_actions(struct nlattr **attrs, struct tc_flower *flower)
|
nl_parse_flower_actions(struct nlattr **attrs, struct tc_flower *flower,
|
||||||
|
bool terse)
|
||||||
{
|
{
|
||||||
const struct nlattr *actions = attrs[TCA_FLOWER_ACT];
|
const struct nlattr *actions = attrs[TCA_FLOWER_ACT];
|
||||||
static struct nl_policy actions_orders_policy[TCA_ACT_MAX_NUM + 1] = {};
|
static struct nl_policy actions_orders_policy[TCA_ACT_MAX_NUM + 1] = {};
|
||||||
@@ -1704,7 +1719,7 @@ nl_parse_flower_actions(struct nlattr **attrs, struct tc_flower *flower)
|
|||||||
VLOG_DBG_RL(&error_rl, "Can only support %d actions", TCA_ACT_MAX_NUM);
|
VLOG_DBG_RL(&error_rl, "Can only support %d actions", TCA_ACT_MAX_NUM);
|
||||||
return EOPNOTSUPP;
|
return EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
err = nl_parse_single_action(actions_orders[i], flower);
|
err = nl_parse_single_action(actions_orders[i], flower, terse);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
@@ -1723,11 +1738,21 @@ nl_parse_flower_actions(struct nlattr **attrs, struct tc_flower *flower)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nl_parse_flower_options(struct nlattr *nl_options, struct tc_flower *flower)
|
nl_parse_flower_options(struct nlattr *nl_options, struct tc_flower *flower,
|
||||||
|
bool terse)
|
||||||
{
|
{
|
||||||
struct nlattr *attrs[ARRAY_SIZE(tca_flower_policy)];
|
struct nlattr *attrs[ARRAY_SIZE(tca_flower_policy)];
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
if (terse) {
|
||||||
|
if (!nl_parse_nested(nl_options, tca_flower_terse_policy,
|
||||||
|
attrs, ARRAY_SIZE(tca_flower_terse_policy))) {
|
||||||
|
VLOG_ERR_RL(&error_rl, "failed to parse flower classifier terse options");
|
||||||
|
return EPROTO;
|
||||||
|
}
|
||||||
|
goto skip_flower_opts;
|
||||||
|
}
|
||||||
|
|
||||||
if (!nl_parse_nested(nl_options, tca_flower_policy,
|
if (!nl_parse_nested(nl_options, tca_flower_policy,
|
||||||
attrs, ARRAY_SIZE(tca_flower_policy))) {
|
attrs, ARRAY_SIZE(tca_flower_policy))) {
|
||||||
VLOG_ERR_RL(&error_rl, "failed to parse flower classifier options");
|
VLOG_ERR_RL(&error_rl, "failed to parse flower classifier options");
|
||||||
@@ -1743,13 +1768,14 @@ nl_parse_flower_options(struct nlattr *nl_options, struct tc_flower *flower)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
skip_flower_opts:
|
||||||
nl_parse_flower_flags(attrs, flower);
|
nl_parse_flower_flags(attrs, flower);
|
||||||
return nl_parse_flower_actions(attrs, flower);
|
return nl_parse_flower_actions(attrs, flower, terse);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tcf_id *id,
|
parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tcf_id *id,
|
||||||
struct tc_flower *flower)
|
struct tc_flower *flower, bool terse)
|
||||||
{
|
{
|
||||||
struct tcmsg *tc;
|
struct tcmsg *tc;
|
||||||
struct nlattr *ta[ARRAY_SIZE(tca_policy)];
|
struct nlattr *ta[ARRAY_SIZE(tca_policy)];
|
||||||
@@ -1792,15 +1818,22 @@ parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tcf_id *id,
|
|||||||
return EPROTO;
|
return EPROTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nl_parse_flower_options(ta[TCA_OPTIONS], flower);
|
return nl_parse_flower_options(ta[TCA_OPTIONS], flower, terse);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
tc_dump_flower_start(struct tcf_id *id, struct nl_dump *dump)
|
tc_dump_flower_start(struct tcf_id *id, struct nl_dump *dump, bool terse)
|
||||||
{
|
{
|
||||||
struct ofpbuf request;
|
struct ofpbuf request;
|
||||||
|
|
||||||
request_from_tcf_id(id, 0, RTM_GETTFILTER, NLM_F_DUMP, &request);
|
request_from_tcf_id(id, 0, RTM_GETTFILTER, NLM_F_DUMP, &request);
|
||||||
|
if (terse) {
|
||||||
|
struct nla_bitfield32 dump_flags = { TCA_DUMP_FLAGS_TERSE,
|
||||||
|
TCA_DUMP_FLAGS_TERSE };
|
||||||
|
|
||||||
|
nl_msg_put_unspec(&request, TCA_DUMP_FLAGS, &dump_flags,
|
||||||
|
sizeof dump_flags);
|
||||||
|
}
|
||||||
nl_dump_start(dump, NETLINK_ROUTE, &request);
|
nl_dump_start(dump, NETLINK_ROUTE, &request);
|
||||||
ofpbuf_uninit(&request);
|
ofpbuf_uninit(&request);
|
||||||
|
|
||||||
@@ -1829,7 +1862,7 @@ tc_get_flower(struct tcf_id *id, struct tc_flower *flower)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = parse_netlink_to_tc_flower(reply, id, flower);
|
error = parse_netlink_to_tc_flower(reply, id, flower, false);
|
||||||
ofpbuf_delete(reply);
|
ofpbuf_delete(reply);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
5
lib/tc.h
5
lib/tc.h
@@ -341,10 +341,11 @@ BUILD_ASSERT_DECL(offsetof(struct tc_flower, rewrite)
|
|||||||
int tc_replace_flower(struct tcf_id *id, struct tc_flower *flower);
|
int tc_replace_flower(struct tcf_id *id, struct tc_flower *flower);
|
||||||
int tc_del_filter(struct tcf_id *id);
|
int tc_del_filter(struct tcf_id *id);
|
||||||
int tc_get_flower(struct tcf_id *id, struct tc_flower *flower);
|
int tc_get_flower(struct tcf_id *id, struct tc_flower *flower);
|
||||||
int tc_dump_flower_start(struct tcf_id *id, struct nl_dump *dump);
|
int tc_dump_flower_start(struct tcf_id *id, struct nl_dump *dump, bool terse);
|
||||||
int parse_netlink_to_tc_flower(struct ofpbuf *reply,
|
int parse_netlink_to_tc_flower(struct ofpbuf *reply,
|
||||||
struct tcf_id *id,
|
struct tcf_id *id,
|
||||||
struct tc_flower *flower);
|
struct tc_flower *flower,
|
||||||
|
bool terse);
|
||||||
void tc_set_policy(const char *policy);
|
void tc_set_policy(const char *policy);
|
||||||
|
|
||||||
#endif /* tc.h */
|
#endif /* tc.h */
|
||||||
|
Reference in New Issue
Block a user