diff mbox series

[ovs-dev,2/2] tc: Support new terse dump kernel API

Message ID 20200601125456.47571-3-roid@mellanox.com
State Superseded
Headers show
Series Implement terse dump for netdev-offload | expand

Commit Message

Roi Dayan June 1, 2020, 12:54 p.m. UTC
From: Vlad Buslov <vladbu@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 <vladbu@mellanox.com>
---
 lib/netdev-offload-tc.c |  4 ++--
 lib/tc.c                | 59 ++++++++++++++++++++++++++++++++++++++-----------
 lib/tc.h                |  5 +++--
 3 files changed, 51 insertions(+), 17 deletions(-)

Comments

Roi Dayan June 1, 2020, 1:01 p.m. UTC | #1
On 2020-06-01 3:54 PM, Roi Dayan wrote:
> From: Vlad Buslov <vladbu@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 <vladbu@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 */
> 

Reviewed-by: Roi Dayan <roid@mellanox.com>
0-day Robot June 1, 2020, 10:38 p.m. UTC | #2
Bleep bloop.  Greetings Roi Dayan, I am a robot and I have tried out your patch.
Thanks for your contribution.

I encountered some error that I wasn't expecting.  See the details below.


checkpatch:
WARNING: Line is 86 characters long (recommended limit is 79)
#146 FILE: lib/tc.c:1728:
            VLOG_ERR_RL(&error_rl, "failed to parse flower classifier terse options");

Lines checked: 226, Warnings: 1, Errors: 0


Please check this out.  If you feel there has been an error, please email aconole@redhat.com

Thanks,
0-day Robot
diff mbox series

Patch

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 */