Skip to content

Commit

Permalink
northd: rely on new actions for ecmp-symmetric routing
Browse files Browse the repository at this point in the history
Rely on the following new actions for ecmp-symmetric routing:
- chk_ecmp_nh_mac
- chk_ecmp_nh
- commit_ecmp_nh

In this way OVN is able to keep up if for any reason the ECMP traffic
source changes L2 address and keeps old L3 addresses.

Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2096233
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
Signed-off-by: Mark Michelson <mmichels@redhat.com>
Acked-by: Mark Michelson <mmichels@redhat.com>
  • Loading branch information
LorenzoBianconi authored and putnopvut committed Aug 19, 2022
1 parent be4f46c commit 506f7d4
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 37 deletions.
102 changes: 91 additions & 11 deletions northd/northd.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ enum ovn_stage {
#define REGBIT_LOOKUP_NEIGHBOR_RESULT "reg9[2]"
#define REGBIT_LOOKUP_NEIGHBOR_IP_RESULT "reg9[3]"
#define REGBIT_DST_NAT_IP_LOCAL "reg9[4]"
#define REGBIT_KNOWN_ECMP_NH "reg9[5]"

/* Register to store the eth address associated to a router port for packets
* received in S_ROUTER_IN_ADMISSION.
Expand Down Expand Up @@ -327,7 +328,8 @@ enum ovn_stage {
* | | EGRESS_LOOPBACK/ | G | UNUSED |
* | R9 | PKT_LARGER/ | 4 | |
* | | LOOKUP_NEIGHBOR_RESULT/| | |
* | | SKIP_LOOKUP_NEIGHBOR} | | |
* | | SKIP_LOOKUP_NEIGHBOR/ | | |
* | | KNOWN_ECMP_NH} | | |
* | | | | |
* | | REG_ORIG_TP_DPORT_ROUTER | | |
* | | | | |
Expand Down Expand Up @@ -9413,6 +9415,7 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows,
struct ds *route_match)
{
const struct nbrec_logical_router_static_route *st_route = route->route;
struct ds base_match = DS_EMPTY_INITIALIZER;
struct ds match = DS_EMPTY_INITIALIZER;
struct ds actions = DS_EMPTY_INITIALIZER;
struct ds ecmp_reply = DS_EMPTY_INITIALIZER;
Expand All @@ -9424,40 +9427,116 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows,
/* If symmetric ECMP replies are enabled, then packets that arrive over
* an ECMP route need to go through conntrack.
*/
ds_put_format(&match, "inport == %s && ip%s.%s == %s",
ds_put_format(&base_match, "inport == %s && ip%s.%s == %s",
out_port->json_key,
IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "4" : "6",
route->is_src_route ? "dst" : "src",
cidr);
free(cidr);
ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DEFRAG, 100,
ds_cstr(&match), "ct_next;",
&st_route->header_);
ds_cstr(&base_match),
REGBIT_KNOWN_ECMP_NH" = chk_ecmp_nh_mac(); ct_next;",
&st_route->header_);

/* And packets that go out over an ECMP route need conntrack */
ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DEFRAG, 100,
ds_cstr(route_match), "ct_next;",
&st_route->header_);
ds_cstr(route_match),
REGBIT_KNOWN_ECMP_NH" = chk_ecmp_nh(); ct_next;",
&st_route->header_);

/* Save src eth and inport in ct_label for packets that arrive over
* an ECMP route.
*
* NOTE: we purposely are not clearing match before this
* ds_put_cstr() call. The previous contents are needed.
*/
ds_put_cstr(&match, " && (ct.new && !ct.est)");
ds_put_format(&match, "%s && (ct.new && !ct.est) && tcp",
ds_cstr(&base_match));
ds_put_format(&actions,
"ct_commit { ct_label.ecmp_reply_eth = eth.src; "
" %s = %" PRId64 ";}; "
"commit_ecmp_nh(ipv6 = %s, proto = tcp); next;",
ct_ecmp_reply_port_match, out_port->sb->tunnel_key,
IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "false" : "true");
ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
ds_cstr(&match), ds_cstr(&actions),
&st_route->header_);
ds_clear(&match);
ds_put_format(&match, "%s && (ct.new && !ct.est) && udp",
ds_cstr(&base_match));
ds_clear(&actions);
ds_put_format(&actions,
"ct_commit { ct_label.ecmp_reply_eth = eth.src; "
" %s = %" PRId64 ";}; "
"commit_ecmp_nh(ipv6 = %s, proto = udp); next;",
ct_ecmp_reply_port_match, out_port->sb->tunnel_key,
IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "false" : "true");
ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
ds_cstr(&match), ds_cstr(&actions),
&st_route->header_);
ds_clear(&match);
ds_put_format(&match, "%s && (ct.new && !ct.est) && sctp",
ds_cstr(&base_match));
ds_clear(&actions);
ds_put_format(&actions,
"ct_commit { ct_label.ecmp_reply_eth = eth.src; "
" %s = %" PRId64 ";}; "
"commit_ecmp_nh(ipv6 = %s, proto = sctp); next;",
ct_ecmp_reply_port_match, out_port->sb->tunnel_key,
IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "false" : "true");
ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
ds_cstr(&match), ds_cstr(&actions),
&st_route->header_);

ds_put_format(&actions, "ct_commit { ct_label.ecmp_reply_eth = eth.src;"
" %s = %" PRId64 ";}; next;",
ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
ds_clear(&match);
ds_put_format(&match,
"%s && (!ct.rpl && ct.est) && tcp && "REGBIT_KNOWN_ECMP_NH" == 0",
ds_cstr(&base_match));
ds_clear(&actions);
ds_put_format(&actions,
"ct_commit { ct_label.ecmp_reply_eth = eth.src; "
" %s = %" PRId64 ";}; "
"commit_ecmp_nh(ipv6 = %s, proto = tcp); next;",
ct_ecmp_reply_port_match, out_port->sb->tunnel_key,
IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "false" : "true");
ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
ds_cstr(&match), ds_cstr(&actions),
&st_route->header_);

ds_clear(&match);
ds_put_format(&match,
"%s && (!ct.rpl && ct.est) && udp && "REGBIT_KNOWN_ECMP_NH" == 0",
ds_cstr(&base_match));
ds_clear(&actions);
ds_put_format(&actions,
"ct_commit { ct_label.ecmp_reply_eth = eth.src; "
" %s = %" PRId64 ";}; "
"commit_ecmp_nh(ipv6 = %s, proto = udp); next;",
ct_ecmp_reply_port_match, out_port->sb->tunnel_key,
IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "false" : "true");
ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
ds_cstr(&match), ds_cstr(&actions),
&st_route->header_);
ds_clear(&match);
ds_put_format(&match,
"%s && (!ct.rpl && ct.est) && sctp && "REGBIT_KNOWN_ECMP_NH" == 0",
ds_cstr(&base_match));
ds_clear(&actions);
ds_put_format(&actions,
"ct_commit { ct_label.ecmp_reply_eth = eth.src; "
" %s = %" PRId64 ";}; "
"commit_ecmp_nh(ipv6 = %s, proto = sctp); next;",
ct_ecmp_reply_port_match, out_port->sb->tunnel_key,
IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "false" : "true");
ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
ds_cstr(&match), ds_cstr(&actions),
&st_route->header_);

/* Bypass ECMP selection if we already have ct_label information
* for where to route the packet.
*/
ds_put_format(&ecmp_reply, "ct.rpl && %s == %"PRId64,
ds_put_format(&ecmp_reply,
"ct.rpl && "REGBIT_KNOWN_ECMP_NH" == 1 && %s == %"PRId64,
ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
ds_clear(&match);
ds_put_format(&match, "%s && %s", ds_cstr(&ecmp_reply),
Expand Down Expand Up @@ -9493,6 +9572,7 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows,
200, ds_cstr(&ecmp_reply),
action, &st_route->header_);

ds_destroy(&base_match);
ds_destroy(&match);
ds_destroy(&actions);
ds_destroy(&ecmp_reply);
Expand Down
24 changes: 14 additions & 10 deletions northd/ovn-northd.8.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3166,8 +3166,11 @@ icmp6 {
configured. The matching logic for these ports essentially reverses the
configured logic of the ECMP route. So for instance, a route with a
destination routing policy will instead match if the source IP address
matches the static route's prefix. The flow uses the action
<code>ct_next</code> to send IP packets to the connection tracker for
matches the static route's prefix. The flow uses the actions
<code>chk_ecmp_nh_mac(); ct_next</code> or
<code>chk_ecmp_nh(); ct_next</code> to send IP packets to table
<code>76</code> or to table <code>77</code> in order to check if source
info are already stored by OVN and then to the connection tracker for
packet de-fragmentation and tracking before sending it to the next table.
</p>

Expand Down Expand Up @@ -3426,10 +3429,11 @@ icmp6 {
route with a destination routing policy will instead match if the
source IP address matches the static route's prefix. The flow uses
the action <code>ct_commit { ct_label.ecmp_reply_eth = eth.src;"
" ct_mark.ecmp_reply_port = <var>K</var>;}; next; </code> to commit
the connection and storing <code>eth.src</code> and the ECMP
reply port binding tunnel key <var>K</var> in the
<code>ct_label</code>.
" ct_mark.ecmp_reply_port = <var>K</var>;}; commit_ecmp_nh(); next;
</code> to commit the connection and storing <code>eth.src</code> and
the ECMP reply port binding tunnel key <var>K</var> in the
<code>ct_label</code> and the traffic pattern to table
<code>76</code> or <code>77</code>.
</li>
</ul>

Expand Down Expand Up @@ -3568,10 +3572,10 @@ output;
which the packet should be sent. The <code>ct_mark.ecmp_reply_port</code>
tells the logical router port on which the packet should be sent. These
values saved to the conntrack fields when the initial ingress traffic is
received over the ECMP route and committed to conntrack. The
priority-10300 flows in this stage set the <code>outport</code>,
while the <code>eth.dst</code> is set by flows at the ARP/ND Resolution
stage.
received over the ECMP route and committed to conntrack.
If <code>REGBIT_KNOWN_ECMP_NH</code> is set, the priority-10300
flows in this stage set the <code>outport</code>, while the
<code>eth.dst</code> is set by flows at the ARP/ND Resolution stage.
</p>

<p>
Expand Down
18 changes: 16 additions & 2 deletions tests/ovn-northd.at
Original file line number Diff line number Diff line change
Expand Up @@ -5655,10 +5655,24 @@ AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed 's/192\.168\.0\..0/192.
table=??(lr_in_ip_routing_ecmp), priority=150 , match=(reg8[[0..15]] == 0), action=(next;)
])

AT_CHECK([grep -e "lr_in_ecmp_stateful".*commit_ecmp_nh lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl
table=??(lr_in_ecmp_stateful), priority=100 , match=(inport == "lr0-public" && ip4.src == 1.0.0.1 && (!ct.rpl && ct.est) && sctp && reg9[[5]] == 0), action=(ct_commit { ct_label.ecmp_reply_eth = eth.src; ct_label.ecmp_reply_port = 1;}; commit_ecmp_nh(ipv6 = false, proto = sctp); next;)
table=??(lr_in_ecmp_stateful), priority=100 , match=(inport == "lr0-public" && ip4.src == 1.0.0.1 && (!ct.rpl && ct.est) && tcp && reg9[[5]] == 0), action=(ct_commit { ct_label.ecmp_reply_eth = eth.src; ct_label.ecmp_reply_port = 1;}; commit_ecmp_nh(ipv6 = false, proto = tcp); next;)
table=??(lr_in_ecmp_stateful), priority=100 , match=(inport == "lr0-public" && ip4.src == 1.0.0.1 && (!ct.rpl && ct.est) && udp && reg9[[5]] == 0), action=(ct_commit { ct_label.ecmp_reply_eth = eth.src; ct_label.ecmp_reply_port = 1;}; commit_ecmp_nh(ipv6 = false, proto = udp); next;)
table=??(lr_in_ecmp_stateful), priority=100 , match=(inport == "lr0-public" && ip4.src == 1.0.0.1 && (ct.new && !ct.est) && sctp), action=(ct_commit { ct_label.ecmp_reply_eth = eth.src; ct_label.ecmp_reply_port = 1;}; commit_ecmp_nh(ipv6 = false, proto = sctp); next;)
table=??(lr_in_ecmp_stateful), priority=100 , match=(inport == "lr0-public" && ip4.src == 1.0.0.1 && (ct.new && !ct.est) && tcp), action=(ct_commit { ct_label.ecmp_reply_eth = eth.src; ct_label.ecmp_reply_port = 1;}; commit_ecmp_nh(ipv6 = false, proto = tcp); next;)
table=??(lr_in_ecmp_stateful), priority=100 , match=(inport == "lr0-public" && ip4.src == 1.0.0.1 && (ct.new && !ct.est) && udp), action=(ct_commit { ct_label.ecmp_reply_eth = eth.src; ct_label.ecmp_reply_port = 1;}; commit_ecmp_nh(ipv6 = false, proto = udp); next;)
])

AT_CHECK([grep -e "lr_in_defrag".*chk_ecmp_nh* lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl
table=??(lr_in_defrag ), priority=100 , match=(inport == "lr0-public" && ip4.src == 1.0.0.1), action=(reg9[[5]] = chk_ecmp_nh_mac(); ct_next;)
table=??(lr_in_defrag ), priority=100 , match=(reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(reg9[[5]] = chk_ecmp_nh(); ct_next;)
])

dnl The chassis was created with other_config:ct-no-masked-label=false, the flows
dnl should be using ct_label.ecmp_reply_port.
AT_CHECK([grep -e "lr_in_arp_resolve.*ecmp" lr0flows | sed 's/table=../table=??/'], [0], [dnl
table=??(lr_in_arp_resolve ), priority=200 , match=(ct.rpl && ct_label.ecmp_reply_port == 1), action=(push(xxreg1); xxreg1 = ct_label; eth.dst = xxreg1[[32..79]]; pop(xxreg1); next;)
table=??(lr_in_arp_resolve ), priority=200 , match=(ct.rpl && reg9[[5]] == 1 && ct_label.ecmp_reply_port == 1), action=(push(xxreg1); xxreg1 = ct_label; eth.dst = xxreg1[[32..79]]; pop(xxreg1); next;)
])

dnl Simulate an ovn-controller upgrade to a version that supports
Expand All @@ -5668,7 +5682,7 @@ check ovn-sbctl set chassis ch1 other_config:ct-no-masked-label=true
check ovn-nbctl --wait=sb sync
ovn-sbctl dump-flows lr0 > lr0flows
AT_CHECK([grep -e "lr_in_arp_resolve.*ecmp" lr0flows | sed 's/table=../table=??/'], [0], [dnl
table=??(lr_in_arp_resolve ), priority=200 , match=(ct.rpl && ct_mark.ecmp_reply_port == 1), action=(push(xxreg1); xxreg1 = ct_label; eth.dst = xxreg1[[32..79]]; pop(xxreg1); next;)
table=??(lr_in_arp_resolve ), priority=200 , match=(ct.rpl && reg9[[5]] == 1 && ct_mark.ecmp_reply_port == 1), action=(push(xxreg1); xxreg1 = ct_label; eth.dst = xxreg1[[32..79]]; pop(xxreg1); next;)
])

# add ecmp route with wrong nexthop
Expand Down
4 changes: 2 additions & 2 deletions tests/ovn.at
Original file line number Diff line number Diff line change
Expand Up @@ -27153,7 +27153,7 @@ AT_CHECK([
grep "priority=200" | \
grep -c "move:NXM_NX_CT_LABEL\\[[\\]]->NXM_NX_XXREG1\\[[\\]],move:NXM_NX_XXREG1\\[[32..79\\]]->NXM_OF_ETH_DST"
done; :], [0], [dnl
1
6
1
0
0
Expand Down Expand Up @@ -27278,7 +27278,7 @@ AT_CHECK([
grep "priority=200" | \
grep -c "move:NXM_NX_CT_LABEL\\[[\\]]->NXM_NX_XXREG1\\[[\\]],move:NXM_NX_XXREG1\\[[32..79\\]]->NXM_OF_ETH_DST"
done; :], [0], [dnl
1
6
1
0
0
Expand Down
79 changes: 67 additions & 12 deletions tests/system-ovn.at
Original file line number Diff line number Diff line change
Expand Up @@ -5958,19 +5958,16 @@ ovn-nbctl --wait=hv sync

on_exit 'ovs-ofctl dump-flows br-int'

# 'bob1' should be able to ping 'alice1' directly.
NS_CHECK_EXEC([bob1], [ping -q -c 20 -i 0.3 -w 15 10.0.0.2 | FORMAT_PING], \
[0], [dnl
20 packets transmitted, 20 received, 0% packet loss, time 0ms
])
NETNS_DAEMONIZE([alice1], [nc -l -k 80], [alice1.pid])
NS_CHECK_EXEC([bob1], [nc -z 10.0.0.2 80], [0])

# Ensure conntrack entry is present. We should not try to predict
# the tunnel key for the output port, so we strip it from the labels
# and just ensure that the known ethernet address is present.
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.0.1) | \
sed -e 's/zone=[[0-9]]*/zone=<cleared>/' |
sed -e 's/mark=[[0-9]]*/mark=<cleared>/'], [0], [dnl
icmp,orig=(src=172.16.0.1,dst=10.0.0.2,id=<cleared>,type=8,code=0),reply=(src=10.0.0.2,dst=172.16.0.1,id=<cleared>,type=0,code=0),zone=<cleared>,mark=<cleared>,labels=0x401020400000000
tcp,orig=(src=172.16.0.1,dst=10.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=10.0.0.2,dst=172.16.0.1,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=<cleared>,labels=0x401020400000000,protoinfo=(state=<cleared>)
])

# Ensure datapaths show conntrack states as expected
Expand All @@ -5983,6 +5980,36 @@ AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(-new+est+rpl+trk).*ct_lab
1
])

# Flush conntrack entries for easier output parsing of next test.
AT_CHECK([ovs-appctl dpctl/flush-conntrack])

# Change bob1 L2 address anche check the reply is properly updated.
ovn-nbctl set Logical_Router_Port R2_ext mac='"00:00:10:01:02:04"'
ovn-nbctl set Logical_Switch_Port r2-ext \
type=router options:router-port=R2_ext addresses='"00:00:10:01:02:04"'

NS_CHECK_EXEC([bob1], [nc -z 10.0.0.2 80], [0])
AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(+new-est-rpl+trk).*ct(.*label=0x1001020400000000/.*)' -c], [0], [dnl
1
])
AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(-new+est+rpl+trk).*ct_label(0x1001020400000000)' -c], [0], [dnl
1
])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 0x1001020400000000 | FORMAT_CT(172.16.0.1) | \
sed -e 's/zone=[[0-9]]*/zone=<cleared>/' |
sed -e 's/mark=[[0-9]]*/mark=<cleared>/'], [0], [dnl
tcp,orig=(src=172.16.0.1,dst=10.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=10.0.0.2,dst=172.16.0.1,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=<cleared>,labels=0x1001020400000000,protoinfo=(state=<cleared>)
])

# Check entries in table 76 and 77 expires w/o traffic
OVS_WAIT_UNTIL([
test $(ovs-ofctl dump-flows br-int | grep -c 'table=76, n_packets') -eq 0
])
OVS_WAIT_UNTIL([
test $(ovs-ofctl dump-flows br-int | grep -c 'table=77, n_packets') -eq 0
])

ovs-ofctl dump-flows br-int

OVS_APP_EXIT_AND_WAIT([ovn-controller])
Expand Down Expand Up @@ -6124,11 +6151,8 @@ ovn-nbctl --wait=hv sync

on_exit 'ovs-ofctl dump-flows br-int'

# 'bob1' should be able to ping 'alice1' directly.
NS_CHECK_EXEC([bob1], [ping -q -c 20 -i 0.3 -w 15 fd01::2 | FORMAT_PING], \
[0], [dnl
20 packets transmitted, 20 received, 0% packet loss, time 0ms
])
NETNS_DAEMONIZE([alice1], [nc -6 -l -k 80], [alice1.pid])
NS_CHECK_EXEC([bob1], [nc -6 -z fd01::2 80], [0])

# Ensure datapaths show conntrack states as expected
# Like with conntrack entries, we shouldn't try to predict
Expand All @@ -6147,7 +6171,38 @@ AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(-new+est+rpl+trk).*ct_lab
AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd01::2) | \
sed -e 's/zone=[[0-9]]*/zone=<cleared>/' |
sed -e 's/mark=[[0-9]]*/mark=<cleared>/'], [0], [dnl
icmpv6,orig=(src=fd07::1,dst=fd01::2,id=<cleared>,type=128,code=0),reply=(src=fd01::2,dst=fd07::1,id=<cleared>,type=129,code=0),zone=<cleared>,mark=<cleared>,labels=0x401020400000000
tcp,orig=(src=fd07::1,dst=fd01::2,sport=<cleared>,dport=<cleared>),reply=(src=fd01::2,dst=fd07::1,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=<cleared>,labels=0x401020400000000,protoinfo=(state=<cleared>)
])

# Flush conntrack entries for easier output parsing of next test.
AT_CHECK([ovs-appctl dpctl/flush-conntrack])

# Change bob1 L2 address anche check the reply is properly updated.
ovn-nbctl set Logical_Router_Port R2_ext mac='"00:00:10:01:02:04"'
ovn-nbctl set Logical_Switch_Port r2-ext \
type=router options:router-port=R2_ext addresses='"00:00:10:01:02:04"'

NS_CHECK_EXEC([bob1], [nc -6 -z fd01::2 80], [0])

AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(+new-est-rpl+trk).*ct(.*label=0x1001020400000000/.*)' -c], [0], [dnl
1
])
AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(-new+est+rpl+trk).*ct_label(0x1001020400000000)' -c], [0], [dnl
1
])

AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 0x1001020400000000 | FORMAT_CT(fd01::2) | \
sed -e 's/zone=[[0-9]]*/zone=<cleared>/' |
sed -e 's/mark=[[0-9]]*/mark=<cleared>/'], [0], [dnl
tcp,orig=(src=fd07::1,dst=fd01::2,sport=<cleared>,dport=<cleared>),reply=(src=fd01::2,dst=fd07::1,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=<cleared>,labels=0x1001020400000000,protoinfo=(state=<cleared>)
])

# Check entries in table 76 and 77 expires w/o traffic
OVS_WAIT_UNTIL([
test $(ovs-ofctl dump-flows br-int | grep -c 'table=76, n_packets') -eq 0
])
OVS_WAIT_UNTIL([
test $(ovs-ofctl dump-flows br-int | grep -c 'table=77, n_packets') -eq 0
])

ovs-ofctl dump-flows br-int
Expand Down

0 comments on commit 506f7d4

Please sign in to comment.