diff mbox series

[ovs-dev,v2] ovn-northd: Don't commit to conntrack if the conntrack was skipped.

Message ID 20220310194243.2624700-1-numans@ovn.org
State Deferred
Headers show
Series [ovs-dev,v2] ovn-northd: Don't commit to conntrack if the conntrack was skipped. | expand

Checks

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

Commit Message

Numan Siddique March 10, 2022, 7:42 p.m. UTC
From: Numan Siddique <numans@ovn.org>

Presently, if the inport or outport is a peer port (of router port),
then we skip sending the packet to conntrack by not setting the
reg0[0]/reg0[1] bits.  But the packet still goes through the
stages - ls_in_acl_hint, ls_in_acl and ls_in_stateful in the ingress
pipeline and similarly ls_out_acl_hint, ls_out_acl and ls_out_stateful
in the egress pipeline of the logical switch.

In these mentioned stages, the logical flows match on the ct states
(ct.new, ct.est etc) and this can be problematic if the packet was
sent to conntrack and committed in the ingress pipeline.  When
that packet enters the egress pipeline with outport set to the peer
port,  we skip sending the packet to conntrack (which is expected)
but ct state values carry over from the ingress state.  If the ct.new
flag was set in the ingress pipeline, then the below flows are hit and
the packet gets committed in the conntrack zone of the inport logical port.

table=4 (ls_out_acl         ), priority=1    ,
         match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))),
         action=(reg0[1] = 1; next;)
table=7 (ls_out_stateful    ), priority=100  ,
         match=(reg0[1] == 1 && reg0[13] == 0),
         action=(ct_commit { ct_label.blocked = 0; }; next;)

With this extra commit to the same conntrack zone, sometimes the packet gets
dropped or doesn't reach the destination.  It is not very clear how
the packet gets misplaced, but avoiding this resolves the issue.
And OVN ideally should not do this extra commit.

This patch addresses this issue by adding the below logical flow
both in ls_in_acl and ls_out_acl stage

priority=2    , match=(reg0[0] == 0 && reg0[1] == 0), action=(next;)

Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2060688
Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2062431
Reported-by: Michael Washer <mwasher@redhat.com>
Signed-off-by: Numan Siddique <numans@ovn.org>
---

v1 -> v2
-------
  * Changed the approach to solve the issue.

 northd/northd.c         | 17 +++++++++++++++--
 northd/ovn-northd.8.xml |  6 ++++++
 tests/ovn-northd.at     |  5 +++++
 3 files changed, 26 insertions(+), 2 deletions(-)

Comments

Numan Siddique March 22, 2022, 6:17 p.m. UTC | #1
On Thu, Mar 10, 2022 at 2:42 PM <numans@ovn.org> wrote:

> From: Numan Siddique <numans@ovn.org>
>
> Presently, if the inport or outport is a peer port (of router port),
> then we skip sending the packet to conntrack by not setting the
> reg0[0]/reg0[1] bits.  But the packet still goes through the
> stages - ls_in_acl_hint, ls_in_acl and ls_in_stateful in the ingress
> pipeline and similarly ls_out_acl_hint, ls_out_acl and ls_out_stateful
> in the egress pipeline of the logical switch.
>
> In these mentioned stages, the logical flows match on the ct states
> (ct.new, ct.est etc) and this can be problematic if the packet was
> sent to conntrack and committed in the ingress pipeline.  When
> that packet enters the egress pipeline with outport set to the peer
> port,  we skip sending the packet to conntrack (which is expected)
> but ct state values carry over from the ingress state.  If the ct.new
> flag was set in the ingress pipeline, then the below flows are hit and
> the packet gets committed in the conntrack zone of the inport logical port.
>
> table=4 (ls_out_acl         ), priority=1    ,
>          match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))),
>          action=(reg0[1] = 1; next;)
> table=7 (ls_out_stateful    ), priority=100  ,
>          match=(reg0[1] == 1 && reg0[13] == 0),
>          action=(ct_commit { ct_label.blocked = 0; }; next;)
>
> With this extra commit to the same conntrack zone, sometimes the packet
> gets
> dropped or doesn't reach the destination.  It is not very clear how
> the packet gets misplaced, but avoiding this resolves the issue.
> And OVN ideally should not do this extra commit.
>
> This patch addresses this issue by adding the below logical flow
> both in ls_in_acl and ls_out_acl stage
>
> priority=2    , match=(reg0[0] == 0 && reg0[1] == 0), action=(next;)
>
> Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2060688
> Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2062431
> Reported-by: Michael Washer <mwasher@redhat.com>
> Signed-off-by: Numan Siddique <numans@ovn.org>
>

ovn-k8s tests are failing with this patch in the github CI.

So please ignore this patch.  I'll submit v3 addressing the test failures.

Numan


> ---
>
> v1 -> v2
> -------
>   * Changed the approach to solve the issue.
>
>  northd/northd.c         | 17 +++++++++++++++--
>  northd/ovn-northd.8.xml |  6 ++++++
>  tests/ovn-northd.at     |  5 +++++
>  3 files changed, 26 insertions(+), 2 deletions(-)
>
> diff --git a/northd/northd.c b/northd/northd.c
> index b264fb850b..23ab5ac260 100644
> --- a/northd/northd.c
> +++ b/northd/northd.c
> @@ -6529,7 +6529,7 @@ build_acls(struct ovn_datapath *od, struct hmap
> *lflows,
>      ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, 0, "1", "next;");
>
>      if (has_stateful) {
> -        /* Ingress and Egress ACL Table (Priority 1).
> +        /* Ingress and Egress ACL Table (Priority 1 and 2).
>           *
>           * By default, traffic is allowed.  This is partially handled by
>           * the Priority 0 ACL flows added earlier, but we also need to
> @@ -6549,7 +6549,20 @@ build_acls(struct ovn_datapath *od, struct hmap
> *lflows,
>           * We need to set ct_label.blocked=0 to let the connection
> continue,
>           * which will be done by ct_commit() in the "stateful" stage.
>           * Subsequent packets will hit the flow at priority 0 that just
> -         * uses "next;". */
> +         * uses "next;".
> +         *
> +         * However, we don't want to commit if the packet was not sent to
> +         * conntrack in the first place.
> +         * Eg. if inport or outport is a router peer port. */
> +        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 2,
> +                      REGBIT_CONNTRACK_DEFRAG" == 0 && "
> +                      REGBIT_CONNTRACK_NAT" == 0",
> +                      "next;");
> +        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 2,
> +                      REGBIT_CONNTRACK_DEFRAG" == 0 && "
> +                      REGBIT_CONNTRACK_NAT" == 0",
> +                      "next;");
> +
>          ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 1,
>                        "ip && (!ct.est || (ct.est && ct_label.blocked ==
> 1))",
>                         REGBIT_CONNTRACK_COMMIT" = 1; next;");
> diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
> index 4784bff041..d788efe70b 100644
> --- a/northd/ovn-northd.8.xml
> +++ b/northd/ovn-northd.8.xml
> @@ -784,6 +784,12 @@
>      </p>
>
>      <ul>
> +      <li>
> +        A priority-2 flow that advances the packet to the next stage if
> the
> +        packet was not sent to conntrack earlier, by matching on
> +        <code>reg0[0] == 0 &amp;&amp; reg0[1] == 1</code>.
> +      </li>
> +
>        <li>
>          A priority-1 flow that sets the hint to commit IP traffic to the
>          connection tracker (with action <code>reg0[1] = 1;
> next;</code>).  This
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> index 60d91a7717..bfd0f2382b 100644
> --- a/tests/ovn-northd.at
> +++ b/tests/ovn-northd.at
> @@ -2265,6 +2265,7 @@ AT_CHECK([ovn-sbctl lflow-list ls | grep -e
> ls_in_acl_hint -e ls_out_acl_hint -e
>    table=4 (ls_out_acl         ), priority=1    , match=(ip && (!ct.est ||
> (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
>    table=4 (ls_out_acl         ), priority=1001 , match=(reg0[[7]] == 1 &&
> (ip)), action=(reg0[[1]] = 1; next;)
>    table=4 (ls_out_acl         ), priority=1001 , match=(reg0[[8]] == 1 &&
> (ip)), action=(next;)
> +  table=4 (ls_out_acl         ), priority=2    , match=(reg0[[0]] == 0 &&
> reg0[[2]] == 0), action=(next;)
>    table=4 (ls_out_acl         ), priority=34000, match=(eth.src ==
> $svc_monitor_mac), action=(next;)
>    table=4 (ls_out_acl         ), priority=65532, match=(!ct.est && ct.rel
> && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
>    table=4 (ls_out_acl         ), priority=65532, match=(ct.est && !ct.rel
> && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;)
> @@ -2282,6 +2283,7 @@ AT_CHECK([ovn-sbctl lflow-list ls | grep -e
> ls_in_acl_hint -e ls_out_acl_hint -e
>    table=9 (ls_in_acl          ), priority=1    , match=(ip && (!ct.est ||
> (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
>    table=9 (ls_in_acl          ), priority=1001 , match=(reg0[[7]] == 1 &&
> (ip)), action=(reg0[[1]] = 1; next;)
>    table=9 (ls_in_acl          ), priority=1001 , match=(reg0[[8]] == 1 &&
> (ip)), action=(next;)
> +  table=9 (ls_in_acl          ), priority=2    , match=(reg0[[0]] == 0 &&
> reg0[[2]] == 0), action=(next;)
>    table=9 (ls_in_acl          ), priority=34000, match=(eth.dst ==
> $svc_monitor_mac), action=(next;)
>    table=9 (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel
> && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
>    table=9 (ls_in_acl          ), priority=65532, match=(ct.est && !ct.rel
> && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0),
> action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
> @@ -6328,6 +6330,7 @@ AT_CAPTURE_FILE([lsflows])
>  AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' |
> sort], [0], [dnl
>    table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
>    table=??(ls_in_acl          ), priority=1    , match=(ip && (!ct.est ||
> (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl          ), priority=2    , match=(reg0[[0]] == 0 &&
> reg0[[2]] == 0), action=(next;)
>    table=??(ls_in_acl          ), priority=2001 , match=(reg0[[10]] == 1
> && (ip4)), action=(ct_commit { ct_label.blocked = 1; }; /* drop */)
>    table=??(ls_in_acl          ), priority=2001 , match=(reg0[[9]] == 1 &&
> (ip4)), action=(/* drop */)
>    table=??(ls_in_acl          ), priority=2002 , match=(reg0[[7]] == 1 &&
> (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
> @@ -6380,6 +6383,7 @@ AT_CAPTURE_FILE([lsflows])
>  AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' |
> sort], [0], [dnl
>    table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
>    table=??(ls_in_acl          ), priority=1    , match=(ip && (!ct.est ||
> (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl          ), priority=2    , match=(reg0[[0]] == 0 &&
> reg0[[2]] == 0), action=(next;)
>    table=??(ls_in_acl          ), priority=34000, match=(eth.dst ==
> $svc_monitor_mac), action=(next;)
>    table=??(ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel
> && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
>    table=??(ls_in_acl          ), priority=65532, match=(ct.est && !ct.rel
> && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0),
> action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
> @@ -6432,6 +6436,7 @@ AT_CAPTURE_FILE([lsflows])
>  AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' |
> sort], [0], [dnl
>    table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
>    table=??(ls_in_acl          ), priority=1    , match=(ip && (!ct.est ||
> (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
> +  table=??(ls_in_acl          ), priority=2    , match=(reg0[[0]] == 0 &&
> reg0[[2]] == 0), action=(next;)
>    table=??(ls_in_acl          ), priority=2002 , match=(reg0[[7]] == 1 &&
> (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
>    table=??(ls_in_acl          ), priority=2002 , match=(reg0[[8]] == 1 &&
> (ip4 && tcp)), action=(next;)
>    table=??(ls_in_acl          ), priority=2003 , match=(reg0[[7]] == 1 &&
> (ip4 && icmp)), action=(reg0[[1]] = 1; next;)
> --
> 2.34.1
>
>
diff mbox series

Patch

diff --git a/northd/northd.c b/northd/northd.c
index b264fb850b..23ab5ac260 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -6529,7 +6529,7 @@  build_acls(struct ovn_datapath *od, struct hmap *lflows,
     ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, 0, "1", "next;");
 
     if (has_stateful) {
-        /* Ingress and Egress ACL Table (Priority 1).
+        /* Ingress and Egress ACL Table (Priority 1 and 2).
          *
          * By default, traffic is allowed.  This is partially handled by
          * the Priority 0 ACL flows added earlier, but we also need to
@@ -6549,7 +6549,20 @@  build_acls(struct ovn_datapath *od, struct hmap *lflows,
          * We need to set ct_label.blocked=0 to let the connection continue,
          * which will be done by ct_commit() in the "stateful" stage.
          * Subsequent packets will hit the flow at priority 0 that just
-         * uses "next;". */
+         * uses "next;".
+         *
+         * However, we don't want to commit if the packet was not sent to
+         * conntrack in the first place.
+         * Eg. if inport or outport is a router peer port. */
+        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 2,
+                      REGBIT_CONNTRACK_DEFRAG" == 0 && "
+                      REGBIT_CONNTRACK_NAT" == 0",
+                      "next;");
+        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 2,
+                      REGBIT_CONNTRACK_DEFRAG" == 0 && "
+                      REGBIT_CONNTRACK_NAT" == 0",
+                      "next;");
+
         ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 1,
                       "ip && (!ct.est || (ct.est && ct_label.blocked == 1))",
                        REGBIT_CONNTRACK_COMMIT" = 1; next;");
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index 4784bff041..d788efe70b 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -784,6 +784,12 @@ 
     </p>
 
     <ul>
+      <li>
+        A priority-2 flow that advances the packet to the next stage if the
+        packet was not sent to conntrack earlier, by matching on
+        <code>reg0[0] == 0 &amp;&amp; reg0[1] == 1</code>.
+      </li>
+
       <li>
         A priority-1 flow that sets the hint to commit IP traffic to the
         connection tracker (with action <code>reg0[1] = 1; next;</code>).  This
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index 60d91a7717..bfd0f2382b 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -2265,6 +2265,7 @@  AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e
   table=4 (ls_out_acl         ), priority=1    , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
   table=4 (ls_out_acl         ), priority=1001 , match=(reg0[[7]] == 1 && (ip)), action=(reg0[[1]] = 1; next;)
   table=4 (ls_out_acl         ), priority=1001 , match=(reg0[[8]] == 1 && (ip)), action=(next;)
+  table=4 (ls_out_acl         ), priority=2    , match=(reg0[[0]] == 0 && reg0[[2]] == 0), action=(next;)
   table=4 (ls_out_acl         ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
   table=4 (ls_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
   table=4 (ls_out_acl         ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;)
@@ -2282,6 +2283,7 @@  AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e
   table=9 (ls_in_acl          ), priority=1    , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
   table=9 (ls_in_acl          ), priority=1001 , match=(reg0[[7]] == 1 && (ip)), action=(reg0[[1]] = 1; next;)
   table=9 (ls_in_acl          ), priority=1001 , match=(reg0[[8]] == 1 && (ip)), action=(next;)
+  table=9 (ls_in_acl          ), priority=2    , match=(reg0[[0]] == 0 && reg0[[2]] == 0), action=(next;)
   table=9 (ls_in_acl          ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
   table=9 (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
   table=9 (ls_in_acl          ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
@@ -6328,6 +6330,7 @@  AT_CAPTURE_FILE([lsflows])
 AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
   table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl          ), priority=1    , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
+  table=??(ls_in_acl          ), priority=2    , match=(reg0[[0]] == 0 && reg0[[2]] == 0), action=(next;)
   table=??(ls_in_acl          ), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(ct_commit { ct_label.blocked = 1; }; /* drop */)
   table=??(ls_in_acl          ), priority=2001 , match=(reg0[[9]] == 1 && (ip4)), action=(/* drop */)
   table=??(ls_in_acl          ), priority=2002 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
@@ -6380,6 +6383,7 @@  AT_CAPTURE_FILE([lsflows])
 AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
   table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl          ), priority=1    , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
+  table=??(ls_in_acl          ), priority=2    , match=(reg0[[0]] == 0 && reg0[[2]] == 0), action=(next;)
   table=??(ls_in_acl          ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
   table=??(ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
   table=??(ls_in_acl          ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
@@ -6432,6 +6436,7 @@  AT_CAPTURE_FILE([lsflows])
 AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
   table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl          ), priority=1    , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
+  table=??(ls_in_acl          ), priority=2    , match=(reg0[[0]] == 0 && reg0[[2]] == 0), action=(next;)
   table=??(ls_in_acl          ), priority=2002 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
   table=??(ls_in_acl          ), priority=2002 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(next;)
   table=??(ls_in_acl          ), priority=2003 , match=(reg0[[7]] == 1 && (ip4 && icmp)), action=(reg0[[1]] = 1; next;)