From: Vlad Buslov <vla...@mellanox.com>

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 <vla...@mellanox.com>
Reviewed-by: Roi Dayan <r...@mellanox.com>
---
 lib/netdev-offload-tc.c |  4 ++--
 lib/tc.c                | 59 ++++++++++++++++++++++++++++++++++++++-----------
 lib/tc.h                |  5 +++--
 3 files changed, 51 insertions(+), 17 deletions(-)

diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c
index 3ba70db4690b..0ad86c448bdf 100644
--- a/lib/netdev-offload-tc.c
+++ b/lib/netdev-offload-tc.c
@@ -390,7 +390,7 @@ netdev_tc_flow_dump_create(struct netdev *netdev,
     dump->terse = terse;
 
     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;
 
@@ -937,7 +937,7 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump,
     while (nl_dump_next(dump->nl_dump, &nl_flow, rbuffer)) {
         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;
         }
 
diff --git a/lib/tc.c b/lib/tc.c
index 12af0192b614..d0d9d0b047f7 100644
--- a/lib/tc.c
+++ b/lib/tc.c
@@ -51,9 +51,14 @@
 #define TCM_IFINDEX_MAGIC_BLOCK (0xFFFFFFFFU)
 #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_INGRESS_BLOCK 13
+#define TCA_DUMP_FLAGS 15
 #endif
 
 VLOG_DEFINE_THIS_MODULE(tc);
@@ -411,6 +416,11 @@ static const struct nl_policy tca_flower_policy[] = {
                                         .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
 nl_parse_flower_eth(struct nlattr **attrs, struct tc_flower *flower)
 {
@@ -1573,7 +1583,7 @@ nl_parse_act_csum(struct nlattr *options, struct 
tc_flower *flower)
 static const struct nl_policy act_policy[] = {
     [TCA_ACT_KIND] = { .type = NL_A_STRING, .optional = false, },
     [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, },
 };
 
@@ -1584,7 +1594,8 @@ static const struct nl_policy stats_policy[] = {
 };
 
 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_stats;
@@ -1597,7 +1608,8 @@ nl_parse_single_action(struct nlattr *action, struct 
tc_flower *flower)
     int err = 0;
 
     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");
         return EPROTO;
     }
@@ -1606,7 +1618,9 @@ nl_parse_single_action(struct nlattr *action, struct 
tc_flower *flower)
     act_options = action_attrs[TCA_ACT_OPTIONS];
     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);
     } else if (!strcmp(act_kind, "mirred")) {
         err = nl_parse_act_mirred(act_options, flower);
@@ -1656,7 +1670,8 @@ nl_parse_single_action(struct nlattr *action, struct 
tc_flower *flower)
 #define TCA_ACT_MIN_PRIO 1
 
 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];
     static struct nl_policy actions_orders_policy[TCA_ACT_MAX_NUM + 1] = {};
@@ -1682,7 +1697,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);
                 return EOPNOTSUPP;
             }
-            err = nl_parse_single_action(actions_orders[i], flower);
+            err = nl_parse_single_action(actions_orders[i], flower, terse);
 
             if (err) {
                 return err;
@@ -1701,11 +1716,21 @@ nl_parse_flower_actions(struct nlattr **attrs, struct 
tc_flower *flower)
 }
 
 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)];
     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,
                          attrs, ARRAY_SIZE(tca_flower_policy))) {
         VLOG_ERR_RL(&error_rl, "failed to parse flower classifier options");
@@ -1721,13 +1746,14 @@ nl_parse_flower_options(struct nlattr *nl_options, 
struct tc_flower *flower)
         return err;
     }
 
+skip_flower_opts:
     nl_parse_flower_flags(attrs, flower);
-    return nl_parse_flower_actions(attrs, flower);
+    return nl_parse_flower_actions(attrs, flower, terse);
 }
 
 int
 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 nlattr *ta[ARRAY_SIZE(tca_policy)];
@@ -1770,15 +1796,22 @@ parse_netlink_to_tc_flower(struct ofpbuf *reply, struct 
tcf_id *id,
         return EPROTO;
     }
 
-    return nl_parse_flower_options(ta[TCA_OPTIONS], flower);
+    return nl_parse_flower_options(ta[TCA_OPTIONS], flower, terse);
 }
 
 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;
 
     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);
     ofpbuf_uninit(&request);
 
@@ -1807,7 +1840,7 @@ tc_get_flower(struct tcf_id *id, struct tc_flower *flower)
         return error;
     }
 
-    error = parse_netlink_to_tc_flower(reply, id, flower);
+    error = parse_netlink_to_tc_flower(reply, id, flower, false);
     ofpbuf_delete(reply);
     return error;
 }
diff --git a/lib/tc.h b/lib/tc.h
index 24a4994fd17e..11f3231f9dfe 100644
--- a/lib/tc.h
+++ b/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_del_filter(struct tcf_id *id);
 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,
                                struct tcf_id *id,
-                               struct tc_flower *flower);
+                               struct tc_flower *flower,
+                               bool terse);
 void tc_set_policy(const char *policy);
 
 #endif /* tc.h */
-- 
2.8.4

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to