diff mbox series

[ovs-dev] vswitchd: Ingress policing to use matchall instead of basic

Message ID 160bc3cabaf546fb15bb5172b49c5956f6f1e744.camel@redhat.com
State Changes Requested
Headers show
Series [ovs-dev] vswitchd: Ingress policing to use matchall instead of basic | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_Build_and_Test fail github build: failed

Commit Message

Mike Pattrick Oct. 14, 2021, 7:44 p.m. UTC
Currently ingress policing uses the basic classifier to apply traffic
control filters.

However, cls_basic was removed from the upcoming RHEL9. Basic is probably
not the proper classifier to use when the more accurage matchall
classifier is available and already in use in the code base. Switching
from basic to matchall allows us to remove a function.

I've also modified tests to detect when ingress policing fails to apply.

Signed-off-by: Michael Pattrick <mkp@redhat.com>
---
 lib/netdev-linux.c | 85 +++++++++-------------------------------------
 tests/ovs-vsctl.at | 24 ++++++-------
 2 files changed, 28 insertions(+), 81 deletions(-)

Comments

Eelco Chaudron Oct. 15, 2021, 8:53 a.m. UTC | #1
See some inline comments below…

On 14 Oct 2021, at 21:44, Michael Pattrick wrote:

> Currently ingress policing uses the basic classifier to apply traffic
> control filters.
>
> However, cls_basic was removed from the upcoming RHEL9. Basic is probably
> not the proper classifier to use when the more accurage matchall
> classifier is available and already in use in the code base. Switching
> from basic to matchall allows us to remove a function.
>
> I've also modified tests to detect when ingress policing fails to apply.
>
> Signed-off-by: Michael Pattrick <mkp@redhat.com>
> ---
>  lib/netdev-linux.c | 85 +++++++++-------------------------------------
>  tests/ovs-vsctl.at | 24 ++++++-------
>  2 files changed, 28 insertions(+), 81 deletions(-)
>
> diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
> index 97bd21be4..d64b88512 100644
> --- a/lib/netdev-linux.c
> +++ b/lib/netdev-linux.c
> @@ -486,10 +486,6 @@ static struct tcmsg *netdev_linux_tc_make_request(const struct netdev *,
>                                                    unsigned int flags,
>                                                    struct ofpbuf *);
>
> -static int tc_add_policer(struct netdev *, uint32_t kbits_rate,
> -                          uint32_t kbits_burst, uint32_t kpkts_rate,
> -                          uint32_t kpkts_burst);
> -
>  static int tc_parse_qdisc(const struct ofpbuf *, const char **kind,
>                            struct nlattr **options);
>  static int tc_parse_class(const struct ofpbuf *, unsigned int *queue_id,
> @@ -2662,6 +2658,20 @@ nl_msg_put_act_police(struct ofpbuf *request, struct tc_police police,
>      }
>  }
>
> +/* Adds a policer to 'netdev' with a rate of 'kbits_rate' and a burst size
> + * of 'kbits_burst', with a rate of 'kpkts_rate' and a burst size of
> + * 'kpkts_burst'.
> + *
> + * This function is equivalent to running:
> + *     /sbin/tc filter add dev <devname> parent ffff: protocol all prio 49
> + *              matchall police rate <kbits_rate>kbit burst <kbits_burst>k
> + *              mtu 65535 drop
> + *
> + * The configuration and stats may be seen with the following command:
> + *     /sbin/tc -s filter show dev <devname> parent ffff:
> + *
> + * Returns 0 if successful, otherwise a positive errno value.
> + */
>  static int
>  tc_add_matchall_policer(struct netdev *netdev, uint32_t kbits_rate,
>                          uint32_t kbits_burst, uint32_t kpkts_rate,
> @@ -2801,8 +2811,8 @@ netdev_linux_set_policing(struct netdev *netdev_, uint32_t kbits_rate,
>              goto out;
>          }
>
> -        error = tc_add_policer(netdev_, kbits_rate, kbits_burst,
> -                               kpkts_rate, kpkts_burst);
> +        error = tc_add_matchall_policer(netdev_, kbits_rate, kbits_burst,
> +                                        kpkts_rate, kpkts_burst);
>          if (error){
>              VLOG_WARN_RL(&rl, "%s: adding policing action failed: %s",
>                      netdev_name, ovs_strerror(error));

If you make this change, maybe it might be good to refactor netdev_linux_set_policing()? Meaning that I think, in “if (netdev_is_flow_api_enabled())” it has a bug where it’s not setting the netdev->k*_* values.

> @@ -5589,69 +5599,6 @@ netdev_linux_tc_make_request(const struct netdev *netdev, int type,
>      return tc_make_request(ifindex, type, flags, request);
>  }
>
> -/* Adds a policer to 'netdev' with a rate of 'kbits_rate' and a burst size
> - * of 'kbits_burst', with a rate of 'kpkts_rate' and a burst size of
> - * 'kpkts_burst'.
> - *
> - * This function is equivalent to running:
> - *     /sbin/tc filter add dev <devname> parent ffff: protocol all prio 49
> - *              basic police rate <kbits_rate>kbit burst <kbits_burst>k
> - *              mtu 65535 drop
> - *
> - * The configuration and stats may be seen with the following command:
> - *     /sbin/tc -s filter show dev <devname> parent ffff:
> - *
> - * Returns 0 if successful, otherwise a positive errno value.
> - */
> -static int
> -tc_add_policer(struct netdev *netdev, uint32_t kbits_rate,
> -               uint32_t kbits_burst, uint32_t kpkts_rate,
> -               uint32_t kpkts_burst)
> -{
> -    size_t basic_offset, police_offset;
> -    struct tc_police tc_police;
> -    struct ofpbuf request;
> -    struct tcmsg *tcmsg;
> -    int error;
> -    int mtu = 65535;
> -
> -    memset(&tc_police, 0, sizeof tc_police);
> -    tc_police.action = TC_POLICE_SHOT;
> -    tc_police.mtu = mtu;
> -    tc_fill_rate(&tc_police.rate, ((uint64_t) kbits_rate * 1000)/8, mtu);
> -
> -    /* The following appears wrong in one way: In networking a kilobit is
> -     * usually 1000 bits but this uses 1024 bits.
> -     *
> -     * However if you "fix" those problems then "tc filter show ..." shows
> -     * "125000b", meaning 125,000 bits, when OVS configures it for 1000 kbit ==
> -     * 1,000,000 bits, whereas this actually ends up doing the right thing from
> -     * tc's point of view.  Whatever. */
> -    tc_police.burst = tc_bytes_to_ticks(
> -        tc_police.rate.rate, MIN(UINT32_MAX / 1024, kbits_burst) * 1024 / 8);
> -    tcmsg = netdev_linux_tc_make_request(netdev, RTM_NEWTFILTER,
> -                                         NLM_F_EXCL | NLM_F_CREATE, &request);
> -    if (!tcmsg) {
> -        return ENODEV;
> -    }
> -    tcmsg->tcm_parent = tc_make_handle(0xffff, 0);
> -    tcmsg->tcm_info = tc_make_handle(49,
> -                                     (OVS_FORCE uint16_t) htons(ETH_P_ALL));
> -    nl_msg_put_string(&request, TCA_KIND, "basic");
> -    basic_offset = nl_msg_start_nested(&request, TCA_OPTIONS);
> -    police_offset = nl_msg_start_nested(&request, TCA_BASIC_ACT);
> -    nl_msg_put_act_police(&request, tc_police, kpkts_rate, kpkts_burst);
> -    nl_msg_end_nested(&request, police_offset);
> -    nl_msg_end_nested(&request, basic_offset);
> -
> -    error = tc_transact(&request, NULL);
> -    if (error) {
> -        return error;
> -    }
> -
> -    return 0;
> -}
> -
>  static void
>  read_psched(void)
>  {
> diff --git a/tests/ovs-vsctl.at b/tests/ovs-vsctl.at
> index d6cd2c084..193bfc5c7 100644
> --- a/tests/ovs-vsctl.at
> +++ b/tests/ovs-vsctl.at
> @@ -1670,22 +1670,22 @@ AT_BANNER([set ingress policing test])
>
>  AT_SETUP([set ingress_policing_rate and ingress_policing_burst])
>  AT_KEYWORDS([ingress_policing])
> -OVS_VSCTL_SETUP
> +AT_CHECK([ip link add a1 type veth])
> +AT_CHECK([ip link set a1 up])
> +on_exit 'ip link del a1'
> +OVS_VSWITCHD_START([add-port br0 a1])
>  AT_CHECK([RUN_OVS_VSCTL_TOGETHER(
> -   [add-br a],
> -   [add-port a a1],
>     [set interface a1 ingress_policing_rate=100],
>     [set interface a1 ingress_policing_burst=10],
>     [--columns=ingress_policing_burst,ingress_policing_rate list interface a1])],
>     [0],
>     [

If you clean this up, maybe also use p1 for port instead of a1.

> -
> -

Did the output change so you needed to delete these empty lines?

>  ingress_policing_burst: 10
>  ingress_policing_rate: 100
>  ])
> -OVS_VSCTL_CLEANUP
> +AT_CHECK([grep "adding policing action failed" ovs-vswitchd.log], [1], [], [])

Don’t think this is needed? If it’s an WARN or up message is in the log OVS_VSWITCHD_STOP would fail.


Also in general not sure if this is the right place for the change, i.e. these are test cases for ovs-vsctl which are platform-independent, so adding Linux-specific ip commands/ports might not be the right thing to do here.
However, I think the “AT_SETUP([offloads - set ingress_policing_kpkts_rate and ingress_policing_kpkts_burst - offloads disabled])” already tests this case.

> +OVS_VSWITCHD_STOP
>  AT_CLEANUP
>
>  dnl ----------------------------------------------------------------------
> @@ -1693,20 +1693,20 @@ AT_BANNER([set ingress policing(kpkts) test])
>
>  AT_SETUP([set ingress_policing_kpkts_rate and ingress_policing_kpkts_burst])
>  AT_KEYWORDS([ingress_policing_kpkts])
> -OVS_VSCTL_SETUP
> +AT_CHECK([ip link add a1 type veth])
> +AT_CHECK([ip link set a1 up])
> +on_exit 'ip link del a1'
> +OVS_VSWITCHD_START([add-port br0 a1])
>  AT_CHECK([RUN_OVS_VSCTL_TOGETHER(
> -   [add-br a],
> -   [add-port a a1],
>     [set interface a1 ingress_policing_kpkts_rate=100],
>     [set interface a1 ingress_policing_kpkts_burst=10],
>     [--columns=ingress_policing_kpkts_burst,ingress_policing_kpkts_rate list interface a1])],
>     [0],
>     [
>
> -
> -
>  ingress_policing_kpkts_burst: 10
>  ingress_policing_kpkts_rate: 100
>  ])
> -OVS_VSCTL_CLEANUP
> +AT_CHECK([grep "adding policing action failed" ovs-vswitchd.log], [1], [], [])
> +OVS_VSWITCHD_STOP
>  AT_CLEANUP
> -- 
> 2.31.1
>
>
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
Ilya Maximets Oct. 15, 2021, 11:41 a.m. UTC | #2
On 10/14/21 21:44, Michael Pattrick wrote:
> Currently ingress policing uses the basic classifier to apply traffic
> control filters.

Hi, Michael.  Thanks for submitting a patch!
I'm not going to review technical details of implementation, I'll leave
this to Simon and others, but I want to make a few high level comments.

First, please increase the version number for a patch while sending new
versions, this can be done by adding --subject-prefix='PATCH v2' or simply
-v2 to the list of 'git format-patch' arguments.  Otherwise it's confusing
for reviewers and any automated patch tracking systems we have.

And the patch name should start with 'netdev-linux:', not 'vswitchd:', as
'vswitchd' is way too broad area, and this patch is only really touching
netdev-linux part.

More comments below.

> 
> However, cls_basic was removed from the upcoming RHEL9.

This itself doesn't sound like a correct justification, as RHEL is not
the only distribution in a world.  Does other distributions getting rid
of cls_basic too or was it deprecated in upstream linux kernel?

> Basic is probably
> not the proper classifier to use when the more accurage matchall

What does "not the proper classifier" mean?  I think, the difference
between classifiers should be better described in a commit message.

> classifier is available and already in use in the code base. Switching
> from basic to matchall allows us to remove a function.

Even though 'matchall' is used in a codebase, it's used only if HW offloading
is enabled.  HW offloading itself is a relatively high requirement, because
it requires more recent kernel versions in most cases.  'matchall' is
available starting from kernel v4.8, while 'basic' goes back to 2.16.12.
It's fair to expect that users of HW offloading will use more recent kernel
than 4.8.  However, 4.4 is still a supported longterm kernel version and
switching to 'matchall' for everyone means dropping support for policing
in OVS for currently supported upstream kernels older than 4.8.
Can we detect the support of 'matchall' and fall back if not available?

Not sure how important this is, but that is something that definitely
needs to be discussed and documented.

> 
> I've also modified tests to detect when ingress policing fails to apply.
> 
> Signed-off-by: Michael Pattrick <mkp@redhat.com>
> ---
>  lib/netdev-linux.c | 85 +++++++++-------------------------------------
>  tests/ovs-vsctl.at | 24 ++++++-------
>  2 files changed, 28 insertions(+), 81 deletions(-)
> 

<snip>

> diff --git a/tests/ovs-vsctl.at b/tests/ovs-vsctl.at
> index d6cd2c084..193bfc5c7 100644
> --- a/tests/ovs-vsctl.at
> +++ b/tests/ovs-vsctl.at
> @@ -1670,22 +1670,22 @@ AT_BANNER([set ingress policing test])
>  
>  AT_SETUP([set ingress_policing_rate and ingress_policing_burst])
>  AT_KEYWORDS([ingress_policing])
> -OVS_VSCTL_SETUP
> +AT_CHECK([ip link add a1 type veth])
> +AT_CHECK([ip link set a1 up])
> +on_exit 'ip link del a1'

These tests are part of "unit" tests.  They should not touch system
interfaces, hence no 'ip' commands should be here.  Also, these tests
should be platform-independent, e.g. they should run on Windows and
DSB systems too.  Moreover, these tests are most of the time not started
from a root user, so they will just fail.  And they do fail all our CI
runs because of that, you can see in the ovsrobot's reports on a patchwork:
  https://patchwork.ozlabs.org/project/openvswitch/patch/160bc3cabaf546fb15bb5172b49c5956f6f1e744.camel@redhat.com/

Another thing is that you're not changing tests/system-offload-traffic.at.
So these tests will fail as they look for configured 'basic' policer.
You may run these tests with 'make check-offloads'.

Best regards, Ilya Maximets.
diff mbox series

Patch

diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index 97bd21be4..d64b88512 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -486,10 +486,6 @@  static struct tcmsg *netdev_linux_tc_make_request(const struct netdev *,
                                                   unsigned int flags,
                                                   struct ofpbuf *);
 
-static int tc_add_policer(struct netdev *, uint32_t kbits_rate,
-                          uint32_t kbits_burst, uint32_t kpkts_rate,
-                          uint32_t kpkts_burst);
-
 static int tc_parse_qdisc(const struct ofpbuf *, const char **kind,
                           struct nlattr **options);
 static int tc_parse_class(const struct ofpbuf *, unsigned int *queue_id,
@@ -2662,6 +2658,20 @@  nl_msg_put_act_police(struct ofpbuf *request, struct tc_police police,
     }
 }
 
+/* Adds a policer to 'netdev' with a rate of 'kbits_rate' and a burst size
+ * of 'kbits_burst', with a rate of 'kpkts_rate' and a burst size of
+ * 'kpkts_burst'.
+ *
+ * This function is equivalent to running:
+ *     /sbin/tc filter add dev <devname> parent ffff: protocol all prio 49
+ *              matchall police rate <kbits_rate>kbit burst <kbits_burst>k
+ *              mtu 65535 drop
+ *
+ * The configuration and stats may be seen with the following command:
+ *     /sbin/tc -s filter show dev <devname> parent ffff:
+ *
+ * Returns 0 if successful, otherwise a positive errno value.
+ */
 static int
 tc_add_matchall_policer(struct netdev *netdev, uint32_t kbits_rate,
                         uint32_t kbits_burst, uint32_t kpkts_rate,
@@ -2801,8 +2811,8 @@  netdev_linux_set_policing(struct netdev *netdev_, uint32_t kbits_rate,
             goto out;
         }
 
-        error = tc_add_policer(netdev_, kbits_rate, kbits_burst,
-                               kpkts_rate, kpkts_burst);
+        error = tc_add_matchall_policer(netdev_, kbits_rate, kbits_burst,
+                                        kpkts_rate, kpkts_burst);
         if (error){
             VLOG_WARN_RL(&rl, "%s: adding policing action failed: %s",
                     netdev_name, ovs_strerror(error));
@@ -5589,69 +5599,6 @@  netdev_linux_tc_make_request(const struct netdev *netdev, int type,
     return tc_make_request(ifindex, type, flags, request);
 }
 
-/* Adds a policer to 'netdev' with a rate of 'kbits_rate' and a burst size
- * of 'kbits_burst', with a rate of 'kpkts_rate' and a burst size of
- * 'kpkts_burst'.
- *
- * This function is equivalent to running:
- *     /sbin/tc filter add dev <devname> parent ffff: protocol all prio 49
- *              basic police rate <kbits_rate>kbit burst <kbits_burst>k
- *              mtu 65535 drop
- *
- * The configuration and stats may be seen with the following command:
- *     /sbin/tc -s filter show dev <devname> parent ffff:
- *
- * Returns 0 if successful, otherwise a positive errno value.
- */
-static int
-tc_add_policer(struct netdev *netdev, uint32_t kbits_rate,
-               uint32_t kbits_burst, uint32_t kpkts_rate,
-               uint32_t kpkts_burst)
-{
-    size_t basic_offset, police_offset;
-    struct tc_police tc_police;
-    struct ofpbuf request;
-    struct tcmsg *tcmsg;
-    int error;
-    int mtu = 65535;
-
-    memset(&tc_police, 0, sizeof tc_police);
-    tc_police.action = TC_POLICE_SHOT;
-    tc_police.mtu = mtu;
-    tc_fill_rate(&tc_police.rate, ((uint64_t) kbits_rate * 1000)/8, mtu);
-
-    /* The following appears wrong in one way: In networking a kilobit is
-     * usually 1000 bits but this uses 1024 bits.
-     *
-     * However if you "fix" those problems then "tc filter show ..." shows
-     * "125000b", meaning 125,000 bits, when OVS configures it for 1000 kbit ==
-     * 1,000,000 bits, whereas this actually ends up doing the right thing from
-     * tc's point of view.  Whatever. */
-    tc_police.burst = tc_bytes_to_ticks(
-        tc_police.rate.rate, MIN(UINT32_MAX / 1024, kbits_burst) * 1024 / 8);
-    tcmsg = netdev_linux_tc_make_request(netdev, RTM_NEWTFILTER,
-                                         NLM_F_EXCL | NLM_F_CREATE, &request);
-    if (!tcmsg) {
-        return ENODEV;
-    }
-    tcmsg->tcm_parent = tc_make_handle(0xffff, 0);
-    tcmsg->tcm_info = tc_make_handle(49,
-                                     (OVS_FORCE uint16_t) htons(ETH_P_ALL));
-    nl_msg_put_string(&request, TCA_KIND, "basic");
-    basic_offset = nl_msg_start_nested(&request, TCA_OPTIONS);
-    police_offset = nl_msg_start_nested(&request, TCA_BASIC_ACT);
-    nl_msg_put_act_police(&request, tc_police, kpkts_rate, kpkts_burst);
-    nl_msg_end_nested(&request, police_offset);
-    nl_msg_end_nested(&request, basic_offset);
-
-    error = tc_transact(&request, NULL);
-    if (error) {
-        return error;
-    }
-
-    return 0;
-}
-
 static void
 read_psched(void)
 {
diff --git a/tests/ovs-vsctl.at b/tests/ovs-vsctl.at
index d6cd2c084..193bfc5c7 100644
--- a/tests/ovs-vsctl.at
+++ b/tests/ovs-vsctl.at
@@ -1670,22 +1670,22 @@  AT_BANNER([set ingress policing test])
 
 AT_SETUP([set ingress_policing_rate and ingress_policing_burst])
 AT_KEYWORDS([ingress_policing])
-OVS_VSCTL_SETUP
+AT_CHECK([ip link add a1 type veth])
+AT_CHECK([ip link set a1 up])
+on_exit 'ip link del a1'
+OVS_VSWITCHD_START([add-port br0 a1])
 AT_CHECK([RUN_OVS_VSCTL_TOGETHER(
-   [add-br a],
-   [add-port a a1],
    [set interface a1 ingress_policing_rate=100],
    [set interface a1 ingress_policing_burst=10],
    [--columns=ingress_policing_burst,ingress_policing_rate list interface a1])],
    [0],
    [
 
-
-
 ingress_policing_burst: 10
 ingress_policing_rate: 100
 ])
-OVS_VSCTL_CLEANUP
+AT_CHECK([grep "adding policing action failed" ovs-vswitchd.log], [1], [], [])
+OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 dnl ----------------------------------------------------------------------
@@ -1693,20 +1693,20 @@  AT_BANNER([set ingress policing(kpkts) test])
 
 AT_SETUP([set ingress_policing_kpkts_rate and ingress_policing_kpkts_burst])
 AT_KEYWORDS([ingress_policing_kpkts])
-OVS_VSCTL_SETUP
+AT_CHECK([ip link add a1 type veth])
+AT_CHECK([ip link set a1 up])
+on_exit 'ip link del a1'
+OVS_VSWITCHD_START([add-port br0 a1])
 AT_CHECK([RUN_OVS_VSCTL_TOGETHER(
-   [add-br a],
-   [add-port a a1],
    [set interface a1 ingress_policing_kpkts_rate=100],
    [set interface a1 ingress_policing_kpkts_burst=10],
    [--columns=ingress_policing_kpkts_burst,ingress_policing_kpkts_rate list interface a1])],
    [0],
    [
 
-
-
 ingress_policing_kpkts_burst: 10
 ingress_policing_kpkts_rate: 100
 ])
-OVS_VSCTL_CLEANUP
+AT_CHECK([grep "adding policing action failed" ovs-vswitchd.log], [1], [], [])
+OVS_VSWITCHD_STOP
 AT_CLEANUP