Merge ~fnordahl/ubuntu/+source/ovn:ubuntu/jammy into ~ubuntu-server-dev/ubuntu/+source/ovn:ubuntu/jammy

Proposed by Frode Nordahl
Status: Merged
Merged at revision: 39a1886e1c2a9c0288be5c1d97775249541717fe
Proposed branch: ~fnordahl/ubuntu/+source/ovn:ubuntu/jammy
Merge into: ~ubuntu-server-dev/ubuntu/+source/ovn:ubuntu/jammy
Diff against target: 7204 lines (+2849/-892)
44 files modified
.ci/ovn-kubernetes/Dockerfile (+1/-1)
AUTHORS.rst (+1/-0)
NEWS (+7/-1)
configure.ac (+1/-1)
controller-vtep/binding.c (+3/-5)
controller/binding.c (+97/-2)
controller/binding.h (+1/-0)
controller/chassis.c (+7/-0)
controller/lflow.c (+61/-10)
controller/lflow.h (+3/-0)
controller/ofctrl.c (+27/-6)
controller/ovn-controller.c (+190/-12)
controller/physical.c (+24/-26)
controller/pinctrl.c (+4/-3)
debian/changelog (+8/-0)
debian/control (+1/-1)
debian/ovn-common.install (+1/-0)
include/ovn/actions.h (+12/-1)
include/ovn/features.h (+2/-1)
include/ovn/logical-fields.h (+3/-2)
lib/actions.c (+122/-12)
lib/expr.c (+18/-13)
lib/inc-proc-eng.c (+4/-7)
lib/logical-fields.c (+16/-1)
lib/ovn-parallel-hmap.h (+5/-5)
lib/ovn-util.c (+24/-3)
lib/ovn-util.h (+4/-0)
northd/en-lflow.c (+1/-0)
northd/northd.c (+467/-190)
northd/northd.h (+6/-0)
northd/ovn-northd.8.xml (+44/-24)
northd/ovn-northd.c (+9/-1)
ovn-nb.xml (+2/-2)
ovn-sb.xml (+59/-11)
rhel/ovn-fedora.spec.in (+1/-1)
tests/ovn-controller.at (+129/-0)
tests/ovn-nbctl.at (+2/-0)
tests/ovn-northd.at (+510/-303)
tests/ovn-performance.at (+17/-0)
tests/ovn.at (+630/-136)
tests/system-ovn.at (+220/-101)
tests/test-ovn.c (+1/-0)
utilities/ovn-nbctl.c (+9/-6)
utilities/ovn-trace.c (+95/-4)
Reviewer Review Type Date Requested Status
James Page Pending
Review via email: mp+426342@code.launchpad.net
To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/.ci/ovn-kubernetes/Dockerfile b/.ci/ovn-kubernetes/Dockerfile
2index bd220b1..1966288 100644
3--- a/.ci/ovn-kubernetes/Dockerfile
4+++ b/.ci/ovn-kubernetes/Dockerfile
5@@ -60,7 +60,7 @@ FROM fedora:35
6
7 # install needed dependencies
8 RUN INSTALL_PKGS=" \
9- iptables iproute iputils hostname unbound-libs kubernetes-client kmod" && \
10+ iptables iproute iputils hostname unbound-libs kubernetes-client kmod socat" && \
11 dnf install --best --refresh -y --setopt=tsflags=nodocs $INSTALL_PKGS && \
12 dnf clean all && rm -rf /var/cache/dnf/*
13
14diff --git a/AUTHORS.rst b/AUTHORS.rst
15index 8572c24..d3747f8 100644
16--- a/AUTHORS.rst
17+++ b/AUTHORS.rst
18@@ -147,6 +147,7 @@ Fabrizio D'Angelo fdangelo@redhat.com
19 Flavio Fernandes flavio@flaviof.com
20 Flavio Leitner fbl@redhat.com
21 Francesco Fusco ffusco@redhat.com
22+François Rigault frigo@amadeus.com
23 Frank Wang wangpeihuixyz@126.com
24 Frédéric Tobias Christ fchrist@live.de
25 Frode Nordahl frode.nordahl@gmail.com
26diff --git a/NEWS b/NEWS
27index 9f3ce3c..1664707 100644
28--- a/NEWS
29+++ b/NEWS
30@@ -1,4 +1,10 @@
31-OVN v22.03.0 - XX XXX XXXX
32+OVN v22.03.1 - 03 Jun 2022
33+--------------------------
34+ - Bug fixes
35+ - Replaced the usage of masked ct_label by ct_mark in most cases to work
36+ better with hardware-offloading.
37+
38+OVN v22.03.0 - 11 Mar 2022
39 --------------------------
40 - Refactor CoPP commands introducing a unique name index in CoPP NB table.
41 Add following new CoPP commands to manage CoPP table:
42diff --git a/configure.ac b/configure.ac
43index 283381b..70f86e1 100644
44--- a/configure.ac
45+++ b/configure.ac
46@@ -13,7 +13,7 @@
47 # limitations under the License.
48
49 AC_PREREQ(2.63)
50-AC_INIT(ovn, 22.03.0, bugs@openvswitch.org)
51+AC_INIT(ovn, 22.03.1, bugs@openvswitch.org)
52 AC_CONFIG_MACRO_DIR([m4])
53 AC_CONFIG_AUX_DIR([build-aux])
54 AC_CONFIG_HEADERS([config.h])
55diff --git a/controller-vtep/binding.c b/controller-vtep/binding.c
56index 01d5a16..1ee52b5 100644
57--- a/controller-vtep/binding.c
58+++ b/controller-vtep/binding.c
59@@ -109,12 +109,10 @@ update_pb_chassis(const struct sbrec_port_binding *port_binding_rec,
60 port_binding_rec->chassis->name,
61 chassis_rec->name);
62 }
63-
64 sbrec_port_binding_set_chassis(port_binding_rec, chassis_rec);
65- if (port_binding_rec->n_up) {
66- bool up = true;
67- sbrec_port_binding_set_up(port_binding_rec, &up, 1);
68- }
69+ } else if (port_binding_rec->n_up) {
70+ bool up = true;
71+ sbrec_port_binding_set_up(port_binding_rec, &up, 1);
72 }
73 }
74
75diff --git a/controller/binding.c b/controller/binding.c
76index 4d62b08..9eaaddb 100644
77--- a/controller/binding.c
78+++ b/controller/binding.c
79@@ -482,6 +482,16 @@ remove_related_lport(const struct sbrec_port_binding *pb,
80 }
81
82 static void
83+delete_active_pb_ras_pd(const struct sbrec_port_binding *pb,
84+ struct shash *ras_pd_map)
85+{
86+ struct pb_ld_binding *ras_pd =
87+ shash_find_and_delete(ras_pd_map, pb->logical_port);
88+
89+ free(ras_pd);
90+}
91+
92+static void
93 update_active_pb_ras_pd(const struct sbrec_port_binding *pb,
94 struct hmap *local_datapaths,
95 struct shash *map, const char *conf)
96@@ -898,7 +908,9 @@ claimed_lport_set_up(const struct sbrec_port_binding *pb,
97 if (!notify_up) {
98 bool up = true;
99 if (!parent_pb || (parent_pb->n_up && parent_pb->up[0])) {
100- sbrec_port_binding_set_up(pb, &up, 1);
101+ if (pb->n_up) {
102+ sbrec_port_binding_set_up(pb, &up, 1);
103+ }
104 }
105 return;
106 }
107@@ -950,7 +962,8 @@ claim_lport(const struct sbrec_port_binding *pb,
108 /* Check if the port encap binding, if any, has changed */
109 struct sbrec_encap *encap_rec =
110 sbrec_get_port_encap(chassis_rec, iface_rec);
111- if (encap_rec && pb->encap != encap_rec) {
112+ if ((encap_rec && pb->encap != encap_rec) ||
113+ (!encap_rec && pb->encap)) {
114 if (sb_readonly) {
115 return false;
116 }
117@@ -1897,6 +1910,71 @@ is_iface_in_int_bridge(const struct ovsrec_interface *iface,
118 return false;
119 }
120
121+static bool
122+is_ext_id_changed(const struct smap *a, const struct smap *b, const char *key)
123+{
124+ const char *value_a = smap_get(a, key);
125+ const char *value_b = smap_get(b, key);
126+ if ((value_a && !value_b)
127+ || (!value_a && value_b)
128+ || (value_a && value_b && strcmp(value_a, value_b))) {
129+ return true;
130+ }
131+ return false;
132+}
133+
134+/* Check if the change in 'iface_rec' is something we are interested in from
135+ * port binding perspective. Return true if the change needs to be handled,
136+ * otherwise return false.
137+ *
138+ * The 'iface_rec' must be change tracked, i.e. iterator from
139+ * OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED. */
140+static bool
141+ovs_interface_change_need_handle(const struct ovsrec_interface *iface_rec,
142+ struct shash *iface_table_external_ids_old)
143+{
144+ if (ovsrec_interface_is_updated(iface_rec,
145+ OVSREC_INTERFACE_COL_NAME)) {
146+ return true;
147+ }
148+ if (ovsrec_interface_is_updated(iface_rec,
149+ OVSREC_INTERFACE_COL_OFPORT)) {
150+ return true;
151+ }
152+ if (ovsrec_interface_is_updated(iface_rec,
153+ OVSREC_INTERFACE_COL_TYPE)) {
154+ return true;
155+ }
156+ if (ovsrec_interface_is_updated(iface_rec,
157+ OVSREC_INTERFACE_COL_EXTERNAL_IDS)) {
158+ /* Compare the external_ids that we are interested in with the old
159+ * values:
160+ * - iface-id
161+ * - iface-id-ver
162+ * - encap-ip
163+ * For any other changes, such as ovn-installed, ovn-installed-ts, etc,
164+ * we don't need to handle. */
165+ struct smap *external_ids_old =
166+ shash_find_data(iface_table_external_ids_old, iface_rec->name);
167+ if (!external_ids_old) {
168+ return true;
169+ }
170+ if (is_ext_id_changed(&iface_rec->external_ids, external_ids_old,
171+ "iface-id")) {
172+ return true;
173+ }
174+ if (is_ext_id_changed(&iface_rec->external_ids, external_ids_old,
175+ "iface-id-ver")) {
176+ return true;
177+ }
178+ if (is_ext_id_changed(&iface_rec->external_ids, external_ids_old,
179+ "encap-ip")) {
180+ return true;
181+ }
182+ }
183+ return false;
184+}
185+
186 /* Returns true if the ovs interface changes were handled successfully,
187 * false otherwise.
188 */
189@@ -2008,6 +2086,11 @@ binding_handle_ovs_interface_changes(struct binding_ctx_in *b_ctx_in,
190 continue;
191 }
192
193+ if (!ovs_interface_change_need_handle(
194+ iface_rec, b_ctx_in->iface_table_external_ids_old)) {
195+ continue;
196+ }
197+
198 const char *iface_id = smap_get(&iface_rec->external_ids, "iface-id");
199 int64_t ofport = iface_rec->n_ofport ? *iface_rec->ofport : 0;
200 if (iface_id && ofport > 0 &&
201@@ -2049,6 +2132,15 @@ handle_deleted_lport(const struct sbrec_port_binding *pb,
202 return;
203 }
204
205+ /*
206+ * Remove localport that was part of local datapath that is not
207+ * considered to be local anymore.
208+ */
209+ if (!ld && !strcmp(pb->type, "localport") &&
210+ sset_find(&b_ctx_out->related_lports->lport_names, pb->logical_port)) {
211+ remove_related_lport(pb, b_ctx_out);
212+ }
213+
214 /* If the binding is not local, if 'pb' is a L3 gateway port, we should
215 * remove its peer, if that one is local.
216 */
217@@ -2251,6 +2343,9 @@ binding_handle_port_binding_changes(struct binding_ctx_in *b_ctx_in,
218 continue;
219 }
220
221+ delete_active_pb_ras_pd(pb, b_ctx_out->local_active_ports_ipv6_pd);
222+ delete_active_pb_ras_pd(pb, b_ctx_out->local_active_ports_ras);
223+
224 enum en_lport_type lport_type = get_lport_type(pb);
225
226 struct binding_lport *b_lport =
227diff --git a/controller/binding.h b/controller/binding.h
228index 430a8d9..e49e1eb 100644
229--- a/controller/binding.h
230+++ b/controller/binding.h
231@@ -55,6 +55,7 @@ struct binding_ctx_in {
232 const struct ovsrec_bridge_table *bridge_table;
233 const struct ovsrec_open_vswitch_table *ovs_table;
234 const struct ovsrec_interface_table *iface_table;
235+ struct shash *iface_table_external_ids_old;
236 };
237
238 /* Locally relevant port bindings, e.g., VIFs that might be bound locally,
239diff --git a/controller/chassis.c b/controller/chassis.c
240index 8a15596..92850fc 100644
241--- a/controller/chassis.c
242+++ b/controller/chassis.c
243@@ -350,6 +350,7 @@ chassis_build_other_config(const struct ovs_chassis_cfg *ovs_cfg,
244 smap_replace(config, "is-interconn",
245 ovs_cfg->is_interconn ? "true" : "false");
246 smap_replace(config, OVN_FEATURE_PORT_UP_NOTIF, "true");
247+ smap_replace(config, OVN_FEATURE_CT_NO_MASKED_LABEL, "true");
248 }
249
250 /*
251@@ -455,6 +456,12 @@ chassis_other_config_changed(const struct ovs_chassis_cfg *ovs_cfg,
252 return true;
253 }
254
255+ if (!smap_get_bool(&chassis_rec->other_config,
256+ OVN_FEATURE_CT_NO_MASKED_LABEL,
257+ false)) {
258+ return true;
259+ }
260+
261 return false;
262 }
263
264diff --git a/controller/lflow.c b/controller/lflow.c
265index e169ede..a988290 100644
266--- a/controller/lflow.c
267+++ b/controller/lflow.c
268@@ -1104,6 +1104,23 @@ lflow_parse_ctrl_meter(const struct sbrec_logical_flow *lflow,
269 }
270 }
271
272+static int
273+get_common_nat_zone(const struct local_datapath *ldp)
274+{
275+ /* Normally, the common NAT zone defaults to the DNAT zone. However,
276+ * if the "snat-ct-zone" is set on the datapath, the user is
277+ * expecting an explicit CT zone to be used for SNAT. If we default
278+ * to the DNAT zone, then it means SNAT will not use the configured
279+ * value. The way we get around this is to use the SNAT zone as the
280+ * common zone if "snat-ct-zone" is set.
281+ */
282+ if (smap_get(&ldp->datapath->external_ids, "snat-ct-zone")) {
283+ return MFF_LOG_SNAT_ZONE;
284+ } else {
285+ return MFF_LOG_DNAT_ZONE;
286+ }
287+}
288+
289 static void
290 add_matches_to_flow_table(const struct sbrec_logical_flow *lflow,
291 const struct local_datapath *ldp,
292@@ -1153,6 +1170,7 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow,
293 .fdb_ptable = OFTABLE_GET_FDB,
294 .fdb_lookup_ptable = OFTABLE_LOOKUP_FDB,
295 .ctrl_meter_id = ctrl_meter_id,
296+ .common_nat_ct_zone = get_common_nat_zone(ldp),
297 };
298 ovnacts_encode(ovnacts->data, ovnacts->size, &ep, &ofpacts);
299
300@@ -1894,6 +1912,7 @@ add_lb_vip_hairpin_flows(struct ovn_controller_lb *lb,
301 struct ovn_lb_vip *lb_vip,
302 struct ovn_lb_backend *lb_backend,
303 uint8_t lb_proto,
304+ bool use_ct_mark,
305 struct ovn_desired_flow_table *flow_table)
306 {
307 uint64_t stub[1024 / 8];
308@@ -1984,15 +2003,30 @@ add_lb_vip_hairpin_flows(struct ovn_controller_lb *lb,
309 * - packets must have ip.src == ip.dst at this point.
310 * - the destination protocol and port must be of a valid backend that
311 * has the same IP as ip.dst.
312+ *
313+ * During upgrades logical flows might still use the old way of storing
314+ * ct.natted in ct_label. For backwards compatibility, only use ct_mark
315+ * if ovn-northd notified ovn-controller to do that.
316 */
317- ovs_u128 lb_ct_label = {
318- .u64.lo = OVN_CT_NATTED,
319- };
320- match_set_ct_label_masked(&hairpin_match, lb_ct_label, lb_ct_label);
321+ if (use_ct_mark) {
322+ uint32_t lb_ct_mark = OVN_CT_NATTED;
323+ match_set_ct_mark_masked(&hairpin_match, lb_ct_mark, lb_ct_mark);
324+
325+ ofctrl_add_flow(flow_table, OFTABLE_CHK_LB_HAIRPIN, 100,
326+ lb->slb->header_.uuid.parts[0], &hairpin_match,
327+ &ofpacts, &lb->slb->header_.uuid);
328+ } else {
329+ match_set_ct_mark_masked(&hairpin_match, 0, 0);
330+ ovs_u128 lb_ct_label = {
331+ .u64.lo = OVN_CT_NATTED,
332+ };
333+ match_set_ct_label_masked(&hairpin_match, lb_ct_label, lb_ct_label);
334+
335+ ofctrl_add_flow(flow_table, OFTABLE_CHK_LB_HAIRPIN, 100,
336+ lb->slb->header_.uuid.parts[0], &hairpin_match,
337+ &ofpacts, &lb->slb->header_.uuid);
338+ }
339
340- ofctrl_add_flow(flow_table, OFTABLE_CHK_LB_HAIRPIN, 100,
341- lb->slb->header_.uuid.parts[0], &hairpin_match,
342- &ofpacts, &lb->slb->header_.uuid);
343 ofpbuf_uninit(&ofpacts);
344 }
345
346@@ -2265,6 +2299,7 @@ add_lb_ct_snat_hairpin_flows(struct ovn_controller_lb *lb,
347 static void
348 consider_lb_hairpin_flows(const struct sbrec_load_balancer *sbrec_lb,
349 const struct hmap *local_datapaths,
350+ bool use_ct_mark,
351 struct ovn_desired_flow_table *flow_table,
352 struct simap *ids)
353 {
354@@ -2304,7 +2339,7 @@ consider_lb_hairpin_flows(const struct sbrec_load_balancer *sbrec_lb,
355 struct ovn_lb_backend *lb_backend = &lb_vip->backends[j];
356
357 add_lb_vip_hairpin_flows(lb, lb_vip, lb_backend, lb_proto,
358- flow_table);
359+ use_ct_mark, flow_table);
360 }
361 }
362
363@@ -2317,7 +2352,7 @@ consider_lb_hairpin_flows(const struct sbrec_load_balancer *sbrec_lb,
364 * backends to handle the load balanced hairpin traffic. */
365 static void
366 add_lb_hairpin_flows(const struct sbrec_load_balancer_table *lb_table,
367- const struct hmap *local_datapaths,
368+ const struct hmap *local_datapaths, bool use_ct_mark,
369 struct ovn_desired_flow_table *flow_table,
370 struct simap *ids,
371 struct id_pool *pool)
372@@ -2340,7 +2375,8 @@ add_lb_hairpin_flows(const struct sbrec_load_balancer_table *lb_table,
373 ovs_assert(id_pool_alloc_id(pool, &id));
374 simap_put(ids, lb->name, id);
375 }
376- consider_lb_hairpin_flows(lb, local_datapaths, flow_table, ids);
377+ consider_lb_hairpin_flows(lb, local_datapaths, use_ct_mark,
378+ flow_table, ids);
379 }
380 }
381
382@@ -2446,6 +2482,7 @@ lflow_run(struct lflow_ctx_in *l_ctx_in, struct lflow_ctx_out *l_ctx_out)
383 l_ctx_in->mac_binding_table, l_ctx_in->local_datapaths,
384 l_ctx_out->flow_table);
385 add_lb_hairpin_flows(l_ctx_in->lb_table, l_ctx_in->local_datapaths,
386+ l_ctx_in->lb_hairpin_use_ct_mark,
387 l_ctx_out->flow_table,
388 l_ctx_out->hairpin_lb_ids,
389 l_ctx_out->hairpin_id_pool);
390@@ -2572,6 +2609,18 @@ lflow_add_flows_for_datapath(const struct sbrec_datapath_binding *dp,
391 }
392 sbrec_fdb_index_destroy_row(fdb_index_row);
393
394+ struct sbrec_mac_binding *mb_index_row = sbrec_mac_binding_index_init_row(
395+ l_ctx_in->sbrec_mac_binding_by_datapath);
396+ sbrec_mac_binding_index_set_datapath(mb_index_row, dp);
397+ const struct sbrec_mac_binding *mb;
398+ SBREC_MAC_BINDING_FOR_EACH_EQUAL (
399+ mb, mb_index_row, l_ctx_in->sbrec_mac_binding_by_datapath) {
400+ consider_neighbor_flow(l_ctx_in->sbrec_port_binding_by_name,
401+ l_ctx_in->local_datapaths,
402+ mb, l_ctx_out->flow_table);
403+ }
404+ sbrec_mac_binding_index_destroy_row(mb_index_row);
405+
406 dhcp_opts_destroy(&dhcp_opts);
407 dhcp_opts_destroy(&dhcpv6_opts);
408 nd_ra_opts_destroy(&nd_ra_opts);
409@@ -2581,6 +2630,7 @@ lflow_add_flows_for_datapath(const struct sbrec_datapath_binding *dp,
410 * associated. */
411 for (size_t i = 0; i < n_dp_lbs; i++) {
412 consider_lb_hairpin_flows(dp_lbs[i], l_ctx_in->local_datapaths,
413+ l_ctx_in->lb_hairpin_use_ct_mark,
414 l_ctx_out->flow_table,
415 l_ctx_out->hairpin_lb_ids);
416 }
417@@ -2694,6 +2744,7 @@ lflow_handle_changed_lbs(struct lflow_ctx_in *l_ctx_in,
418 VLOG_DBG("Add load balancer hairpin flows for "UUID_FMT,
419 UUID_ARGS(&lb->header_.uuid));
420 consider_lb_hairpin_flows(lb, l_ctx_in->local_datapaths,
421+ l_ctx_in->lb_hairpin_use_ct_mark,
422 l_ctx_out->flow_table,
423 l_ctx_out->hairpin_lb_ids);
424 }
425diff --git a/controller/lflow.h b/controller/lflow.h
426index d61733b..48a3650 100644
427--- a/controller/lflow.h
428+++ b/controller/lflow.h
429@@ -136,6 +136,8 @@ struct lflow_ctx_in {
430 struct ovsdb_idl_index *sbrec_logical_flow_by_logical_dp_group;
431 struct ovsdb_idl_index *sbrec_port_binding_by_name;
432 struct ovsdb_idl_index *sbrec_fdb_by_dp_key;
433+ struct ovsdb_idl_index *sbrec_mac_binding_by_datapath;
434+ struct ovsdb_idl_index *sbrec_static_mac_binding_by_datapath;
435 const struct sbrec_port_binding_table *port_binding_table;
436 const struct sbrec_dhcp_options_table *dhcp_options_table;
437 const struct sbrec_dhcpv6_options_table *dhcpv6_options_table;
438@@ -153,6 +155,7 @@ struct lflow_ctx_in {
439 const struct sset *active_tunnels;
440 const struct sset *related_lport_ids;
441 const struct hmap *chassis_tunnels;
442+ bool lb_hairpin_use_ct_mark;
443 };
444
445 struct lflow_ctx_out {
446diff --git a/controller/ofctrl.c b/controller/ofctrl.c
447index a7c2d20..3b9d717 100644
448--- a/controller/ofctrl.c
449+++ b/controller/ofctrl.c
450@@ -943,7 +943,12 @@ link_installed_to_desired(struct installed_flow *i, struct desired_flow *d)
451 break;
452 }
453 }
454- ovs_list_insert(&f->installed_ref_list_node, &d->installed_ref_list_node);
455+ if (!f) {
456+ ovs_list_insert(&i->desired_refs, &d->installed_ref_list_node);
457+ } else {
458+ ovs_list_insert(&f->installed_ref_list_node,
459+ &d->installed_ref_list_node);
460+ }
461 d->installed_flow = i;
462 return installed_flow_get_active(i) == d;
463 }
464@@ -2324,7 +2329,20 @@ deleted_flow_lookup(struct hmap *deleted_flows, struct ovn_flow *target)
465 && f->cookie == target->cookie
466 && ofpacts_equal(f->ofpacts, f->ofpacts_len, target->ofpacts,
467 target->ofpacts_len)) {
468- return d;
469+ /* del_f must have been installed, otherwise it should have
470+ * been removed during track_flow_del. */
471+ ovs_assert(d->installed_flow);
472+
473+ /* Now we also need to make sure the desired flow being
474+ * added/updated has exact same action and cookie as the installed
475+ * flow of d. Otherwise, don't merge them, so that the
476+ * installed flow can be updated later. */
477+ struct ovn_flow *f_i = &d->installed_flow->flow;
478+ if (f_i->cookie == target->cookie
479+ && ofpacts_equal(f_i->ofpacts, f_i->ofpacts_len,
480+ target->ofpacts, target->ofpacts_len)) {
481+ return d;
482+ }
483 }
484 }
485 return NULL;
486@@ -2353,10 +2371,6 @@ merge_tracked_flows(struct ovn_desired_flow_table *flow_table)
487 continue;
488 }
489
490- /* del_f must have been installed, otherwise it should have been
491- * removed during track_flow_add_or_modify. */
492- ovs_assert(del_f->installed_flow);
493-
494 if (!f->installed_flow) {
495 /* f is not installed yet. */
496 replace_installed_to_desired(del_f->installed_flow, del_f, f);
497@@ -2665,6 +2679,13 @@ ofctrl_put(struct ovn_desired_flow_table *lflow_table,
498 EXTEND_TABLE_FOR_EACH_INSTALLED (m_installed, next_meter, meters) {
499 /* Delete the meter. */
500 ofctrl_meter_bands_erase(m_installed, &msgs);
501+ if (!strncmp(m_installed->name, "__string: ", 10)) {
502+ struct ofputil_meter_mod mm = {
503+ .command = OFPMC13_DELETE,
504+ .meter = { .meter_id = m_installed->table_id },
505+ };
506+ add_meter_mod(&mm, &msgs);
507+ }
508 ovn_extend_table_remove_existing(meters, m_installed);
509 }
510
511diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
512index ea5e9df..6d10c03 100644
513--- a/controller/ovn-controller.c
514+++ b/controller/ovn-controller.c
515@@ -131,6 +131,9 @@ static const char *ssl_ca_cert_file;
516 #define DEFAULT_LFLOW_CACHE_WMARK_PERC 50
517 #define DEFAULT_LFLOW_CACHE_TRIM_TO_MS 30000
518
519+/* SB Global options defaults. */
520+#define DEFAULT_SB_GLOBAL_LB_HAIRPIN_USE_CT_MARK false
521+
522 struct controller_engine_ctx {
523 struct lflow_cache *lflow_cache;
524 struct if_status_mgr *if_mgr;
525@@ -819,13 +822,18 @@ restore_ct_zones(const struct ovsrec_bridge_table *bridge_table,
526 }
527
528 const char *user = node->key + 8;
529- int zone = atoi(node->value);
530+ if (!user[0]) {
531+ continue;
532+ }
533
534- if (user[0] && zone) {
535- VLOG_DBG("restoring ct zone %"PRId32" for '%s'", zone, user);
536- bitmap_set1(ct_zone_bitmap, zone);
537- simap_put(ct_zones, user, zone);
538+ unsigned int zone;
539+ if (!str_to_uint(node->value, 10, &zone)) {
540+ continue;
541 }
542+
543+ VLOG_DBG("restoring ct zone %"PRId32" for '%s'", zone, user);
544+ bitmap_set1(ct_zone_bitmap, zone);
545+ simap_put(ct_zones, user, zone);
546 }
547 }
548
549@@ -954,6 +962,7 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl)
550 }
551
552 #define SB_NODES \
553+ SB_NODE(sb_global, "sb_global") \
554 SB_NODE(chassis, "chassis") \
555 SB_NODE(encap, "encap") \
556 SB_NODE(address_set, "address_set") \
557@@ -1034,6 +1043,91 @@ en_ofctrl_is_connected_run(struct engine_node *node, void *data)
558 engine_set_node_state(node, EN_UNCHANGED);
559 }
560
561+/* This engine node is to wrap the OVS_interface input and maintain a copy of
562+ * the old version of data for the column external_ids.
563+ *
564+ * There are some special considerations of this engine node:
565+ * 1. It has a single input OVS_interface, and it transparently passes the
566+ * input changes as its own output data to its dependants. So there is no
567+ * processing to OVS_interface changes but simply mark the node status as
568+ * UPDATED (and so the run() and the change handler is the same).
569+ * 2. The iface_table_external_ids_old is computed/updated in the member
570+ * clear_tracked_data(), because that is when the last round of processing
571+ * has completed but the new IDL data is yet to refresh, so we replace the
572+ * old data with the current data. */
573+struct ed_type_ovs_interface_shadow {
574+ struct ovsrec_interface_table *iface_table;
575+ struct shash iface_table_external_ids_old;
576+};
577+
578+static void *
579+en_ovs_interface_shadow_init(struct engine_node *node OVS_UNUSED,
580+ struct engine_arg *arg OVS_UNUSED)
581+{
582+ struct ed_type_ovs_interface_shadow *data = xzalloc(sizeof *data);
583+ data->iface_table = NULL;
584+ shash_init(&data->iface_table_external_ids_old);
585+
586+ return data;
587+}
588+
589+static void
590+iface_table_external_ids_old_destroy(struct shash *table_ext_ids)
591+{
592+ struct shash_node *node;
593+ SHASH_FOR_EACH (node, table_ext_ids) {
594+ struct smap *ext_ids = node->data;
595+ smap_destroy(ext_ids);
596+ }
597+ shash_destroy_free_data(table_ext_ids);
598+}
599+
600+static void
601+en_ovs_interface_shadow_cleanup(void *data_)
602+{
603+ struct ed_type_ovs_interface_shadow *data = data_;
604+ iface_table_external_ids_old_destroy(&data->iface_table_external_ids_old);
605+}
606+
607+static void
608+en_ovs_interface_shadow_clear_tracked_data(void *data_)
609+{
610+ struct ed_type_ovs_interface_shadow *data = data_;
611+ iface_table_external_ids_old_destroy(&data->iface_table_external_ids_old);
612+ shash_init(&data->iface_table_external_ids_old);
613+
614+ if (!data->iface_table) {
615+ return;
616+ }
617+
618+ const struct ovsrec_interface *iface_rec;
619+ OVSREC_INTERFACE_TABLE_FOR_EACH (iface_rec, data->iface_table) {
620+ struct smap *external_ids = xmalloc(sizeof *external_ids);
621+ smap_clone(external_ids, &iface_rec->external_ids);
622+ shash_add(&data->iface_table_external_ids_old, iface_rec->name,
623+ external_ids);
624+ }
625+}
626+
627+static void
628+en_ovs_interface_shadow_run(struct engine_node *node, void *data_)
629+{
630+ struct ed_type_ovs_interface_shadow *data = data_;
631+ struct ovsrec_interface_table *iface_table =
632+ (struct ovsrec_interface_table *)EN_OVSDB_GET(
633+ engine_get_input("OVS_interface", node));
634+ data->iface_table = iface_table;
635+ engine_set_node_state(node, EN_UPDATED);
636+}
637+
638+static bool
639+ovs_interface_shadow_ovs_interface_handler(struct engine_node *node,
640+ void *data_)
641+{
642+ en_ovs_interface_shadow_run(node, data_);
643+ return true;
644+}
645+
646 struct ed_type_runtime_data {
647 /* Contains "struct local_datapath" nodes. */
648 struct hmap local_datapaths;
649@@ -1206,9 +1300,8 @@ init_binding_ctx(struct engine_node *node,
650 (struct ovsrec_port_table *)EN_OVSDB_GET(
651 engine_get_input("OVS_port", node));
652
653- struct ovsrec_interface_table *iface_table =
654- (struct ovsrec_interface_table *)EN_OVSDB_GET(
655- engine_get_input("OVS_interface", node));
656+ struct ed_type_ovs_interface_shadow *iface_shadow =
657+ engine_get_input_data("ovs_interface_shadow", node);
658
659 struct ovsrec_qos_table *qos_table =
660 (struct ovsrec_qos_table *)EN_OVSDB_GET(
661@@ -1241,7 +1334,9 @@ init_binding_ctx(struct engine_node *node,
662 b_ctx_in->sbrec_port_binding_by_datapath = sbrec_port_binding_by_datapath;
663 b_ctx_in->sbrec_port_binding_by_name = sbrec_port_binding_by_name;
664 b_ctx_in->port_table = port_table;
665- b_ctx_in->iface_table = iface_table;
666+ b_ctx_in->iface_table = iface_shadow->iface_table;
667+ b_ctx_in->iface_table_external_ids_old =
668+ &iface_shadow->iface_table_external_ids_old;
669 b_ctx_in->qos_table = qos_table;
670 b_ctx_in->port_binding_table = pb_table;
671 b_ctx_in->br_int = br_int;
672@@ -1323,7 +1418,7 @@ en_runtime_data_run(struct engine_node *node, void *data)
673 }
674
675 static bool
676-runtime_data_ovs_interface_handler(struct engine_node *node, void *data)
677+runtime_data_ovs_interface_shadow_handler(struct engine_node *node, void *data)
678 {
679 struct ed_type_runtime_data *rt_data = data;
680 struct binding_ctx_in b_ctx_in;
681@@ -2194,6 +2289,63 @@ non_vif_data_ovs_iface_handler(struct engine_node *node, void *data OVS_UNUSED)
682 return local_nonvif_data_handle_ovs_iface_changes(iface_table);
683 }
684
685+struct ed_type_northd_options {
686+ bool lb_hairpin_use_ct_mark;
687+};
688+
689+
690+static void *
691+en_northd_options_init(struct engine_node *node OVS_UNUSED,
692+ struct engine_arg *arg OVS_UNUSED)
693+{
694+ struct ed_type_northd_options *n_opts = xzalloc(sizeof *n_opts);
695+ return n_opts;
696+}
697+
698+static void
699+en_northd_options_cleanup(void *data OVS_UNUSED)
700+{
701+}
702+
703+static void
704+en_northd_options_run(struct engine_node *node, void *data)
705+{
706+ struct ed_type_northd_options *n_opts = data;
707+ const struct sbrec_sb_global_table *sb_global_table =
708+ EN_OVSDB_GET(engine_get_input("SB_sb_global", node));
709+ const struct sbrec_sb_global *sb_global =
710+ sbrec_sb_global_table_first(sb_global_table);
711+
712+ n_opts->lb_hairpin_use_ct_mark =
713+ sb_global
714+ ? smap_get_bool(&sb_global->options, "lb_hairpin_use_ct_mark",
715+ DEFAULT_SB_GLOBAL_LB_HAIRPIN_USE_CT_MARK)
716+ : DEFAULT_SB_GLOBAL_LB_HAIRPIN_USE_CT_MARK;
717+ engine_set_node_state(node, EN_UPDATED);
718+}
719+
720+static bool
721+en_northd_options_sb_sb_global_handler(struct engine_node *node, void *data)
722+{
723+ struct ed_type_northd_options *n_opts = data;
724+ const struct sbrec_sb_global_table *sb_global_table =
725+ EN_OVSDB_GET(engine_get_input("SB_sb_global", node));
726+ const struct sbrec_sb_global *sb_global =
727+ sbrec_sb_global_table_first(sb_global_table);
728+
729+ bool lb_hairpin_use_ct_mark =
730+ sb_global
731+ ? smap_get_bool(&sb_global->options, "lb_hairpin_use_ct_mark",
732+ DEFAULT_SB_GLOBAL_LB_HAIRPIN_USE_CT_MARK)
733+ : DEFAULT_SB_GLOBAL_LB_HAIRPIN_USE_CT_MARK;
734+
735+ if (lb_hairpin_use_ct_mark != n_opts->lb_hairpin_use_ct_mark) {
736+ n_opts->lb_hairpin_use_ct_mark = lb_hairpin_use_ct_mark;
737+ engine_set_node_state(node, EN_UPDATED);
738+ }
739+ return true;
740+}
741+
742 struct lflow_output_persistent_data {
743 struct lflow_cache *lflow_cache;
744 };
745@@ -2259,6 +2411,11 @@ init_lflow_ctx(struct engine_node *node,
746 engine_get_input("SB_fdb", node),
747 "dp_key");
748
749+ struct ovsdb_idl_index *sbrec_mac_binding_by_datapath =
750+ engine_ovsdb_node_get_index(
751+ engine_get_input("SB_mac_binding", node),
752+ "datapath");
753+
754 struct sbrec_port_binding_table *port_binding_table =
755 (struct sbrec_port_binding_table *)EN_OVSDB_GET(
756 engine_get_input("SB_port_binding", node));
757@@ -2325,6 +2482,9 @@ init_lflow_ctx(struct engine_node *node,
758 engine_get_input_data("port_groups", node);
759 struct shash *port_groups = &pg_data->port_groups_cs_local;
760
761+ struct ed_type_northd_options *n_opts =
762+ engine_get_input_data("northd_options", node);
763+
764 l_ctx_in->sbrec_multicast_group_by_name_datapath =
765 sbrec_mc_group_by_name_dp;
766 l_ctx_in->sbrec_logical_flow_by_logical_datapath =
767@@ -2333,6 +2493,7 @@ init_lflow_ctx(struct engine_node *node,
768 sbrec_logical_flow_by_dp_group;
769 l_ctx_in->sbrec_port_binding_by_name = sbrec_port_binding_by_name;
770 l_ctx_in->sbrec_fdb_by_dp_key = sbrec_fdb_by_dp_key;
771+ l_ctx_in->sbrec_mac_binding_by_datapath = sbrec_mac_binding_by_datapath;
772 l_ctx_in->port_binding_table = port_binding_table;
773 l_ctx_in->dhcp_options_table = dhcp_table;
774 l_ctx_in->dhcpv6_options_table = dhcpv6_table;
775@@ -2349,6 +2510,7 @@ init_lflow_ctx(struct engine_node *node,
776 l_ctx_in->active_tunnels = &rt_data->active_tunnels;
777 l_ctx_in->related_lport_ids = &rt_data->related_lports.lport_ids;
778 l_ctx_in->chassis_tunnels = &non_vif_data->chassis_tunnels;
779+ l_ctx_in->lb_hairpin_use_ct_mark = n_opts->lb_hairpin_use_ct_mark;
780
781 l_ctx_out->flow_table = &fo->flow_table;
782 l_ctx_out->group_table = &fo->group_table;
783@@ -3173,6 +3335,9 @@ main(int argc, char *argv[])
784 = ovsdb_idl_index_create2(ovnsb_idl_loop.idl,
785 &sbrec_fdb_col_mac,
786 &sbrec_fdb_col_dp_key);
787+ struct ovsdb_idl_index *sbrec_mac_binding_by_datapath
788+ = ovsdb_idl_index_create1(ovnsb_idl_loop.idl,
789+ &sbrec_mac_binding_col_datapath);
790
791 ovsdb_idl_track_add_all(ovnsb_idl_loop.idl);
792 ovsdb_idl_omit_alert(ovnsb_idl_loop.idl,
793@@ -3234,6 +3399,8 @@ main(int argc, char *argv[])
794
795 /* Define inc-proc-engine nodes. */
796 ENGINE_NODE_WITH_CLEAR_TRACK_DATA_IS_VALID(ct_zones, "ct_zones");
797+ ENGINE_NODE_WITH_CLEAR_TRACK_DATA(ovs_interface_shadow,
798+ "ovs_interface_shadow");
799 ENGINE_NODE_WITH_CLEAR_TRACK_DATA(runtime_data, "runtime_data");
800 ENGINE_NODE(non_vif_data, "non_vif_data");
801 ENGINE_NODE(mff_ovn_geneve, "mff_ovn_geneve");
802@@ -3243,6 +3410,7 @@ main(int argc, char *argv[])
803 ENGINE_NODE(flow_output, "flow_output");
804 ENGINE_NODE_WITH_CLEAR_TRACK_DATA(addr_sets, "addr_sets");
805 ENGINE_NODE_WITH_CLEAR_TRACK_DATA(port_groups, "port_groups");
806+ ENGINE_NODE(northd_options, "northd_options");
807
808 #define SB_NODE(NAME, NAME_STR) ENGINE_NODE_SB(NAME, NAME_STR);
809 SB_NODES
810@@ -3291,6 +3459,11 @@ main(int argc, char *argv[])
811 engine_add_input(&en_pflow_output, &en_ovs_open_vswitch, NULL);
812 engine_add_input(&en_pflow_output, &en_ovs_bridge, NULL);
813
814+ engine_add_input(&en_northd_options, &en_sb_sb_global,
815+ en_northd_options_sb_sb_global_handler);
816+
817+ engine_add_input(&en_lflow_output, &en_northd_options, NULL);
818+
819 /* Keep en_addr_sets before en_runtime_data because
820 * lflow_output_runtime_data_handler may *partially* reprocess a lflow when
821 * the lflow is attached to a DP group and a new DP in that DP group is
822@@ -3347,6 +3520,9 @@ main(int argc, char *argv[])
823 engine_add_input(&en_ct_zones, &en_runtime_data,
824 ct_zones_runtime_data_handler);
825
826+ engine_add_input(&en_ovs_interface_shadow, &en_ovs_interface,
827+ ovs_interface_shadow_ovs_interface_handler);
828+
829 engine_add_input(&en_runtime_data, &en_ofctrl_is_connected, NULL);
830
831 engine_add_input(&en_runtime_data, &en_ovs_open_vswitch, NULL);
832@@ -3368,8 +3544,8 @@ main(int argc, char *argv[])
833 */
834 engine_add_input(&en_runtime_data, &en_ovs_port,
835 engine_noop_handler);
836- engine_add_input(&en_runtime_data, &en_ovs_interface,
837- runtime_data_ovs_interface_handler);
838+ engine_add_input(&en_runtime_data, &en_ovs_interface_shadow,
839+ runtime_data_ovs_interface_shadow_handler);
840
841 engine_add_input(&en_flow_output, &en_lflow_output,
842 flow_output_lflow_output_handler);
843@@ -3399,6 +3575,8 @@ main(int argc, char *argv[])
844 sbrec_datapath_binding_by_key);
845 engine_ovsdb_node_add_index(&en_sb_fdb, "dp_key",
846 sbrec_fdb_by_dp_key);
847+ engine_ovsdb_node_add_index(&en_sb_mac_binding, "datapath",
848+ sbrec_mac_binding_by_datapath);
849
850 struct ed_type_lflow_output *lflow_output_data =
851 engine_get_internal_data(&en_lflow_output);
852diff --git a/controller/physical.c b/controller/physical.c
853index 033828d..adf4632 100644
854--- a/controller/physical.c
855+++ b/controller/physical.c
856@@ -421,6 +421,12 @@ populate_remote_chassis_macs(const struct sbrec_chassis *my_chassis,
857 char *save_ptr2 = NULL;
858 char *chassis_mac_bridge = strtok_r(token, ":", &save_ptr2);
859 char *chassis_mac_str = strtok_r(NULL, "", &save_ptr2);
860+ if (!chassis_mac_str) {
861+ VLOG_WARN("Parsing of ovn-chassis-mac-mappings failed for: "
862+ "\"%s\", the correct format is \"br-name1:MAC1\".",
863+ token);
864+ continue;
865+ }
866 struct remote_chassis_mac *remote_chassis_mac = NULL;
867 remote_chassis_mac = xmalloc(sizeof *remote_chassis_mac);
868 hmap_insert(&remote_chassis_macs, &remote_chassis_mac->hmap_node,
869@@ -1309,6 +1315,24 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name,
870 }
871 }
872
873+ /* Table 37, priority 150.
874+ * =======================
875+ *
876+ * Handles packets received from ports of type "localport". These
877+ * ports are present on every hypervisor. Traffic that originates at
878+ * one should never go over a tunnel to a remote hypervisor,
879+ * so resubmit them to table 38 for local delivery. */
880+ if (!strcmp(binding->type, "localport")) {
881+ ofpbuf_clear(ofpacts_p);
882+ put_resubmit(OFTABLE_LOCAL_OUTPUT, ofpacts_p);
883+ match_init_catchall(&match);
884+ match_set_reg(&match, MFF_LOG_INPORT - MFF_REG0,
885+ binding->tunnel_key);
886+ match_set_metadata(&match, htonll(binding->datapath->tunnel_key));
887+ ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150,
888+ binding->header_.uuid.parts[0], &match,
889+ ofpacts_p, &binding->header_.uuid);
890+ }
891 } else if (!tun && !is_ha_remote) {
892 /* Remote port connected by localnet port */
893 /* Table 38, priority 100.
894@@ -1840,32 +1864,6 @@ physical_run(struct physical_ctx *p_ctx,
895 ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150, 0,
896 &match, &ofpacts, hc_uuid);
897
898- /* Table 37, priority 150.
899- * =======================
900- *
901- * Handles packets received from ports of type "localport". These ports
902- * are present on every hypervisor. Traffic that originates at one should
903- * never go over a tunnel to a remote hypervisor, so resubmit them to table
904- * 38 for local delivery. */
905- match_init_catchall(&match);
906- ofpbuf_clear(&ofpacts);
907- put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts);
908- const char *localport;
909- SSET_FOR_EACH (localport, p_ctx->local_lports) {
910- /* Iterate over all local logical ports and insert a drop
911- * rule with higher priority for every localport in this
912- * datapath. */
913- const struct sbrec_port_binding *pb = lport_lookup_by_name(
914- p_ctx->sbrec_port_binding_by_name, localport);
915- if (pb && !strcmp(pb->type, "localport")) {
916- match_set_reg(&match, MFF_LOG_INPORT - MFF_REG0, pb->tunnel_key);
917- match_set_metadata(&match, htonll(pb->datapath->tunnel_key));
918- ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150,
919- pb->header_.uuid.parts[0],
920- &match, &ofpacts, hc_uuid);
921- }
922- }
923-
924 /* Table 37, Priority 0.
925 * =======================
926 *
927diff --git a/controller/pinctrl.c b/controller/pinctrl.c
928index 25b37ee..2f718ac 100644
929--- a/controller/pinctrl.c
930+++ b/controller/pinctrl.c
931@@ -5523,7 +5523,7 @@ get_localnet_vifs_l3gwports(
932 }
933 const struct sbrec_port_binding *pb
934 = lport_lookup_by_name(sbrec_port_binding_by_name, iface_id);
935- if (!pb) {
936+ if (!pb || pb->chassis != chassis) {
937 continue;
938 }
939 struct local_datapath *ld
940@@ -5554,7 +5554,7 @@ get_localnet_vifs_l3gwports(
941 sbrec_port_binding_index_set_datapath(target, ld->datapath);
942 SBREC_PORT_BINDING_FOR_EACH_EQUAL (pb, target,
943 sbrec_port_binding_by_datapath) {
944- if (!strcmp(pb->type, "l3gateway")
945+ if ((!strcmp(pb->type, "l3gateway") && pb->chassis == chassis)
946 || !strcmp(pb->type, "patch")) {
947 sset_add(local_l3gw_ports, pb->logical_port);
948 }
949@@ -5781,7 +5781,8 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn *ovnsb_idl_txn,
950 const struct sbrec_port_binding *pb = lport_lookup_by_name(
951 sbrec_port_binding_by_name, iface_id);
952 if (pb) {
953- send_garp_rarp_update(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip,
954+ send_garp_rarp_update(ovnsb_idl_txn,
955+ sbrec_mac_binding_by_lport_ip,
956 local_datapaths, pb, &nat_addresses);
957 }
958 }
959diff --git a/debian/changelog b/debian/changelog
960index e1246f3..d294bfc 100644
961--- a/debian/changelog
962+++ b/debian/changelog
963@@ -1,3 +1,11 @@
964+ovn (22.03.1-0ubuntu1) UNRELEASED; urgency=medium
965+
966+ * New upstream point release (LP: #1980809).
967+ * d/ovn-common.install: Add missing ovn_detrace.py binary (LP: #1971178).
968+ * d/control: Update openvswitch build requirement.
969+
970+ -- Frode Nordahl <frode.nordahl@canonical.com> Wed, 06 Jul 2022 09:09:25 +0200
971+
972 ovn (22.03.0-0ubuntu1) jammy; urgency=medium
973
974 [ Frode Nordahl ]
975diff --git a/debian/control b/debian/control
976index 503de8e..87f7265 100644
977--- a/debian/control
978+++ b/debian/control
979@@ -18,7 +18,7 @@ Build-Depends:
980 libudev-dev,
981 libunbound-dev,
982 openssl,
983- openvswitch-source (>= 2.17.0~),
984+ openvswitch-source (>= 2.17.2~),
985 pkg-config,
986 procps,
987 python3-all-dev,
988diff --git a/debian/ovn-common.install b/debian/ovn-common.install
989index 8503c01..9bdbdca 100644
990--- a/debian/ovn-common.install
991+++ b/debian/ovn-common.install
992@@ -1,4 +1,5 @@
993 usr/bin/ovn-appctl
994+usr/bin/ovn_detrace.py
995 usr/bin/ovn-detrace
996 usr/bin/ovn-nbctl
997 usr/bin/ovn-sbctl
998diff --git a/include/ovn/actions.h b/include/ovn/actions.h
999index 0641b92..5477975 100644
1000--- a/include/ovn/actions.h
1001+++ b/include/ovn/actions.h
1002@@ -59,6 +59,8 @@ struct ovn_extend_table;
1003 OVNACT(NEXT, ovnact_next) \
1004 OVNACT(LOAD, ovnact_load) \
1005 OVNACT(MOVE, ovnact_move) \
1006+ OVNACT(PUSH, ovnact_push_pop) \
1007+ OVNACT(POP, ovnact_push_pop) \
1008 OVNACT(EXCHANGE, ovnact_move) \
1009 OVNACT(DEC_TTL, ovnact_null) \
1010 OVNACT(CT_NEXT, ovnact_ct_next) \
1011@@ -69,6 +71,7 @@ struct ovn_extend_table;
1012 OVNACT(CT_DNAT_IN_CZONE, ovnact_ct_nat) \
1013 OVNACT(CT_SNAT_IN_CZONE, ovnact_ct_nat) \
1014 OVNACT(CT_LB, ovnact_ct_lb) \
1015+ OVNACT(CT_LB_MARK, ovnact_ct_lb) \
1016 OVNACT(SELECT, ovnact_select) \
1017 OVNACT(CT_CLEAR, ovnact_null) \
1018 OVNACT(CLONE, ovnact_nest) \
1019@@ -233,6 +236,12 @@ struct ovnact_move {
1020 struct expr_field rhs;
1021 };
1022
1023+/* OVNACT_PUSH, OVNACT_POP. */
1024+struct ovnact_push_pop {
1025+ struct ovnact ovnact;
1026+ struct expr_field field;
1027+};
1028+
1029 /* OVNACT_CT_NEXT. */
1030 struct ovnact_ct_next {
1031 struct ovnact ovnact;
1032@@ -273,7 +282,7 @@ struct ovnact_ct_lb_dst {
1033 uint16_t port;
1034 };
1035
1036-/* OVNACT_CT_LB. */
1037+/* OVNACT_CT_LB/OVNACT_CT_LB_MARK. */
1038 struct ovnact_ct_lb {
1039 struct ovnact ovnact;
1040 struct ovnact_ct_lb_dst *dsts;
1041@@ -799,6 +808,8 @@ struct ovnact_encode_params {
1042 * 'lookup_fdb' to resubmit. */
1043 uint32_t ctrl_meter_id; /* Meter to be used if the resulting flow
1044 sends packets to controller. */
1045+ uint32_t common_nat_ct_zone; /* When performing NAT in a common CT zone,
1046+ this determines which CT zone to use */
1047 };
1048
1049 void ovnacts_encode(const struct ovnact[], size_t ovnacts_len,
1050diff --git a/include/ovn/features.h b/include/ovn/features.h
1051index d12a8eb..8fbdbf1 100644
1052--- a/include/ovn/features.h
1053+++ b/include/ovn/features.h
1054@@ -21,7 +21,8 @@
1055 #include "smap.h"
1056
1057 /* ovn-controller supported feature names. */
1058-#define OVN_FEATURE_PORT_UP_NOTIF "port-up-notif"
1059+#define OVN_FEATURE_PORT_UP_NOTIF "port-up-notif"
1060+#define OVN_FEATURE_CT_NO_MASKED_LABEL "ct-no-masked-label"
1061
1062 /* OVS datapath supported features. Based on availability OVN might generate
1063 * different types of openflows.
1064diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h
1065index 2118f79..1851663 100644
1066--- a/include/ovn/logical-fields.h
1067+++ b/include/ovn/logical-fields.h
1068@@ -36,8 +36,6 @@ enum ovn_controller_event {
1069 * (32 bits). */
1070 #define MFF_LOG_SNAT_ZONE MFF_REG12 /* conntrack snat zone for gateway router
1071 * (32 bits). */
1072-#define MFF_LOG_NAT_ZONE MFF_LOG_DNAT_ZONE /* conntrack zone for both snat
1073- * and dnat. */
1074 #define MFF_LOG_CT_ZONE MFF_REG13 /* Logical conntrack zone for lports
1075 * (32 bits). */
1076 #define MFF_LOG_INPORT MFF_REG14 /* Logical input port (32 bits). */
1077@@ -176,6 +174,9 @@ const struct ovn_field *ovn_field_from_name(const char *name);
1078 #define OVN_CT_BLOCKED 1
1079 #define OVN_CT_NATTED 2
1080
1081+#define OVN_CT_ECMP_ETH_1ST_BIT 32
1082+#define OVN_CT_ECMP_ETH_END_BIT 79
1083+
1084 #define OVN_CT_STR(LABEL_VALUE) OVS_STRINGIZE(LABEL_VALUE)
1085 #define OVN_CT_MASKED_STR(LABEL_VALUE) \
1086 OVS_STRINGIZE(LABEL_VALUE) "/" OVS_STRINGIZE(LABEL_VALUE)
1087diff --git a/lib/actions.c b/lib/actions.c
1088index 5d3caaf..a9c2760 100644
1089--- a/lib/actions.c
1090+++ b/lib/actions.c
1091@@ -573,6 +573,75 @@ ovnact_move_free(struct ovnact_move *move OVS_UNUSED)
1092 {
1093 }
1094
1095
1096+
1097+static void
1098+parse_push_pop(struct action_context *ctx, bool is_push)
1099+{
1100+ lexer_force_match(ctx->lexer, LEX_T_LPAREN);
1101+
1102+ struct expr_field f;
1103+ if (!expr_field_parse(ctx->lexer, ctx->pp->symtab, &f, &ctx->prereqs)) {
1104+ return;
1105+ }
1106+ size_t ofs = ctx->ovnacts->size;
1107+ char *error = expr_type_check(&f, f.n_bits, !is_push, ctx->scope);
1108+ if (error) {
1109+ ctx->ovnacts->size = ofs;
1110+ lexer_error(ctx->lexer, "%s", error);
1111+ free(error);
1112+ return;
1113+ }
1114+
1115+ lexer_force_match(ctx->lexer, LEX_T_RPAREN);
1116+
1117+ struct ovnact_push_pop *p;
1118+ if (is_push) {
1119+ p = ovnact_put_PUSH(ctx->ovnacts);
1120+ } else {
1121+ p = ovnact_put_POP(ctx->ovnacts);
1122+ }
1123+ p->field = f;
1124+}
1125+
1126+static void
1127+format_PUSH(const struct ovnact_push_pop *push, struct ds *s)
1128+{
1129+ ds_put_cstr(s, "push(");
1130+ expr_field_format(&push->field, s);
1131+ ds_put_cstr(s, ");");
1132+}
1133+
1134+static void
1135+encode_PUSH(const struct ovnact_push_pop *push,
1136+ const struct ovnact_encode_params *ep OVS_UNUSED,
1137+ struct ofpbuf *ofpacts)
1138+{
1139+ ofpact_put_STACK_PUSH(ofpacts)->subfield =
1140+ expr_resolve_field(&push->field);
1141+}
1142+
1143+static void
1144+format_POP(const struct ovnact_push_pop *pop, struct ds *s)
1145+{
1146+ ds_put_cstr(s, "pop(");
1147+ expr_field_format(&pop->field, s);
1148+ ds_put_cstr(s, ");");
1149+}
1150+
1151+static void
1152+encode_POP(const struct ovnact_push_pop *pop,
1153+ const struct ovnact_encode_params *ep OVS_UNUSED,
1154+ struct ofpbuf *ofpacts)
1155+{
1156+ ofpact_put_STACK_POP(ofpacts)->subfield =
1157+ expr_resolve_field(&pop->field);
1158+}
1159+
1160+static void
1161+ovnact_push_pop_free(struct ovnact_push_pop *push OVS_UNUSED)
1162+{
1163+}
1164+
1165
1166 static void
1167 parse_DEC_TTL(struct action_context *ctx)
1168 {
1169@@ -1062,7 +1131,7 @@ encode_CT_DNAT_IN_CZONE(const struct ovnact_ct_nat *cn,
1170 const struct ovnact_encode_params *ep,
1171 struct ofpbuf *ofpacts)
1172 {
1173- encode_ct_nat(cn, ep, false, MFF_LOG_NAT_ZONE, ofpacts);
1174+ encode_ct_nat(cn, ep, false, ep->common_nat_ct_zone, ofpacts);
1175 }
1176
1177 static void
1178@@ -1070,7 +1139,7 @@ encode_CT_SNAT_IN_CZONE(const struct ovnact_ct_nat *cn,
1179 const struct ovnact_encode_params *ep,
1180 struct ofpbuf *ofpacts)
1181 {
1182- encode_ct_nat(cn, ep, true, MFF_LOG_NAT_ZONE, ofpacts);
1183+ encode_ct_nat(cn, ep, true, ep->common_nat_ct_zone, ofpacts);
1184 }
1185
1186 static void
1187@@ -1079,7 +1148,7 @@ ovnact_ct_nat_free(struct ovnact_ct_nat *ct_nat OVS_UNUSED)
1188 }
1189
1190
1191 static void
1192-parse_ct_lb_action(struct action_context *ctx)
1193+parse_ct_lb_action(struct action_context *ctx, bool ct_lb_mark)
1194 {
1195 if (ctx->pp->cur_ltable >= ctx->pp->n_tables) {
1196 lexer_error(ctx->lexer, "\"ct_lb\" action not allowed in last table.");
1197@@ -1185,7 +1254,8 @@ parse_ct_lb_action(struct action_context *ctx)
1198 }
1199 }
1200
1201- struct ovnact_ct_lb *cl = ovnact_put_CT_LB(ctx->ovnacts);
1202+ struct ovnact_ct_lb *cl = ct_lb_mark ? ovnact_put_CT_LB_MARK(ctx->ovnacts)
1203+ : ovnact_put_CT_LB(ctx->ovnacts);
1204 cl->ltable = ctx->pp->cur_ltable + 1;
1205 cl->dsts = dsts;
1206 cl->n_dsts = n_dsts;
1207@@ -1193,9 +1263,13 @@ parse_ct_lb_action(struct action_context *ctx)
1208 }
1209
1210 static void
1211-format_CT_LB(const struct ovnact_ct_lb *cl, struct ds *s)
1212+format_ct_lb(const struct ovnact_ct_lb *cl, struct ds *s, bool ct_lb_mark)
1213 {
1214- ds_put_cstr(s, "ct_lb");
1215+ if (ct_lb_mark) {
1216+ ds_put_cstr(s, "ct_lb_mark");
1217+ } else {
1218+ ds_put_cstr(s, "ct_lb");
1219+ }
1220 if (cl->n_dsts) {
1221 ds_put_cstr(s, "(backends=");
1222 for (size_t i = 0; i < cl->n_dsts; i++) {
1223@@ -1231,9 +1305,22 @@ format_CT_LB(const struct ovnact_ct_lb *cl, struct ds *s)
1224 }
1225
1226 static void
1227-encode_CT_LB(const struct ovnact_ct_lb *cl,
1228+format_CT_LB(const struct ovnact_ct_lb *cl, struct ds *s)
1229+{
1230+ format_ct_lb(cl, s, false);
1231+}
1232+
1233+static void
1234+format_CT_LB_MARK(const struct ovnact_ct_lb *cl, struct ds *s)
1235+{
1236+ format_ct_lb(cl, s, true);
1237+}
1238+
1239+static void
1240+encode_ct_lb(const struct ovnact_ct_lb *cl,
1241 const struct ovnact_encode_params *ep,
1242- struct ofpbuf *ofpacts)
1243+ struct ofpbuf *ofpacts,
1244+ bool ct_lb_mark)
1245 {
1246 uint8_t recirc_table = cl->ltable + first_ptable(ep, ep->pipeline);
1247 if (!cl->n_dsts) {
1248@@ -1302,8 +1389,9 @@ encode_CT_LB(const struct ovnact_ct_lb *cl,
1249 ds_put_format(&ds, "),commit,table=%d,zone=NXM_NX_REG%d[0..15],"
1250 "exec(set_field:"
1251 OVN_CT_MASKED_STR(OVN_CT_NATTED)
1252- "->ct_label))",
1253- recirc_table, zone_reg);
1254+ "->%s))",
1255+ recirc_table, zone_reg,
1256+ ct_lb_mark ? "ct_mark" : "ct_label");
1257 }
1258
1259 table_id = ovn_extend_table_assign_id(ep->group_table, ds_cstr(&ds),
1260@@ -1319,6 +1407,22 @@ encode_CT_LB(const struct ovnact_ct_lb *cl,
1261 }
1262
1263 static void
1264+encode_CT_LB(const struct ovnact_ct_lb *cl,
1265+ const struct ovnact_encode_params *ep,
1266+ struct ofpbuf *ofpacts)
1267+{
1268+ encode_ct_lb(cl, ep, ofpacts, false);
1269+}
1270+
1271+static void
1272+encode_CT_LB_MARK(const struct ovnact_ct_lb *cl,
1273+ const struct ovnact_encode_params *ep,
1274+ struct ofpbuf *ofpacts)
1275+{
1276+ encode_ct_lb(cl, ep, ofpacts, true);
1277+}
1278+
1279+static void
1280 ovnact_ct_lb_free(struct ovnact_ct_lb *ct_lb)
1281 {
1282 free(ct_lb->dsts);
1283@@ -2336,7 +2440,7 @@ validate_empty_lb_backends(struct action_context *ctx,
1284
1285 switch (o->option->code) {
1286 case EMPTY_LB_VIP:
1287- if (!inet_parse_active(c->string, 0, &ss, false)) {
1288+ if (!inet_parse_active(c->string, 0, &ss, false, NULL)) {
1289 lexer_error(ctx->lexer, "Invalid load balancer VIP '%s'",
1290 c->string);
1291 return;
1292@@ -4202,6 +4306,10 @@ parse_action(struct action_context *ctx)
1293 parse_set_action(ctx);
1294 } else if (lexer_match_id(ctx->lexer, "next")) {
1295 parse_NEXT(ctx);
1296+ } else if (lexer_match_id(ctx->lexer, "push")) {
1297+ parse_push_pop(ctx, true);
1298+ } else if (lexer_match_id(ctx->lexer, "pop")) {
1299+ parse_push_pop(ctx, false);
1300 } else if (lexer_match_id(ctx->lexer, "output")) {
1301 ovnact_put_OUTPUT(ctx->ovnacts);
1302 } else if (lexer_match_id(ctx->lexer, "ip.ttl")) {
1303@@ -4219,7 +4327,9 @@ parse_action(struct action_context *ctx)
1304 } else if (lexer_match_id(ctx->lexer, "ct_snat_in_czone")) {
1305 parse_CT_SNAT_IN_CZONE(ctx);
1306 } else if (lexer_match_id(ctx->lexer, "ct_lb")) {
1307- parse_ct_lb_action(ctx);
1308+ parse_ct_lb_action(ctx, false);
1309+ } else if (lexer_match_id(ctx->lexer, "ct_lb_mark")) {
1310+ parse_ct_lb_action(ctx, true);
1311 } else if (lexer_match_id(ctx->lexer, "ct_clear")) {
1312 ovnact_put_CT_CLEAR(ctx->ovnacts);
1313 } else if (lexer_match_id(ctx->lexer, "clone")) {
1314diff --git a/lib/expr.c b/lib/expr.c
1315index 47ef610..058390a 100644
1316--- a/lib/expr.c
1317+++ b/lib/expr.c
1318@@ -211,16 +211,17 @@ expr_combine(enum expr_type type, struct expr *a, struct expr *b)
1319 }
1320
1321 static void
1322-expr_insert_andor(struct expr *andor, struct expr *before, struct expr *new)
1323+expr_insert_andor(struct expr *andor, struct ovs_list *before,
1324+ struct expr *new)
1325 {
1326 if (new->type == andor->type) {
1327 if (andor->type == EXPR_T_AND) {
1328 /* Conjunction junction, what's your function? */
1329 }
1330- ovs_list_splice(&before->node, new->andor.next, &new->andor);
1331+ ovs_list_splice(before, new->andor.next, &new->andor);
1332 expr_destroy(new);
1333 } else {
1334- ovs_list_insert(&before->node, &new->node);
1335+ ovs_list_insert(before, &new->node);
1336 }
1337 }
1338
1339@@ -2101,7 +2102,8 @@ expr_annotate__(struct expr *expr, const struct shash *symtab,
1340 expr_destroy(expr);
1341 return NULL;
1342 }
1343- expr_insert_andor(expr, next, new_sub);
1344+ expr_insert_andor(expr, next ? &next->node : &expr->andor,
1345+ new_sub);
1346 }
1347 *errorp = NULL;
1348 return expr;
1349@@ -2301,7 +2303,7 @@ expr_evaluate_condition(struct expr *expr,
1350 struct expr *e = expr_evaluate_condition(sub, is_chassis_resident,
1351 c_aux);
1352 e = expr_fix(e);
1353- expr_insert_andor(expr, next, e);
1354+ expr_insert_andor(expr, next ? &next->node : &expr->andor, e);
1355 }
1356 return expr_fix(expr);
1357
1358@@ -2334,7 +2336,8 @@ expr_simplify(struct expr *expr)
1359 case EXPR_T_OR:
1360 LIST_FOR_EACH_SAFE (sub, next, node, &expr->andor) {
1361 ovs_list_remove(&sub->node);
1362- expr_insert_andor(expr, next, expr_simplify(sub));
1363+ expr_insert_andor(expr, next ? &next->node : &expr->andor,
1364+ expr_simplify(sub));
1365 }
1366 return expr_fix(expr);
1367
1368@@ -2444,12 +2447,13 @@ crush_and_string(struct expr *expr, const struct expr_symbol *symbol)
1369 * EXPR_T_OR with EXPR_T_CMP subexpressions. */
1370 struct expr *sub, *next = NULL;
1371 LIST_FOR_EACH_SAFE (sub, next, node, &expr->andor) {
1372+ struct ovs_list *next_list = next ? &next->node : &expr->andor;
1373 ovs_list_remove(&sub->node);
1374 struct expr *new = crush_cmps(sub, symbol);
1375 switch (new->type) {
1376 case EXPR_T_CMP:
1377 if (!singleton) {
1378- ovs_list_insert(&next->node, &new->node);
1379+ ovs_list_insert(next_list, &new->node);
1380 singleton = new;
1381 } else {
1382 bool match = !strcmp(new->cmp.string, singleton->cmp.string);
1383@@ -2463,7 +2467,7 @@ crush_and_string(struct expr *expr, const struct expr_symbol *symbol)
1384 case EXPR_T_AND:
1385 OVS_NOT_REACHED();
1386 case EXPR_T_OR:
1387- ovs_list_insert(&next->node, &new->node);
1388+ ovs_list_insert(next_list, &new->node);
1389 break;
1390 case EXPR_T_BOOLEAN:
1391 if (!new->boolean) {
1392@@ -2559,7 +2563,7 @@ crush_and_numeric(struct expr *expr, const struct expr_symbol *symbol)
1393 case EXPR_T_AND:
1394 OVS_NOT_REACHED();
1395 case EXPR_T_OR:
1396- ovs_list_insert(&next->node, &new->node);
1397+ ovs_list_insert(next ? &next->node : &expr->andor, &new->node);
1398 break;
1399 case EXPR_T_BOOLEAN:
1400 if (!new->boolean) {
1401@@ -2725,7 +2729,8 @@ crush_or(struct expr *expr, const struct expr_symbol *symbol)
1402 * is now a disjunction of cmps over the same symbol. */
1403 LIST_FOR_EACH_SAFE (sub, next, node, &expr->andor) {
1404 ovs_list_remove(&sub->node);
1405- expr_insert_andor(expr, next, crush_cmps(sub, symbol));
1406+ expr_insert_andor(expr, next ? &next->node : &expr->andor,
1407+ crush_cmps(sub, symbol));
1408 }
1409 expr = expr_fix(expr);
1410 if (expr->type != EXPR_T_OR) {
1411@@ -2886,8 +2891,7 @@ expr_normalize_and(struct expr *expr)
1412
1413 struct expr *a, *b;
1414 LIST_FOR_EACH_SAFE (a, b, node, &expr->andor) {
1415- if (&b->node == &expr->andor
1416- || a->type != EXPR_T_CMP || b->type != EXPR_T_CMP
1417+ if (!b || a->type != EXPR_T_CMP || b->type != EXPR_T_CMP
1418 || a->cmp.symbol != b->cmp.symbol) {
1419 continue;
1420 } else if (a->cmp.symbol->width
1421@@ -2964,7 +2968,8 @@ expr_normalize_or(struct expr *expr)
1422 }
1423 expr_destroy(new);
1424 } else {
1425- expr_insert_andor(expr, next, new);
1426+ expr_insert_andor(expr, next ? &next->node : &expr->andor,
1427+ new);
1428 }
1429 } else {
1430 ovs_assert(sub->type == EXPR_T_CMP ||
1431diff --git a/lib/inc-proc-eng.c b/lib/inc-proc-eng.c
1432index 7b43917..575b774 100644
1433--- a/lib/inc-proc-eng.c
1434+++ b/lib/inc-proc-eng.c
1435@@ -354,14 +354,11 @@ engine_recompute(struct engine_node *node, bool allowed,
1436 const char *reason_fmt, ...)
1437 {
1438 char *reason = NULL;
1439+ va_list reason_args;
1440
1441- if (VLOG_IS_DBG_ENABLED()) {
1442- va_list reason_args;
1443-
1444- va_start(reason_args, reason_fmt);
1445- reason = xvasprintf(reason_fmt, reason_args);
1446- va_end(reason_args);
1447- }
1448+ va_start(reason_args, reason_fmt);
1449+ reason = xvasprintf(reason_fmt, reason_args);
1450+ va_end(reason_args);
1451
1452 if (!allowed) {
1453 VLOG_DBG("node: %s, recompute (%s) aborted", node->name, reason);
1454diff --git a/lib/logical-fields.c b/lib/logical-fields.c
1455index 352a48c..ed3ec62 100644
1456--- a/lib/logical-fields.c
1457+++ b/lib/logical-fields.c
1458@@ -133,6 +133,18 @@ ovn_init_symtab(struct shash *symtab)
1459 /* Connection tracking state. */
1460 expr_symtab_add_field_scoped(symtab, "ct_mark", MFF_CT_MARK, NULL, false,
1461 WR_CT_COMMIT);
1462+ expr_symtab_add_subfield_scoped(symtab, "ct_mark.blocked", NULL,
1463+ "ct_mark["
1464+ OVN_CT_STR(OVN_CT_BLOCKED_BIT)
1465+ "]",
1466+ WR_CT_COMMIT);
1467+ expr_symtab_add_subfield_scoped(symtab, "ct_mark.natted", NULL,
1468+ "ct_mark["
1469+ OVN_CT_STR(OVN_CT_NATTED_BIT)
1470+ "]",
1471+ WR_CT_COMMIT);
1472+ expr_symtab_add_subfield_scoped(symtab, "ct_mark.ecmp_reply_port", NULL,
1473+ "ct_mark[16..31]", WR_CT_COMMIT);
1474
1475 expr_symtab_add_field_scoped(symtab, "ct_label", MFF_CT_LABEL, NULL,
1476 false, WR_CT_COMMIT);
1477@@ -147,7 +159,10 @@ ovn_init_symtab(struct shash *symtab)
1478 "]",
1479 WR_CT_COMMIT);
1480 expr_symtab_add_subfield_scoped(symtab, "ct_label.ecmp_reply_eth", NULL,
1481- "ct_label[32..79]", WR_CT_COMMIT);
1482+ "ct_label["
1483+ OVN_CT_STR(OVN_CT_ECMP_ETH_1ST_BIT) ".."
1484+ OVN_CT_STR(OVN_CT_ECMP_ETH_END_BIT) "]",
1485+ WR_CT_COMMIT);
1486 expr_symtab_add_subfield_scoped(symtab, "ct_label.ecmp_reply_port", NULL,
1487 "ct_label[80..95]", WR_CT_COMMIT);
1488 expr_symtab_add_subfield_scoped(symtab, "ct_label.label", NULL,
1489diff --git a/lib/ovn-parallel-hmap.h b/lib/ovn-parallel-hmap.h
1490index 897208e..0f7d687 100644
1491--- a/lib/ovn-parallel-hmap.h
1492+++ b/lib/ovn-parallel-hmap.h
1493@@ -58,11 +58,11 @@ extern "C" {
1494 * ThreadID + step * i as the JOBID parameter.
1495 */
1496
1497-#define HMAP_FOR_EACH_IN_PARALLEL(NODE, MEMBER, JOBID, HMAP) \
1498- for (INIT_CONTAINER(NODE, hmap_first_in_bucket_num(HMAP, JOBID), MEMBER); \
1499- (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)) \
1500- || ((NODE = NULL), false); \
1501- ASSIGN_CONTAINER(NODE, hmap_next_in_bucket(&(NODE)->MEMBER), MEMBER))
1502+#define HMAP_FOR_EACH_IN_PARALLEL(NODE, MEMBER, JOBID, HMAP) \
1503+ for (INIT_MULTIVAR(NODE, MEMBER, hmap_first_in_bucket_num(HMAP, JOBID), \
1504+ struct hmap_node); \
1505+ CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL); \
1506+ UPDATE_MULTIVAR(NODE, hmap_next_in_bucket(ITER_VAR(NODE))))
1507
1508 /* We do not have a SAFE version of the macro, because the hash size is not
1509 * atomic and hash removal operations would need to be wrapped with
1510diff --git a/lib/ovn-util.c b/lib/ovn-util.c
1511index a22ae84..81f18d6 100644
1512--- a/lib/ovn-util.c
1513+++ b/lib/ovn-util.c
1514@@ -735,7 +735,7 @@ ip_address_and_port_from_lb_key(const char *key, char **ip_address,
1515 uint16_t *port, int *addr_family)
1516 {
1517 struct sockaddr_storage ss;
1518- if (!inet_parse_active(key, 0, &ss, false)) {
1519+ if (!inet_parse_active(key, 0, &ss, false, NULL)) {
1520 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
1521 VLOG_WARN_RL(&rl, "bad ip address or port for load balancer key %s",
1522 key);
1523@@ -754,8 +754,11 @@ ip_address_and_port_from_lb_key(const char *key, char **ip_address,
1524 }
1525
1526 /* Increment this for any logical flow changes, if an existing OVN action is
1527- * modified or a stage is added to a logical pipeline. */
1528-#define OVN_INTERNAL_MINOR_VER 3
1529+ * modified or a stage is added to a logical pipeline.
1530+ *
1531+ * This value is also used to handle some backward compatibility during
1532+ * upgrading. It should never decrease or rewind. */
1533+#define OVN_INTERNAL_MINOR_VER 4
1534
1535 /* Returns the OVN version. The caller must free the returned value. */
1536 char *
1537@@ -766,6 +769,24 @@ ovn_get_internal_version(void)
1538 N_OVNACTS, OVN_INTERNAL_MINOR_VER);
1539 }
1540
1541+unsigned int
1542+ovn_parse_internal_version_minor(const char *ver)
1543+{
1544+ const char *p = ver + strlen(ver);
1545+ for (int i = 0; i < strlen(ver); i++) {
1546+ if (*p == '.') {
1547+ break;
1548+ }
1549+ p--;
1550+ }
1551+
1552+ unsigned int minor;
1553+ if (ovs_scan(p, ".%u", &minor)) {
1554+ return minor;
1555+ }
1556+ return 0;
1557+}
1558+
1559 #ifdef DDLOG
1560 /* Callbacks used by the ddlog northd code to print warnings and errors. */
1561 void
1562diff --git a/lib/ovn-util.h b/lib/ovn-util.h
1563index 1fe91ba..024b86b 100644
1564--- a/lib/ovn-util.h
1565+++ b/lib/ovn-util.h
1566@@ -245,6 +245,10 @@ bool ip_address_and_port_from_lb_key(const char *key, char **ip_address,
1567 * value. */
1568 char *ovn_get_internal_version(void);
1569
1570+/* Parse the provided internal version string and return the "minor" part which
1571+ * is expected to be an unsigned integer followed by the last "." in the
1572+ * string. Returns 0 if the string can't be parsed. */
1573+unsigned int ovn_parse_internal_version_minor(const char *ver);
1574
1575 /* OVN Packet definitions. These may eventually find a home in OVS's
1576 * packets.h file. For the time being, they live here because OVN uses them
1577diff --git a/northd/en-lflow.c b/northd/en-lflow.c
1578index ffbdaf4..fa0dfcb 100644
1579--- a/northd/en-lflow.c
1580+++ b/northd/en-lflow.c
1581@@ -60,6 +60,7 @@ void en_lflow_run(struct engine_node *node, void *data OVS_UNUSED)
1582 lflow_input.meter_groups = &northd_data->meter_groups;
1583 lflow_input.lbs = &northd_data->lbs;
1584 lflow_input.bfd_connections = &northd_data->bfd_connections;
1585+ lflow_input.features = &northd_data->features;
1586 lflow_input.ovn_internal_version_changed =
1587 northd_data->ovn_internal_version_changed;
1588
1589diff --git a/northd/northd.c b/northd/northd.c
1590index b22da67..d06f6a7 100644
1591--- a/northd/northd.c
1592+++ b/northd/northd.c
1593@@ -238,6 +238,17 @@ enum ovn_stage {
1594 /* Register used for setting a label for ACLs in a Logical Switch. */
1595 #define REG_LABEL "reg3"
1596
1597+/* Register used for temporarily store ECMP eth.src to avoid masked ct_label
1598+ * access. It doesn't really occupy registers because the content of the
1599+ * register is saved to stack and then restored in the same flow.
1600+ * Note: the bits must match ct_label.ecmp_reply_eth defined in
1601+ * logical-fields.c */
1602+#define REG_ECMP_ETH_FULL "xxreg1"
1603+#define REG_ECMP_ETH_FIELD REG_ECMP_ETH_FULL "[" \
1604+ OVN_CT_STR(OVN_CT_ECMP_ETH_1ST_BIT) \
1605+ ".." \
1606+ OVN_CT_STR(OVN_CT_ECMP_ETH_END_BIT) "]"
1607+
1608 #define FLAGBIT_NOT_VXLAN "flags[1] == 0"
1609
1610 /*
1611@@ -378,6 +389,23 @@ ovn_stage_to_datapath_type(enum ovn_stage stage)
1612 }
1613 }
1614
1615
1616+static void
1617+build_chassis_features(const struct northd_input *input_data,
1618+ struct chassis_features *chassis_features)
1619+{
1620+ const struct sbrec_chassis *chassis;
1621+
1622+ SBREC_CHASSIS_TABLE_FOR_EACH (chassis, input_data->sbrec_chassis) {
1623+ if (!smap_get_bool(&chassis->other_config,
1624+ OVN_FEATURE_CT_NO_MASKED_LABEL,
1625+ false)) {
1626+ chassis_features->ct_no_masked_label = false;
1627+ return;
1628+ }
1629+ }
1630+ chassis_features->ct_no_masked_label = true;
1631+}
1632+
1633
1634 struct ovn_chassis_qdisc_queues {
1635 struct hmap_node key_node;
1636 uint32_t queue_id;
1637@@ -763,16 +791,6 @@ init_nat_entries(struct ovn_datapath *od)
1638 return;
1639 }
1640
1641- if (od->n_l3dgw_ports > 1) {
1642- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
1643- VLOG_WARN_RL(&rl, "NAT is configured on logical router %s, which has %"
1644- PRIuSIZE" distributed gateway ports. NAT is not supported"
1645- " yet when there is more than one distributed gateway "
1646- "port on the router.",
1647- od->nbr->name, od->n_l3dgw_ports);
1648- return;
1649- }
1650-
1651 od->nat_entries = xmalloc(od->nbr->n_nat * sizeof *od->nat_entries);
1652
1653 for (size_t i = 0; i < od->nbr->n_nat; i++) {
1654@@ -1795,6 +1813,38 @@ lsp_is_router(const struct nbrec_logical_switch_port *nbsp)
1655 }
1656
1657 static bool
1658+lsp_is_type_changed(const struct sbrec_port_binding *sb,
1659+ const struct nbrec_logical_switch_port *nbsp,
1660+ bool *is_old_container_lport)
1661+{
1662+ *is_old_container_lport = false;
1663+ if (!sb || !nbsp) {
1664+ return false;
1665+ }
1666+
1667+ if (!sb->type[0] && !nbsp->type[0]) {
1668+ /* Two "VIF's" interface make sure both have parent_port
1669+ * set or both have parent_port unset, otherwisre they are
1670+ * different ports type.
1671+ */
1672+ if ((!sb->parent_port && nbsp->parent_name) ||
1673+ (sb->parent_port && !nbsp->parent_name)) {
1674+ *is_old_container_lport = true;
1675+ return true;
1676+ } else {
1677+ return false;
1678+ }
1679+ }
1680+
1681+ /* Both lports are not "VIF's" it is safe to use strcmp. */
1682+ if (sb->type[0] && nbsp->type[0]) {
1683+ return strcmp(sb->type, nbsp->type);
1684+ }
1685+
1686+ return true;
1687+}
1688+
1689+static bool
1690 lrport_is_enabled(const struct nbrec_logical_router_port *lrport)
1691 {
1692 return !lrport->enabled || *lrport->enabled;
1693@@ -2474,22 +2524,56 @@ join_logical_ports(struct northd_input *input_data,
1694 VLOG_WARN_RL(&rl, "duplicate logical port %s", nbsp->name);
1695 continue;
1696 } else if (op && (!op->sb || op->sb->datapath == od->sb)) {
1697- ovn_port_set_nb(op, nbsp, NULL);
1698- ovs_list_remove(&op->list);
1699-
1700- uint32_t queue_id = smap_get_int(&op->sb->options,
1701- "qdisc_queue_id", 0);
1702- if (queue_id && op->sb->chassis) {
1703- add_chassis_queue(
1704- chassis_qdisc_queues, &op->sb->chassis->header_.uuid,
1705- queue_id);
1706- }
1707+ /*
1708+ * Handle cases where lport type was explicitly changed
1709+ * in the NBDB, in such cases:
1710+ * 1. remove the current sbrec of the affected lport from
1711+ * the port_binding table.
1712+ *
1713+ * 2. create a new sbrec with the same logical_port as the
1714+ * deleted lport and add it to the nb_only list which
1715+ * will make the northd handle this lport as a new
1716+ * created one and recompute everything that is needed
1717+ * for this lport.
1718+ *
1719+ * This change will affect container lport type changes
1720+ * only for now, this change is needed in container
1721+ * lport cases to avoid port type conflicts in the
1722+ * ovn-controller when the user clears the parent_port
1723+ * field in the container lport.
1724+ *
1725+ * This approach can be applied to all other lport types
1726+ * changes by removing the is_old_container_lport.
1727+ */
1728+ bool is_old_container_lport = false;
1729+ if (op->sb && lsp_is_type_changed(op->sb, nbsp,
1730+ &is_old_container_lport)
1731+ && is_old_container_lport) {
1732+ ovs_list_remove(&op->list);
1733+ sbrec_port_binding_delete(op->sb);
1734+ ovn_port_destroy(ports, op);
1735+ op = ovn_port_create(ports, nbsp->name, nbsp,
1736+ NULL, NULL);
1737+ ovs_list_push_back(nb_only, &op->list);
1738+ } else {
1739+ ovn_port_set_nb(op, nbsp, NULL);
1740+ ovs_list_remove(&op->list);
1741+
1742+ uint32_t queue_id = smap_get_int(&op->sb->options,
1743+ "qdisc_queue_id", 0);
1744+ if (queue_id && op->sb->chassis) {
1745+ add_chassis_queue(
1746+ chassis_qdisc_queues,
1747+ &op->sb->chassis->header_.uuid,
1748+ queue_id);
1749+ }
1750
1751- ovs_list_push_back(both, &op->list);
1752+ ovs_list_push_back(both, &op->list);
1753
1754- /* This port exists due to a SB binding, but should
1755- * not have been initialized fully. */
1756- ovs_assert(!op->n_lsp_addrs && !op->n_ps_addrs);
1757+ /* This port exists due to a SB binding, but should
1758+ * not have been initialized fully. */
1759+ ovs_assert(!op->n_lsp_addrs && !op->n_ps_addrs);
1760+ }
1761 } else {
1762 op = ovn_port_create(ports, nbsp->name, nbsp, NULL, NULL);
1763 ovs_list_push_back(nb_only, &op->list);
1764@@ -3670,12 +3754,13 @@ static bool
1765 build_lb_vip_actions(struct ovn_lb_vip *lb_vip,
1766 struct ovn_northd_lb_vip *lb_vip_nb,
1767 struct ds *action, char *selection_fields,
1768- bool ls_dp)
1769+ bool ls_dp, bool ct_lb_mark)
1770 {
1771+ const char *ct_lb_action = ct_lb_mark ? "ct_lb_mark" : "ct_lb";
1772 bool skip_hash_fields = false, reject = false;
1773
1774 if (lb_vip_nb->lb_health_check) {
1775- ds_put_cstr(action, "ct_lb(backends=");
1776+ ds_put_format(action, "%s(backends=", ct_lb_action);
1777
1778 size_t n_active_backends = 0;
1779 for (size_t i = 0; i < lb_vip->n_backends; i++) {
1780@@ -3708,7 +3793,8 @@ build_lb_vip_actions(struct ovn_lb_vip *lb_vip,
1781 } else if (lb_vip->empty_backend_rej && !lb_vip->n_backends) {
1782 reject = true;
1783 } else {
1784- ds_put_format(action, "ct_lb(backends=%s);", lb_vip_nb->backend_ips);
1785+ ds_put_format(action, "%s(backends=%s);", ct_lb_action,
1786+ lb_vip_nb->backend_ips);
1787 }
1788
1789 if (reject) {
1790@@ -5914,13 +6000,18 @@ build_pre_lb(struct ovn_datapath *od, struct hmap *lflows)
1791 }
1792
1793 static void
1794-build_pre_stateful(struct ovn_datapath *od, struct hmap *lflows)
1795+build_pre_stateful(struct ovn_datapath *od,
1796+ const struct chassis_features *features,
1797+ struct hmap *lflows)
1798 {
1799 /* Ingress and Egress pre-stateful Table (Priority 0): Packets are
1800 * allowed by default. */
1801 ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 0, "1", "next;");
1802 ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_STATEFUL, 0, "1", "next;");
1803
1804+ const char *ct_lb_action = features->ct_no_masked_label
1805+ ? "ct_lb_mark"
1806+ : "ct_lb";
1807 const char *lb_protocols[] = {"tcp", "udp", "sctp"};
1808 struct ds actions = DS_EMPTY_INITIALIZER;
1809 struct ds match = DS_EMPTY_INITIALIZER;
1810@@ -5931,8 +6022,8 @@ build_pre_stateful(struct ovn_datapath *od, struct hmap *lflows)
1811 ds_put_format(&match, REGBIT_CONNTRACK_NAT" == 1 && ip4 && %s",
1812 lb_protocols[i]);
1813 ds_put_format(&actions, REG_ORIG_DIP_IPV4 " = ip4.dst; "
1814- REG_ORIG_TP_DPORT " = %s.dst; ct_lb;",
1815- lb_protocols[i]);
1816+ REG_ORIG_TP_DPORT " = %s.dst; %s;",
1817+ lb_protocols[i], ct_lb_action);
1818 ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 120,
1819 ds_cstr(&match), ds_cstr(&actions));
1820
1821@@ -5941,20 +6032,20 @@ build_pre_stateful(struct ovn_datapath *od, struct hmap *lflows)
1822 ds_put_format(&match, REGBIT_CONNTRACK_NAT" == 1 && ip6 && %s",
1823 lb_protocols[i]);
1824 ds_put_format(&actions, REG_ORIG_DIP_IPV6 " = ip6.dst; "
1825- REG_ORIG_TP_DPORT " = %s.dst; ct_lb;",
1826- lb_protocols[i]);
1827+ REG_ORIG_TP_DPORT " = %s.dst; %s;",
1828+ lb_protocols[i], ct_lb_action);
1829 ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 120,
1830 ds_cstr(&match), ds_cstr(&actions));
1831 }
1832
1833- ds_destroy(&actions);
1834- ds_destroy(&match);
1835+ ds_clear(&actions);
1836+ ds_put_format(&actions, "%s;", ct_lb_action);
1837
1838 ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 110,
1839- REGBIT_CONNTRACK_NAT" == 1", "ct_lb;");
1840+ REGBIT_CONNTRACK_NAT" == 1", ds_cstr(&actions));
1841
1842 ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_STATEFUL, 110,
1843- REGBIT_CONNTRACK_NAT" == 1", "ct_lb;");
1844+ REGBIT_CONNTRACK_NAT" == 1", ds_cstr(&actions));
1845
1846 /* If REGBIT_CONNTRACK_DEFRAG is set as 1, then the packets should be
1847 * sent to conntrack for tracking and defragmentation. */
1848@@ -5963,10 +6054,15 @@ build_pre_stateful(struct ovn_datapath *od, struct hmap *lflows)
1849
1850 ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_STATEFUL, 100,
1851 REGBIT_CONNTRACK_DEFRAG" == 1", "ct_next;");
1852+
1853+ ds_destroy(&actions);
1854+ ds_destroy(&match);
1855 }
1856
1857 static void
1858-build_acl_hints(struct ovn_datapath *od, struct hmap *lflows)
1859+build_acl_hints(struct ovn_datapath *od,
1860+ const struct chassis_features *features,
1861+ struct hmap *lflows)
1862 {
1863 /* This stage builds hints for the IN/OUT_ACL stage. Based on various
1864 * combinations of ct flags packets may hit only a subset of the logical
1865@@ -5988,6 +6084,7 @@ build_acl_hints(struct ovn_datapath *od, struct hmap *lflows)
1866
1867 for (size_t i = 0; i < ARRAY_SIZE(stages); i++) {
1868 enum ovn_stage stage = stages[i];
1869+ const char *match;
1870
1871 /* In any case, advance to the next stage. */
1872 if (!od->has_acls && !od->has_lb_vip) {
1873@@ -6017,8 +6114,10 @@ build_acl_hints(struct ovn_datapath *od, struct hmap *lflows)
1874 * REGBIT_ACL_HINT_ALLOW_NEW.
1875 * - drop ACLs.
1876 */
1877- ovn_lflow_add(lflows, od, stage, 6,
1878- "!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1",
1879+ match = features->ct_no_masked_label
1880+ ? "!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1"
1881+ : "!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1";
1882+ ovn_lflow_add(lflows, od, stage, 6, match,
1883 REGBIT_ACL_HINT_ALLOW_NEW " = 1; "
1884 REGBIT_ACL_HINT_DROP " = 1; "
1885 "next;");
1886@@ -6034,11 +6133,13 @@ build_acl_hints(struct ovn_datapath *od, struct hmap *lflows)
1887 * - allow ACLs in which case the traffic should be allowed so we set
1888 * REGBIT_ACL_HINT_ALLOW.
1889 * - drop ACLs in which case the traffic should be blocked and the
1890- * connection must be committed with ct_label.blocked set so we set
1891+ * connection must be committed with ct_mark.blocked set so we set
1892 * REGBIT_ACL_HINT_BLOCK.
1893 */
1894- ovn_lflow_add(lflows, od, stage, 4,
1895- "!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0",
1896+ match = features->ct_no_masked_label
1897+ ? "!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0"
1898+ : "!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0";
1899+ ovn_lflow_add(lflows, od, stage, 4, match,
1900 REGBIT_ACL_HINT_ALLOW " = 1; "
1901 REGBIT_ACL_HINT_BLOCK " = 1; "
1902 "next;");
1903@@ -6049,15 +6150,21 @@ build_acl_hints(struct ovn_datapath *od, struct hmap *lflows)
1904 ovn_lflow_add(lflows, od, stage, 3, "!ct.est",
1905 REGBIT_ACL_HINT_DROP " = 1; "
1906 "next;");
1907- ovn_lflow_add(lflows, od, stage, 2, "ct.est && ct_label.blocked == 1",
1908+ match = features->ct_no_masked_label
1909+ ? "ct.est && ct_mark.blocked == 1"
1910+ : "ct.est && ct_label.blocked == 1";
1911+ ovn_lflow_add(lflows, od, stage, 2, match,
1912 REGBIT_ACL_HINT_DROP " = 1; "
1913 "next;");
1914
1915 /* Established connections that were previously allowed might hit
1916 * drop ACLs in which case the connection must be committed with
1917- * ct_label.blocked set.
1918+ * ct_mark.blocked set.
1919 */
1920- ovn_lflow_add(lflows, od, stage, 1, "ct.est && ct_label.blocked == 0",
1921+ match = features->ct_no_masked_label
1922+ ? "ct.est && ct_mark.blocked == 0"
1923+ : "ct.est && ct_label.blocked == 0";
1924+ ovn_lflow_add(lflows, od, stage, 1, match,
1925 REGBIT_ACL_HINT_BLOCK " = 1; "
1926 "next;");
1927 }
1928@@ -6183,10 +6290,13 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows,
1929
1930 static void
1931 consider_acl(struct hmap *lflows, struct ovn_datapath *od,
1932- struct nbrec_acl *acl, bool has_stateful,
1933+ struct nbrec_acl *acl, bool has_stateful, bool ct_masked_mark,
1934 const struct shash *meter_groups, struct ds *match,
1935 struct ds *actions)
1936 {
1937+ const char *ct_blocked_match = ct_masked_mark
1938+ ? "ct_mark.blocked"
1939+ : "ct_label.blocked";
1940 bool ingress = !strcmp(acl->direction, "from-lport") ? true :false;
1941 enum ovn_stage stage;
1942
1943@@ -6230,7 +6340,7 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od,
1944 * It's also possible that a known connection was marked for
1945 * deletion after a policy was deleted, but the policy was
1946 * re-added while that connection is still known. We catch
1947- * that case here and un-set ct_label.blocked (which will be done
1948+ * that case here and un-set ct_mark.blocked (which will be done
1949 * by ct_commit in the "stateful" stage) to indicate that the
1950 * connection should be allowed to resume.
1951 */
1952@@ -6281,6 +6391,12 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od,
1953 * the ACL, then we need to ensure that the related and reply
1954 * traffic is logged, so we install a slightly higher-priority
1955 * flow that matches the ACL, allows the traffic, and logs it.
1956+ *
1957+ * Note: Matching the ct_label.label may prevent OVS flow HW
1958+ * offloading to work for some NICs because masked-access of
1959+ * ct_label is not supported on those NICs due to HW
1960+ * limitations. In such case the user may choose to avoid using the
1961+ * "log-related" option.
1962 */
1963 bool log_related = smap_get_bool(&acl->options, "log-related",
1964 false);
1965@@ -6295,10 +6411,10 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od,
1966 ds_clear(actions);
1967
1968 ds_put_format(match, "ct.est && !ct.rel && !ct.new%s && "
1969- "ct.rpl && ct_label.blocked == 0 && "
1970+ "ct.rpl && %s == 0 && "
1971 "ct_label.label == %" PRId64,
1972 use_ct_inv_match ? " && !ct.inv" : "",
1973- acl->label);
1974+ ct_blocked_match, acl->label);
1975 build_acl_log(actions, acl, meter_groups);
1976 ds_put_cstr(actions, "next;");
1977 ovn_lflow_add_with_hint(lflows, od, log_related_stage,
1978@@ -6308,10 +6424,10 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od,
1979
1980 ds_clear(match);
1981 ds_put_format(match, "!ct.est && ct.rel && !ct.new%s && "
1982- "ct_label.blocked == 0 && "
1983+ "%s == 0 && "
1984 "ct_label.label == %" PRId64,
1985 use_ct_inv_match ? " && !ct.inv" : "",
1986- acl->label);
1987+ ct_blocked_match, acl->label);
1988 ovn_lflow_add_with_hint(lflows, od, log_related_stage,
1989 UINT16_MAX - 2,
1990 ds_cstr(match), ds_cstr(actions),
1991@@ -6343,11 +6459,11 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od,
1992 ds_cstr(match), ds_cstr(actions),
1993 &acl->header_);
1994 }
1995- /* For an existing connection without ct_label set, we've
1996+ /* For an existing connection without ct_mark.blocked set, we've
1997 * encountered a policy change. ACLs previously allowed
1998 * this connection and we committed the connection tracking
1999 * entry. Current policy says that we should drop this
2000- * connection. First, we set bit 0 of ct_label to indicate
2001+ * connection. First, we set ct_mark.blocked to indicate
2002 * that this connection is set for deletion. By not
2003 * specifying "next;", we implicitly drop the packet after
2004 * updating conntrack state. We would normally defer
2005@@ -6357,7 +6473,8 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od,
2006 ds_clear(match);
2007 ds_clear(actions);
2008 ds_put_cstr(match, REGBIT_ACL_HINT_BLOCK " == 1");
2009- ds_put_cstr(actions, "ct_commit { ct_label.blocked = 1; }; ");
2010+ ds_put_format(actions, "ct_commit { %s = 1; }; ",
2011+ ct_blocked_match);
2012 if (!strcmp(acl->action, "reject")) {
2013 build_reject_acl_rules(od, lflows, stage, acl, match,
2014 actions, &acl->header_, meter_groups);
2015@@ -6419,6 +6536,72 @@ ovn_port_group_destroy(struct hmap *pgs, struct ovn_port_group *pg)
2016 }
2017
2018 static void
2019+copy_ra_to_sb(struct ovn_port *op, const char *address_mode);
2020+
2021+static void
2022+ovn_update_ipv6_options(struct hmap *ports)
2023+{
2024+ struct ovn_port *op;
2025+ HMAP_FOR_EACH (op, key_node, ports) {
2026+ if (!op->nbrp || op->nbrp->peer || !op->peer) {
2027+ continue;
2028+ }
2029+
2030+ if (!op->lrp_networks.n_ipv6_addrs) {
2031+ continue;
2032+ }
2033+
2034+ struct smap options;
2035+ smap_clone(&options, &op->sb->options);
2036+
2037+ /* enable IPv6 prefix delegation */
2038+ bool prefix_delegation = smap_get_bool(&op->nbrp->options,
2039+ "prefix_delegation", false);
2040+ if (!lrport_is_enabled(op->nbrp)) {
2041+ prefix_delegation = false;
2042+ }
2043+ if (smap_get_bool(&options, "ipv6_prefix_delegation",
2044+ false) != prefix_delegation) {
2045+ smap_add(&options, "ipv6_prefix_delegation",
2046+ prefix_delegation ? "true" : "false");
2047+ }
2048+
2049+ bool ipv6_prefix = smap_get_bool(&op->nbrp->options,
2050+ "prefix", false);
2051+ if (!lrport_is_enabled(op->nbrp)) {
2052+ ipv6_prefix = false;
2053+ }
2054+ if (smap_get_bool(&options, "ipv6_prefix", false) != ipv6_prefix) {
2055+ smap_add(&options, "ipv6_prefix",
2056+ ipv6_prefix ? "true" : "false");
2057+ }
2058+ sbrec_port_binding_set_options(op->sb, &options);
2059+
2060+ smap_destroy(&options);
2061+
2062+ const char *address_mode = smap_get(
2063+ &op->nbrp->ipv6_ra_configs, "address_mode");
2064+
2065+ if (!address_mode) {
2066+ continue;
2067+ }
2068+ if (strcmp(address_mode, "slaac") &&
2069+ strcmp(address_mode, "dhcpv6_stateful") &&
2070+ strcmp(address_mode, "dhcpv6_stateless")) {
2071+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
2072+ VLOG_WARN_RL(&rl, "Invalid address mode [%s] defined",
2073+ address_mode);
2074+ continue;
2075+ }
2076+
2077+ if (smap_get_bool(&op->nbrp->ipv6_ra_configs, "send_periodic",
2078+ false)) {
2079+ copy_ra_to_sb(op, address_mode);
2080+ }
2081+ }
2082+}
2083+
2084+static void
2085 build_port_group_lswitches(struct northd_input *input_data,
2086 struct hmap *pgs,
2087 struct hmap *ports)
2088@@ -6459,10 +6642,14 @@ build_port_group_lswitches(struct northd_input *input_data,
2089 }
2090
2091 static void
2092-build_acls(struct ovn_datapath *od, struct hmap *lflows,
2093- const struct hmap *port_groups, const struct shash *meter_groups)
2094+build_acls(struct ovn_datapath *od, const struct chassis_features *features,
2095+ struct hmap *lflows, const struct hmap *port_groups,
2096+ const struct shash *meter_groups)
2097 {
2098 bool has_stateful = od->has_stateful_acl || od->has_lb_vip;
2099+ const char *ct_blocked_match = features->ct_no_masked_label
2100+ ? "ct_mark.blocked"
2101+ : "ct_label.blocked";
2102 struct ds match = DS_EMPTY_INITIALIZER;
2103 struct ds actions = DS_EMPTY_INITIALIZER;
2104
2105@@ -6498,30 +6685,34 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows,
2106 * subsequent packets will hit the flow at priority 0 that just
2107 * uses "next;"
2108 *
2109- * We also check for established connections that have ct_label.blocked
2110+ * We also check for established connections that have ct_mark.blocked
2111 * set on them. That's a connection that was disallowed, but is
2112 * now allowed by policy again since it hit this default-allow flow.
2113- * We need to set ct_label.blocked=0 to let the connection continue,
2114+ * We need to set ct_mark.blocked=0 to let the connection continue,
2115 * which will be done by ct_commit() in the "stateful" stage.
2116 * Subsequent packets will hit the flow at priority 0 that just
2117 * uses "next;". */
2118+ ds_clear(&match);
2119+ ds_put_format(&match, "ip && (!ct.est || (ct.est && %s == 1))",
2120+ ct_blocked_match);
2121 ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 1,
2122- "ip && (!ct.est || (ct.est && ct_label.blocked == 1))",
2123- REGBIT_CONNTRACK_COMMIT" = 1; next;");
2124+ ds_cstr(&match),
2125+ REGBIT_CONNTRACK_COMMIT" = 1; next;");
2126 ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 1,
2127- "ip && (!ct.est || (ct.est && ct_label.blocked == 1))",
2128- REGBIT_CONNTRACK_COMMIT" = 1; next;");
2129+ ds_cstr(&match),
2130+ REGBIT_CONNTRACK_COMMIT" = 1; next;");
2131
2132 /* Ingress and Egress ACL Table (Priority 65532).
2133 *
2134 * Always drop traffic that's in an invalid state. Also drop
2135 * reply direction packets for connections that have been marked
2136- * for deletion (bit 0 of ct_label is set).
2137+ * for deletion (ct_mark.blocked is set).
2138 *
2139 * This is enforced at a higher priority than ACLs can be defined. */
2140 ds_clear(&match);
2141- ds_put_format(&match, "%s(ct.est && ct.rpl && ct_label.blocked == 1)",
2142- use_ct_inv_match ? "ct.inv || " : "");
2143+ ds_put_format(&match, "%s(ct.est && ct.rpl && %s == 1)",
2144+ use_ct_inv_match ? "ct.inv || " : "",
2145+ ct_blocked_match);
2146 ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3,
2147 ds_cstr(&match), "drop;");
2148 ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3,
2149@@ -6531,15 +6722,16 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows,
2150 *
2151 * Allow reply traffic that is part of an established
2152 * conntrack entry that has not been marked for deletion
2153- * (bit 0 of ct_label). We only match traffic in the
2154+ * (ct_mark.blocked). We only match traffic in the
2155 * reply direction because we want traffic in the request
2156 * direction to hit the currently defined policy from ACLs.
2157 *
2158 * This is enforced at a higher priority than ACLs can be defined. */
2159 ds_clear(&match);
2160 ds_put_format(&match, "ct.est && !ct.rel && !ct.new%s && "
2161- "ct.rpl && ct_label.blocked == 0",
2162- use_ct_inv_match ? " && !ct.inv" : "");
2163+ "ct.rpl && %s == 0",
2164+ use_ct_inv_match ? " && !ct.inv" : "",
2165+ ct_blocked_match);
2166 ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3,
2167 ds_cstr(&match), REGBIT_ACL_HINT_DROP" = 0; "
2168 REGBIT_ACL_HINT_BLOCK" = 0; next;");
2169@@ -6549,7 +6741,7 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows,
2170 /* Ingress and Egress ACL Table (Priority 65535).
2171 *
2172 * Allow traffic that is related to an existing conntrack entry that
2173- * has not been marked for deletion (bit 0 of ct_label).
2174+ * has not been marked for deletion (ct_mark.blocked).
2175 *
2176 * This is enforced at a higher priority than ACLs can be defined.
2177 *
2178@@ -6558,9 +6750,9 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows,
2179 * related traffic such as an ICMP Port Unreachable through
2180 * that's generated from a non-listening UDP port. */
2181 ds_clear(&match);
2182- ds_put_format(&match, "!ct.est && ct.rel && !ct.new%s && "
2183- "ct_label.blocked == 0",
2184- use_ct_inv_match ? " && !ct.inv" : "");
2185+ ds_put_format(&match, "!ct.est && ct.rel && !ct.new%s && %s == 0",
2186+ use_ct_inv_match ? " && !ct.inv" : "",
2187+ ct_blocked_match);
2188 ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3,
2189 ds_cstr(&match), "next;");
2190 ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3,
2191@@ -6578,14 +6770,16 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows,
2192 /* Ingress or Egress ACL Table (Various priorities). */
2193 for (size_t i = 0; i < od->nbs->n_acls; i++) {
2194 struct nbrec_acl *acl = od->nbs->acls[i];
2195- consider_acl(lflows, od, acl, has_stateful, meter_groups, &match,
2196- &actions);
2197+ consider_acl(lflows, od, acl, has_stateful,
2198+ features->ct_no_masked_label,
2199+ meter_groups, &match, &actions);
2200 }
2201 struct ovn_port_group *pg;
2202 HMAP_FOR_EACH (pg, key_node, port_groups) {
2203 if (ovn_port_group_ls_find(pg, &od->nbs->header_.uuid)) {
2204 for (size_t i = 0; i < pg->nb_pg->n_acls; i++) {
2205 consider_acl(lflows, od, pg->nb_pg->acls[i], has_stateful,
2206+ features->ct_no_masked_label,
2207 meter_groups, &match, &actions);
2208 }
2209 }
2210@@ -6737,7 +6931,7 @@ build_qos(struct ovn_datapath *od, struct hmap *lflows) {
2211 }
2212
2213 static void
2214-build_lb_rules(struct hmap *lflows, struct ovn_northd_lb *lb,
2215+build_lb_rules(struct hmap *lflows, struct ovn_northd_lb *lb, bool ct_lb_mark,
2216 struct ds *match, struct ds *action,
2217 const struct shash *meter_groups)
2218 {
2219@@ -6787,7 +6981,8 @@ build_lb_rules(struct hmap *lflows, struct ovn_northd_lb *lb,
2220 /* New connections in Ingress table. */
2221 const char *meter = NULL;
2222 bool reject = build_lb_vip_actions(lb_vip, lb_vip_nb, action,
2223- lb->selection_fields, true);
2224+ lb->selection_fields, true,
2225+ ct_lb_mark);
2226
2227 ds_put_format(match, "ct.new && %s.dst == %s", ip_match,
2228 lb_vip->vip_str);
2229@@ -6809,21 +7004,29 @@ build_lb_rules(struct hmap *lflows, struct ovn_northd_lb *lb,
2230 if (reject) {
2231 meter = copp_meter_get(COPP_REJECT, od->nbs->copp,
2232 meter_groups);
2233- } else if (ovn_dp_group_add_with_reference(lflow_ref, od)) {
2234- continue;
2235 }
2236- lflow_ref = ovn_lflow_add_at_with_hash(lflows, od,
2237- S_SWITCH_IN_LB, priority,
2238- ds_cstr(match), ds_cstr(action),
2239- NULL, meter, &lb->nlb->header_,
2240- OVS_SOURCE_LOCATOR, hash);
2241+ if (meter || !ovn_dp_group_add_with_reference(lflow_ref, od)) {
2242+ struct ovn_lflow *lflow = ovn_lflow_add_at_with_hash(
2243+ lflows, od, S_SWITCH_IN_LB, priority,
2244+ ds_cstr(match), ds_cstr(action),
2245+ NULL, meter, &lb->nlb->header_,
2246+ OVS_SOURCE_LOCATOR, hash);
2247+ lflow_ref = meter ? NULL : lflow;
2248+ }
2249 }
2250 }
2251 }
2252
2253 static void
2254-build_stateful(struct ovn_datapath *od, struct hmap *lflows)
2255+build_stateful(struct ovn_datapath *od,
2256+ const struct chassis_features *features,
2257+ struct hmap *lflows)
2258 {
2259+ const char *ct_block_action = features->ct_no_masked_label
2260+ ? "ct_mark.blocked"
2261+ : "ct_label.blocked";
2262+ struct ds actions = DS_EMPTY_INITIALIZER;
2263+
2264 /* Ingress LB, Ingress and Egress stateful Table (Priority 0): Packets are
2265 * allowed by default. */
2266 ovn_lflow_add(lflows, od, S_SWITCH_IN_LB, 0, "1", "next;");
2267@@ -6836,29 +7039,33 @@ build_stateful(struct ovn_datapath *od, struct hmap *lflows)
2268 * We always set ct_mark.blocked to 0 here as
2269 * any packet that makes it this far is part of a connection we
2270 * want to allow to continue. */
2271+ ds_put_format(&actions, "ct_commit { %s = 0; "
2272+ "ct_label.label = " REG_LABEL "; }; next;",
2273+ ct_block_action);
2274 ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, 100,
2275 REGBIT_CONNTRACK_COMMIT" == 1 && "
2276 REGBIT_ACL_LABEL" == 1",
2277- "ct_commit { ct_label.blocked = 0; "
2278- "ct_label.label = " REG_LABEL "; }; next;");
2279+ ds_cstr(&actions));
2280 ovn_lflow_add(lflows, od, S_SWITCH_OUT_STATEFUL, 100,
2281 REGBIT_CONNTRACK_COMMIT" == 1 && "
2282 REGBIT_ACL_LABEL" == 1",
2283- "ct_commit { ct_label.blocked = 0; "
2284- "ct_label.label = " REG_LABEL "; }; next;");
2285+ ds_cstr(&actions));
2286
2287 /* If REGBIT_CONNTRACK_COMMIT is set as 1, then the packets should be
2288- * committed to conntrack. We always set ct_label.blocked to 0 here as
2289+ * committed to conntrack. We always set ct_mark.blocked to 0 here as
2290 * any packet that makes it this far is part of a connection we
2291 * want to allow to continue. */
2292+ ds_clear(&actions);
2293+ ds_put_format(&actions, "ct_commit { %s = 0; }; next;", ct_block_action);
2294 ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, 100,
2295 REGBIT_CONNTRACK_COMMIT" == 1 && "
2296 REGBIT_ACL_LABEL" == 0",
2297- "ct_commit { ct_label.blocked = 0; }; next;");
2298+ ds_cstr(&actions));
2299 ovn_lflow_add(lflows, od, S_SWITCH_OUT_STATEFUL, 100,
2300 REGBIT_CONNTRACK_COMMIT" == 1 && "
2301 REGBIT_ACL_LABEL" == 0",
2302- "ct_commit { ct_label.blocked = 0; }; next;");
2303+ ds_cstr(&actions));
2304+ ds_destroy(&actions);
2305 }
2306
2307 static void
2308@@ -7596,6 +7803,7 @@ build_lswitch_flows(const struct hmap *datapaths,
2309 static void
2310 build_lswitch_lflows_pre_acl_and_acl(struct ovn_datapath *od,
2311 const struct hmap *port_groups,
2312+ const struct chassis_features *features,
2313 struct hmap *lflows,
2314 const struct shash *meter_groups)
2315 {
2316@@ -7604,11 +7812,11 @@ build_lswitch_lflows_pre_acl_and_acl(struct ovn_datapath *od,
2317
2318 build_pre_acls(od, port_groups, lflows);
2319 build_pre_lb(od, lflows);
2320- build_pre_stateful(od, lflows);
2321- build_acl_hints(od, lflows);
2322- build_acls(od, lflows, port_groups, meter_groups);
2323+ build_pre_stateful(od, features, lflows);
2324+ build_acl_hints(od, features, lflows);
2325+ build_acls(od, features, lflows, port_groups, meter_groups);
2326 build_qos(od, lflows);
2327- build_stateful(od, lflows);
2328+ build_stateful(od, features, lflows);
2329 build_lb_hairpin(od, lflows);
2330 }
2331 }
2332@@ -9303,6 +9511,7 @@ find_static_route_outport(struct ovn_datapath *od, const struct hmap *ports,
2333 static void
2334 add_ecmp_symmetric_reply_flows(struct hmap *lflows,
2335 struct ovn_datapath *od,
2336+ bool ct_masked_mark,
2337 const char *port_ip,
2338 struct ovn_port *out_port,
2339 const struct parsed_route *route,
2340@@ -9313,6 +9522,9 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows,
2341 struct ds actions = DS_EMPTY_INITIALIZER;
2342 struct ds ecmp_reply = DS_EMPTY_INITIALIZER;
2343 char *cidr = normalize_v46_prefix(&route->prefix, route->plen);
2344+ const char *ct_ecmp_reply_port_match = ct_masked_mark
2345+ ? "ct_mark.ecmp_reply_port"
2346+ : "ct_label.ecmp_reply_port";
2347
2348 /* If symmetric ECMP replies are enabled, then packets that arrive over
2349 * an ECMP route need to go through conntrack.
2350@@ -9341,8 +9553,8 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows,
2351 ds_put_cstr(&match, " && (ct.new && !ct.est)");
2352
2353 ds_put_format(&actions, "ct_commit { ct_label.ecmp_reply_eth = eth.src;"
2354- " ct_label.ecmp_reply_port = %" PRId64 ";}; next;",
2355- out_port->sb->tunnel_key);
2356+ " %s = %" PRId64 ";}; next;",
2357+ ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
2358 ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
2359 ds_cstr(&match), ds_cstr(&actions),
2360 &st_route->header_);
2361@@ -9350,8 +9562,8 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows,
2362 /* Bypass ECMP selection if we already have ct_label information
2363 * for where to route the packet.
2364 */
2365- ds_put_format(&ecmp_reply, "ct.rpl && ct_label.ecmp_reply_port == %"
2366- PRId64, out_port->sb->tunnel_key);
2367+ ds_put_format(&ecmp_reply, "ct.rpl && %s == %"PRId64,
2368+ ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
2369 ds_clear(&match);
2370 ds_put_format(&match, "%s && %s", ds_cstr(&ecmp_reply),
2371 ds_cstr(route_match));
2372@@ -9370,7 +9582,18 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows,
2373 ds_cstr(&ecmp_reply), "next;",
2374 &st_route->header_);
2375
2376- const char *action = "eth.dst = ct_label.ecmp_reply_eth; next;";
2377+ /* Use REG_ECMP_ETH_FULL to pass the eth field from ct_label to eth.dst to
2378+ * avoid masked access to ct_label. Otherwise it may prevent OVS flow
2379+ * HW offloading to work for some NICs because masked-access of ct_label is
2380+ * not supported on those NICs due to HW limitations.
2381+ *
2382+ * Use push/pop to save the value of the register before using it and
2383+ * restore it immediately afterwards, so that the use of the register is
2384+ * temporary and doesn't interfere with other stages. */
2385+ const char *action = "push(" REG_ECMP_ETH_FULL "); "
2386+ REG_ECMP_ETH_FULL " = ct_label;"
2387+ " eth.dst = " REG_ECMP_ETH_FIELD ";"
2388+ " pop(" REG_ECMP_ETH_FULL "); next;";
2389 ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ARP_RESOLVE,
2390 200, ds_cstr(&ecmp_reply),
2391 action, &st_route->header_);
2392@@ -9382,7 +9605,8 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows,
2393
2394 static void
2395 build_ecmp_route_flow(struct hmap *lflows, struct ovn_datapath *od,
2396- const struct hmap *ports, struct ecmp_groups_node *eg)
2397+ bool ct_masked_mark, const struct hmap *ports,
2398+ struct ecmp_groups_node *eg)
2399
2400 {
2401 bool is_ipv4 = IN6_IS_ADDR_V4MAPPED(&eg->prefix);
2402@@ -9436,7 +9660,8 @@ build_ecmp_route_flow(struct hmap *lflows, struct ovn_datapath *od,
2403 if (smap_get(&od->nbr->options, "chassis") &&
2404 route_->ecmp_symmetric_reply && sset_add(&visited_ports,
2405 out_port->key)) {
2406- add_ecmp_symmetric_reply_flows(lflows, od, lrp_addr_s, out_port,
2407+ add_ecmp_symmetric_reply_flows(lflows, od, ct_masked_mark,
2408+ lrp_addr_s, out_port,
2409 route_, &route_match);
2410 }
2411 ds_clear(&match);
2412@@ -9631,8 +9856,10 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
2413 struct ovn_northd_lb_vip *vips_nb,
2414 struct hmap *lflows,
2415 struct ds *match, struct ds *action,
2416- const struct shash *meter_groups)
2417+ const struct shash *meter_groups,
2418+ bool ct_lb_mark)
2419 {
2420+ const char *ct_natted = ct_lb_mark ? "ct_mark.natted" : "ct_label.natted";
2421 char *skip_snat_new_action = NULL;
2422 char *skip_snat_est_action = NULL;
2423 char *new_match;
2424@@ -9642,12 +9869,13 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
2425 ds_clear(action);
2426
2427 bool reject = build_lb_vip_actions(lb_vip, vips_nb, action,
2428- lb->selection_fields, false);
2429+ lb->selection_fields, false,
2430+ ct_lb_mark);
2431
2432 /* Higher priority rules are added for load-balancing in DNAT
2433 * table. For every match (on a VIP[:port]), we add two flows.
2434 * One flow is for specific matching on ct.new with an action
2435- * of "ct_lb($targets);". The other flow is for ct.est with
2436+ * of "ct_lb_mark($targets);". The other flow is for ct.est with
2437 * an action of "next;".
2438 */
2439 if (IN6_IS_ADDR_V4MAPPED(&lb_vip->vip)) {
2440@@ -9674,13 +9902,13 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
2441 REG_ORIG_TP_DPORT_ROUTER" == %d",
2442 ds_cstr(match), lb->proto, lb_vip->vip_port);
2443 est_match = xasprintf("ct.est && %s && %s && "
2444- REG_ORIG_TP_DPORT_ROUTER" == %d && "
2445- "ct_label.natted == 1",
2446- ds_cstr(match), lb->proto, lb_vip->vip_port);
2447+ REG_ORIG_TP_DPORT_ROUTER" == %d && %s == 1",
2448+ ds_cstr(match), lb->proto, lb_vip->vip_port,
2449+ ct_natted);
2450 } else {
2451 new_match = xasprintf("ct.new && %s", ds_cstr(match));
2452- est_match = xasprintf("ct.est && %s && ct_label.natted == 1",
2453- ds_cstr(match));
2454+ est_match = xasprintf("ct.est && %s && %s == 1",
2455+ ds_cstr(match), ct_natted);
2456 }
2457
2458 const char *ip_match = NULL;
2459@@ -9841,8 +10069,9 @@ next:
2460
2461 static void
2462 build_lswitch_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows,
2463- const struct shash *meter_groups, struct ds *match,
2464- struct ds *action)
2465+ const struct shash *meter_groups,
2466+ const struct chassis_features *features,
2467+ struct ds *match, struct ds *action)
2468 {
2469 if (!lb->n_nb_ls) {
2470 return;
2471@@ -9878,7 +10107,8 @@ build_lswitch_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows,
2472 * a higher priority rule for load balancing below also commits the
2473 * connection, so it is okay if we do not hit the above match on
2474 * REGBIT_CONNTRACK_COMMIT. */
2475- build_lb_rules(lflows, lb, match, action, meter_groups);
2476+ build_lb_rules(lflows, lb, features->ct_no_masked_label,
2477+ match, action, meter_groups);
2478 }
2479
2480 /* If there are any load balancing rules, we should send the packet to
2481@@ -9948,8 +10178,9 @@ build_lrouter_defrag_flows_for_lb(struct ovn_northd_lb *lb,
2482
2483 static void
2484 build_lrouter_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows,
2485- const struct shash *meter_groups, struct ds *match,
2486- struct ds *action)
2487+ const struct shash *meter_groups,
2488+ const struct chassis_features *features,
2489+ struct ds *match, struct ds *action)
2490 {
2491 if (!lb->n_nb_lr) {
2492 return;
2493@@ -9959,8 +10190,8 @@ build_lrouter_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows,
2494 struct ovn_lb_vip *lb_vip = &lb->vips[i];
2495
2496 build_lrouter_nat_flows_for_lb(lb_vip, lb, &lb->vips_nb[i],
2497- lflows, match, action,
2498- meter_groups);
2499+ lflows, match, action, meter_groups,
2500+ features->ct_no_masked_label);
2501
2502 if (!build_empty_lb_event_flow(lb_vip, lb->nlb, match, action)) {
2503 continue;
2504@@ -10100,7 +10331,7 @@ static inline void
2505 lrouter_nat_add_ext_ip_match(struct ovn_datapath *od,
2506 struct hmap *lflows, struct ds *match,
2507 const struct nbrec_nat *nat,
2508- bool is_v6, bool is_src, ovs_be32 mask)
2509+ bool is_v6, bool is_src, int cidr_bits)
2510 {
2511 struct nbrec_address_set *allowed_ext_ips = nat->allowed_ext_ips;
2512 struct nbrec_address_set *exempted_ext_ips = nat->exempted_ext_ips;
2513@@ -10136,7 +10367,7 @@ lrouter_nat_add_ext_ip_match(struct ovn_datapath *od,
2514 priority = 100 + 2;
2515 } else {
2516 /* S_ROUTER_OUT_SNAT uses priority (mask + 1 + 128 + 1) */
2517- priority = count_1bits(ntohl(mask)) + 3;
2518+ priority = cidr_bits + 3;
2519
2520 if (!od->is_gw_router) {
2521 priority += 128;
2522@@ -10576,6 +10807,28 @@ build_adm_ctrl_flows_for_lrouter(
2523 }
2524 }
2525
2526+static int
2527+build_gateway_get_l2_hdr_size(struct ovn_port *op)
2528+{
2529+ struct ovn_port *peer = op->peer;
2530+
2531+ if (peer && peer->od && peer->od->nbs) {
2532+ /* Check if vlans are enabled on a localnet port running the logical
2533+ * switch connected to this logical router.
2534+ */
2535+ for (size_t i = 0; i < peer->od->n_localnet_ports; i++) {
2536+ struct ovn_port *localnet_port = peer->od->localnet_ports[i];
2537+ const struct nbrec_logical_switch_port *nbsp = localnet_port->nbsp;
2538+
2539+ if (nbsp && nbsp->n_tag_request > 0) {
2540+ return VLAN_ETH_HEADER_LEN;
2541+ }
2542+ }
2543+ }
2544+
2545+ return ETH_HEADER_LEN;
2546+}
2547+
2548 /* All 'gateway_mtu' and 'gateway_mtu_bypass' flows should be built with this
2549 * function.
2550 */
2551@@ -10593,8 +10846,9 @@ build_gateway_mtu_flow(struct hmap *lflows, struct ovn_port *op,
2552
2553 ds_clear(actions);
2554 if (gw_mtu > 0) {
2555+ int l2_hdr_size = build_gateway_get_l2_hdr_size(op);
2556 ds_put_format(actions, REGBIT_PKT_LARGER" = check_pkt_larger(%d); ",
2557- gw_mtu + VLAN_ETH_HEADER_LEN);
2558+ gw_mtu + l2_hdr_size);
2559 }
2560
2561 ds_put_format_valist(actions, extra_actions_fmt, extra_actions_args);
2562@@ -10759,6 +11013,12 @@ build_neigh_learning_flows_for_lrouter(
2563 copp_meter_get(COPP_ARP, od->nbr->copp,
2564 meter_groups));
2565
2566+ ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 95,
2567+ "nd_na && nd.tll == 0",
2568+ "put_nd(inport, nd.target, eth.src); next;",
2569+ copp_meter_get(COPP_ND_NA, od->nbr->copp,
2570+ meter_groups));
2571+
2572 ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90,
2573 "nd_na", "put_nd(inport, nd.target, nd.tll); next;",
2574 copp_meter_get(COPP_ND_NA, od->nbr->copp,
2575@@ -10851,34 +11111,6 @@ build_ND_RA_flows_for_lrouter_port(
2576 return;
2577 }
2578
2579- struct smap options;
2580- smap_clone(&options, &op->sb->options);
2581-
2582- /* enable IPv6 prefix delegation */
2583- bool prefix_delegation = smap_get_bool(&op->nbrp->options,
2584- "prefix_delegation", false);
2585- if (!lrport_is_enabled(op->nbrp)) {
2586- prefix_delegation = false;
2587- }
2588- if (smap_get_bool(&options, "ipv6_prefix_delegation",
2589- false) != prefix_delegation) {
2590- smap_add(&options, "ipv6_prefix_delegation",
2591- prefix_delegation ? "true" : "false");
2592- }
2593-
2594- bool ipv6_prefix = smap_get_bool(&op->nbrp->options,
2595- "prefix", false);
2596- if (!lrport_is_enabled(op->nbrp)) {
2597- ipv6_prefix = false;
2598- }
2599- if (smap_get_bool(&options, "ipv6_prefix", false) != ipv6_prefix) {
2600- smap_add(&options, "ipv6_prefix",
2601- ipv6_prefix ? "true" : "false");
2602- }
2603- sbrec_port_binding_set_options(op->sb, &options);
2604-
2605- smap_destroy(&options);
2606-
2607 const char *address_mode = smap_get(
2608 &op->nbrp->ipv6_ra_configs, "address_mode");
2609
2610@@ -10894,11 +11126,6 @@ build_ND_RA_flows_for_lrouter_port(
2611 return;
2612 }
2613
2614- if (smap_get_bool(&op->nbrp->ipv6_ra_configs, "send_periodic",
2615- false)) {
2616- copy_ra_to_sb(op, address_mode);
2617- }
2618-
2619 ds_clear(match);
2620 ds_put_format(match, "inport == %s && ip6.dst == ff02::2 && nd_rs",
2621 op->json_key);
2622@@ -11072,8 +11299,9 @@ build_ip_routing_flows_for_lrouter_port(
2623
2624 static void
2625 build_static_route_flows_for_lrouter(
2626- struct ovn_datapath *od, struct hmap *lflows,
2627- const struct hmap *ports, const struct hmap *bfd_connections)
2628+ struct ovn_datapath *od, const struct chassis_features *features,
2629+ struct hmap *lflows, const struct hmap *ports,
2630+ const struct hmap *bfd_connections)
2631 {
2632 if (od->nbr) {
2633 ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP, 150,
2634@@ -11116,7 +11344,8 @@ build_static_route_flows_for_lrouter(
2635 HMAP_FOR_EACH (group, hmap_node, &ecmp_groups) {
2636 /* add a flow in IP_ROUTING, and one flow for each member in
2637 * IP_ROUTING_ECMP. */
2638- build_ecmp_route_flow(lflows, od, ports, group);
2639+ build_ecmp_route_flow(lflows, od, features->ct_no_masked_label,
2640+ ports, group);
2641 }
2642 const struct unique_routes_node *ur;
2643 HMAP_FOR_EACH (ur, hmap_node, &unique_routes) {
2644@@ -11815,6 +12044,23 @@ build_gateway_redirect_flows_for_lrouter(
2645 ds_cstr(match), ds_cstr(actions),
2646 stage_hint);
2647 }
2648+
2649+ for (int i = 0; i < od->n_nat_entries; i++) {
2650+ const struct ovn_nat *nat = &od->nat_entries[i];
2651+
2652+ if (!lrouter_nat_is_stateless(nat->nb) ||
2653+ strcmp(nat->nb->type, "dnat_and_snat")) {
2654+ continue;
2655+ }
2656+
2657+ ds_clear(match);
2658+ ds_put_format(match, "ip && ip%s.dst == %s",
2659+ nat_entry_is_v6(nat) ? "6" : "4",
2660+ nat->nb->external_ip);
2661+ ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 100,
2662+ ds_cstr(match), "drop;");
2663+ }
2664+
2665 /* Packets are allowed by default. */
2666 ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 0, "1", "next;");
2667 }
2668@@ -12553,8 +12799,7 @@ build_lrouter_in_unsnat_flow(struct hmap *lflows, struct ovn_datapath *od,
2669 ds_put_format(match, "ip && ip%s.dst == %s",
2670 is_v6 ? "6" : "4", nat->external_ip);
2671 if (!strcmp(nat->type, "dnat_and_snat") && stateless) {
2672- ds_put_format(actions, "ip%s.dst=%s; next;",
2673- is_v6 ? "6" : "4", nat->logical_ip);
2674+ ds_put_format(actions, "next;");
2675 } else {
2676 ds_put_cstr(actions, "ct_snat;");
2677 }
2678@@ -12579,8 +12824,7 @@ build_lrouter_in_unsnat_flow(struct hmap *lflows, struct ovn_datapath *od,
2679 }
2680
2681 if (!strcmp(nat->type, "dnat_and_snat") && stateless) {
2682- ds_put_format(actions, "ip%s.dst=%s; next;",
2683- is_v6 ? "6" : "4", nat->logical_ip);
2684+ ds_put_format(actions, "next;");
2685 } else {
2686 ds_put_cstr(actions, "ct_snat_in_czone;");
2687 }
2688@@ -12614,7 +12858,7 @@ static void
2689 build_lrouter_in_dnat_flow(struct hmap *lflows, struct ovn_datapath *od,
2690 const struct nbrec_nat *nat, struct ds *match,
2691 struct ds *actions, bool distributed,
2692- ovs_be32 mask, bool is_v6)
2693+ int cidr_bits, bool is_v6)
2694 {
2695 /* Ingress DNAT table: Packets enter the pipeline with destination
2696 * IP address that needs to be DNATted from a external IP address
2697@@ -12632,7 +12876,7 @@ build_lrouter_in_dnat_flow(struct hmap *lflows, struct ovn_datapath *od,
2698 ds_clear(actions);
2699 if (nat->allowed_ext_ips || nat->exempted_ext_ips) {
2700 lrouter_nat_add_ext_ip_match(od, lflows, match, nat,
2701- is_v6, true, mask);
2702+ is_v6, true, cidr_bits);
2703 }
2704
2705 if (!lport_addresses_is_empty(&od->dnat_force_snat_addrs)) {
2706@@ -12676,7 +12920,7 @@ build_lrouter_in_dnat_flow(struct hmap *lflows, struct ovn_datapath *od,
2707 ds_clear(actions);
2708 if (nat->allowed_ext_ips || nat->exempted_ext_ips) {
2709 lrouter_nat_add_ext_ip_match(od, lflows, match, nat,
2710- is_v6, true, mask);
2711+ is_v6, true, cidr_bits);
2712 }
2713
2714 if (!strcmp(nat->type, "dnat_and_snat") && stateless) {
2715@@ -12733,8 +12977,7 @@ build_lrouter_out_undnat_flow(struct hmap *lflows, struct ovn_datapath *od,
2716
2717 if (!strcmp(nat->type, "dnat_and_snat") &&
2718 lrouter_nat_is_stateless(nat)) {
2719- ds_put_format(actions, "ip%s.src=%s; next;",
2720- is_v6 ? "6" : "4", nat->external_ip);
2721+ ds_put_format(actions, "next;");
2722 } else {
2723 ds_put_format(actions,
2724 od->is_gw_router ? "ct_dnat;" : "ct_dnat_in_czone;");
2725@@ -12779,8 +13022,7 @@ static void
2726 build_lrouter_out_snat_flow(struct hmap *lflows, struct ovn_datapath *od,
2727 const struct nbrec_nat *nat, struct ds *match,
2728 struct ds *actions, bool distributed,
2729- struct eth_addr mac, ovs_be32 mask,
2730- int cidr_bits, bool is_v6)
2731+ struct eth_addr mac, int cidr_bits, bool is_v6)
2732 {
2733 /* Egress SNAT table: Packets enter the egress pipeline with
2734 * source ip address that needs to be SNATted to a external ip
2735@@ -12798,13 +13040,14 @@ build_lrouter_out_snat_flow(struct hmap *lflows, struct ovn_datapath *od,
2736
2737 if (nat->allowed_ext_ips || nat->exempted_ext_ips) {
2738 lrouter_nat_add_ext_ip_match(od, lflows, match, nat,
2739- is_v6, false, mask);
2740+ is_v6, false, cidr_bits);
2741 }
2742
2743 if (!strcmp(nat->type, "dnat_and_snat") && stateless) {
2744 ds_put_format(actions, "ip%s.src=%s; next;",
2745 is_v6 ? "6" : "4", nat->external_ip);
2746 } else {
2747+ ds_put_format(match, " && (!ct.trk || !ct.rpl)");
2748 ds_put_format(actions, "ct_snat(%s", nat->external_ip);
2749
2750 if (nat->external_port_range[0]) {
2751@@ -12846,7 +13089,7 @@ build_lrouter_out_snat_flow(struct hmap *lflows, struct ovn_datapath *od,
2752
2753 if (nat->allowed_ext_ips || nat->exempted_ext_ips) {
2754 lrouter_nat_add_ext_ip_match(od, lflows, match, nat,
2755- is_v6, false, mask);
2756+ is_v6, false, cidr_bits);
2757 }
2758
2759 if (distributed) {
2760@@ -13155,6 +13398,18 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows,
2761 return;
2762 }
2763
2764+ /* NAT rules are not currently supported on logical routers with multiple
2765+ * distributed gateway ports. */
2766+ if (od->n_l3dgw_ports > 1) {
2767+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
2768+ VLOG_WARN_RL(&rl, "NAT is configured on logical router %s, which has %"
2769+ PRIuSIZE" distributed gateway ports. NAT is not supported"
2770+ " yet when there is more than one distributed gateway "
2771+ "port on the router.",
2772+ od->nbr->name, od->n_l3dgw_ports);
2773+ return;
2774+ }
2775+
2776 struct sset nat_entries = SSET_INITIALIZER(&nat_entries);
2777
2778 bool dnat_force_snat_ip =
2779@@ -13179,7 +13434,7 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows,
2780 is_v6);
2781 /* S_ROUTER_IN_DNAT */
2782 build_lrouter_in_dnat_flow(lflows, od, nat, match, actions, distributed,
2783- mask, is_v6);
2784+ cidr_bits, is_v6);
2785
2786 /* ARP resolve for NAT IPs. */
2787 if (od->is_gw_router) {
2788@@ -13218,7 +13473,7 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows,
2789 mac, is_v6);
2790 /* S_ROUTER_OUT_SNAT */
2791 build_lrouter_out_snat_flow(lflows, od, nat, match, actions, distributed,
2792- mac, mask, cidr_bits, is_v6);
2793+ mac, cidr_bits, is_v6);
2794
2795 /* S_ROUTER_IN_ADMISSION - S_ROUTER_IN_IP_INPUT */
2796 build_lrouter_ingress_flow(lflows, od, nat, match, actions,
2797@@ -13341,6 +13596,7 @@ struct lswitch_flow_build_info {
2798 const struct shash *meter_groups;
2799 const struct hmap *lbs;
2800 const struct hmap *bfd_connections;
2801+ const struct chassis_features *features;
2802 char *svc_check_match;
2803 struct ds match;
2804 struct ds actions;
2805@@ -13359,7 +13615,9 @@ build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *od,
2806 struct lswitch_flow_build_info *lsi)
2807 {
2808 /* Build Logical Switch Flows. */
2809- build_lswitch_lflows_pre_acl_and_acl(od, lsi->port_groups, lsi->lflows,
2810+ build_lswitch_lflows_pre_acl_and_acl(od, lsi->port_groups,
2811+ lsi->features,
2812+ lsi->lflows,
2813 lsi->meter_groups);
2814
2815 build_fwd_group_lflows(od, lsi->lflows);
2816@@ -13379,7 +13637,8 @@ build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *od,
2817 &lsi->actions, lsi->meter_groups);
2818 build_ND_RA_flows_for_lrouter(od, lsi->lflows);
2819 build_ip_routing_pre_flows_for_lrouter(od, lsi->lflows);
2820- build_static_route_flows_for_lrouter(od, lsi->lflows, lsi->ports,
2821+ build_static_route_flows_for_lrouter(od, lsi->features,
2822+ lsi->lflows, lsi->ports,
2823 lsi->bfd_connections);
2824 build_mcast_lookup_flows_for_lrouter(od, lsi->lflows, &lsi->match,
2825 &lsi->actions);
2826@@ -13509,10 +13768,12 @@ build_lflows_thread(void *arg)
2827 build_lrouter_defrag_flows_for_lb(lb, lsi->lflows,
2828 &lsi->match);
2829 build_lrouter_flows_for_lb(lb, lsi->lflows,
2830- lsi->meter_groups, &lsi->match,
2831- &lsi->actions);
2832+ lsi->meter_groups,
2833+ lsi->features,
2834+ &lsi->match, &lsi->actions);
2835 build_lswitch_flows_for_lb(lb, lsi->lflows,
2836 lsi->meter_groups,
2837+ lsi->features,
2838 &lsi->match, &lsi->actions);
2839 }
2840 }
2841@@ -13604,7 +13865,8 @@ build_lswitch_and_lrouter_flows(const struct hmap *datapaths,
2842 struct hmap *igmp_groups,
2843 const struct shash *meter_groups,
2844 const struct hmap *lbs,
2845- const struct hmap *bfd_connections)
2846+ const struct hmap *bfd_connections,
2847+ const struct chassis_features *features)
2848 {
2849
2850 char *svc_check_match = xasprintf("eth.dst == %s", svc_monitor_mac);
2851@@ -13648,6 +13910,7 @@ build_lswitch_and_lrouter_flows(const struct hmap *datapaths,
2852 lsiv[index].meter_groups = meter_groups;
2853 lsiv[index].lbs = lbs;
2854 lsiv[index].bfd_connections = bfd_connections;
2855+ lsiv[index].features = features;
2856 lsiv[index].svc_check_match = svc_check_match;
2857 lsiv[index].thread_lflow_counter = 0;
2858 ds_init(&lsiv[index].match);
2859@@ -13686,6 +13949,7 @@ build_lswitch_and_lrouter_flows(const struct hmap *datapaths,
2860 .meter_groups = meter_groups,
2861 .lbs = lbs,
2862 .bfd_connections = bfd_connections,
2863+ .features = features,
2864 .svc_check_match = svc_check_match,
2865 .match = DS_EMPTY_INITIALIZER,
2866 .actions = DS_EMPTY_INITIALIZER,
2867@@ -13711,9 +13975,9 @@ build_lswitch_and_lrouter_flows(const struct hmap *datapaths,
2868 &lsi.match);
2869 build_lrouter_defrag_flows_for_lb(lb, lsi.lflows, &lsi.match);
2870 build_lrouter_flows_for_lb(lb, lsi.lflows, lsi.meter_groups,
2871- &lsi.match, &lsi.actions);
2872+ lsi.features, &lsi.match, &lsi.actions);
2873 build_lswitch_flows_for_lb(lb, lsi.lflows, lsi.meter_groups,
2874- &lsi.match, &lsi.actions);
2875+ lsi.features, &lsi.match, &lsi.actions);
2876 }
2877 stopwatch_stop(LFLOWS_LBS_STOPWATCH_NAME, time_msec());
2878 stopwatch_start(LFLOWS_IGMP_STOPWATCH_NAME, time_msec());
2879@@ -13845,7 +14109,8 @@ void build_lflows(struct lflow_input *input_data,
2880 input_data->port_groups, &lflows,
2881 &mcast_groups, &igmp_groups,
2882 input_data->meter_groups, input_data->lbs,
2883- input_data->bfd_connections);
2884+ input_data->bfd_connections,
2885+ input_data->features);
2886
2887 /* Parallel build may result in a suboptimal hash. Resize the
2888 * hash to a correct size before doing lookups */
2889@@ -14901,6 +15166,7 @@ northd_init(struct northd_data *data)
2890 hmap_init(&data->lbs);
2891 hmap_init(&data->bfd_connections);
2892 ovs_list_init(&data->lr_list);
2893+ memset(&data->features, 0, sizeof data->features);
2894 data->ovn_internal_version_changed = false;
2895 }
2896
2897@@ -14961,15 +15227,6 @@ ovnnb_db_run(struct northd_input *input_data,
2898 if (!nb) {
2899 nb = nbrec_nb_global_insert(ovnnb_txn);
2900 }
2901- const struct sbrec_sb_global *sb = sbrec_sb_global_table_first(
2902- input_data->sbrec_sb_global_table);
2903- if (!sb) {
2904- sb = sbrec_sb_global_insert(ovnsb_txn);
2905- }
2906- if (nb->ipsec != sb->ipsec) {
2907- sbrec_sb_global_set_ipsec(sb, nb->ipsec);
2908- }
2909- sbrec_sb_global_set_options(sb, &nb->options);
2910
2911 const char *mac_addr_prefix = set_mac_prefix(smap_get(&nb->options,
2912 "mac_prefix"));
2913@@ -15015,8 +15272,6 @@ ovnnb_db_run(struct northd_input *input_data,
2914 nbrec_nb_global_set_options(nb, &options);
2915 }
2916
2917- smap_destroy(&options);
2918-
2919 use_parallel_build =
2920 (smap_get_bool(&nb->options, "use_parallel_build", false) &&
2921 can_parallelize_hashes(false));
2922@@ -15032,6 +15287,7 @@ ovnnb_db_run(struct northd_input *input_data,
2923 check_lsp_is_up = !smap_get_bool(&nb->options,
2924 "ignore_lsp_down", true);
2925
2926+ build_chassis_features(input_data, &data->features);
2927 build_datapaths(input_data, ovnsb_txn, &data->datapaths, &data->lr_list);
2928 build_ovn_lbs(input_data, ovnsb_txn, &data->datapaths, &data->lbs);
2929 build_lrouter_lbs(&data->datapaths, &data->lbs);
2930@@ -15048,6 +15304,7 @@ ovnnb_db_run(struct northd_input *input_data,
2931 build_meter_groups(input_data, &data->meter_groups);
2932 stopwatch_stop(BUILD_LFLOWS_CTX_STOPWATCH_NAME, time_msec());
2933 stopwatch_start(CLEAR_LFLOWS_CTX_STOPWATCH_NAME, time_msec());
2934+ ovn_update_ipv6_options(&data->ports);
2935 ovn_update_ipv6_prefix(&data->ports);
2936
2937 sync_address_sets(input_data, ovnsb_txn, &data->datapaths);
2938@@ -15056,6 +15313,26 @@ ovnnb_db_run(struct northd_input *input_data,
2939 sync_dns_entries(input_data, ovnsb_txn, &data->datapaths);
2940 cleanup_stale_fdp_entries(input_data, &data->datapaths);
2941 stopwatch_stop(CLEAR_LFLOWS_CTX_STOPWATCH_NAME, time_msec());
2942+
2943+ /* Set up SB_Global (depends on chassis features). */
2944+ const struct sbrec_sb_global *sb = sbrec_sb_global_table_first(
2945+ input_data->sbrec_sb_global_table);
2946+ if (!sb) {
2947+ sb = sbrec_sb_global_insert(ovnsb_txn);
2948+ }
2949+ if (nb->ipsec != sb->ipsec) {
2950+ sbrec_sb_global_set_ipsec(sb, nb->ipsec);
2951+ }
2952+
2953+ /* Inform ovn-controllers whether LB flows will use ct_mark
2954+ * (i.e., only if all chassis support it).
2955+ */
2956+ smap_replace(&options, "lb_hairpin_use_ct_mark",
2957+ data->features.ct_no_masked_label ? "true" : "false");
2958+ if (!smap_equal(&sb->options, &options)) {
2959+ sbrec_sb_global_set_options(sb, &options);
2960+ }
2961+ smap_destroy(&options);
2962 }
2963
2964 /* Stores the list of chassis which references an ha_chassis_group.
2965diff --git a/northd/northd.h b/northd/northd.h
2966index ebcb40d..0d9c7b8 100644
2967--- a/northd/northd.h
2968+++ b/northd/northd.h
2969@@ -53,6 +53,10 @@ struct northd_input {
2970 struct ovsdb_idl_index *sbrec_ip_mcast_by_dp;
2971 };
2972
2973+struct chassis_features {
2974+ bool ct_no_masked_label;
2975+};
2976+
2977 struct northd_data {
2978 /* Global state for 'en-northd'. */
2979 struct hmap datapaths;
2980@@ -63,6 +67,7 @@ struct northd_data {
2981 struct hmap bfd_connections;
2982 struct ovs_list lr_list;
2983 bool ovn_internal_version_changed;
2984+ struct chassis_features features;
2985 };
2986
2987 struct lflow_input {
2988@@ -84,6 +89,7 @@ struct lflow_input {
2989 const struct shash *meter_groups;
2990 const struct hmap *lbs;
2991 const struct hmap *bfd_connections;
2992+ const struct chassis_features *features;
2993 bool ovn_internal_version_changed;
2994 };
2995
2996diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
2997index 1c9d408..199d419 100644
2998--- a/northd/ovn-northd.8.xml
2999+++ b/northd/ovn-northd.8.xml
3000@@ -599,7 +599,7 @@
3001 <ul>
3002 <li>
3003 Priority-120 flows that send the packets to connection tracker using
3004- <code>ct_lb;</code> as the action so that the already established
3005+ <code>ct_lb_mark;</code> as the action so that the already established
3006 traffic destined to the load balancer VIP gets DNATted based on a hint
3007 provided by the previous tables (with a match
3008 for <code>reg0[2] == 1</code> and on supported load balancer protocols
3009@@ -614,7 +614,7 @@
3010 A priority-110 flow sends the packets to connection tracker based
3011 on a hint provided by the previous tables
3012 (with a match for <code>reg0[2] == 1</code>) by using the
3013- <code>ct_lb;</code> action. This flow is added to handle
3014+ <code>ct_lb_mark;</code> action. This flow is added to handle
3015 the traffic for load balancer VIPs whose protocol is not defined
3016 (mainly for ICMP traffic).
3017 </li>
3018@@ -790,12 +790,12 @@
3019 A priority-65532 flow that allows any traffic in the reply
3020 direction for a connection that has been committed to the
3021 connection tracker (i.e., established flows), as long as
3022- the committed flow does not have <code>ct_label.blocked</code> set.
3023+ the committed flow does not have <code>ct_mark.blocked</code> set.
3024 We only handle traffic in the reply direction here because
3025 we want all packets going in the request direction to still
3026 go through the flows that implement the currently defined
3027 policy based on ACLs. If a connection is no longer allowed by
3028- policy, <code>ct_label.blocked</code> will get set and packets in the
3029+ policy, <code>ct_mark.blocked</code> will get set and packets in the
3030 reply direction will no longer be allowed, either. This flow also
3031 clears the register bits <code>reg0[9]</code> and
3032 <code>reg0[10]</code>. If ACL logging and logging of related packets
3033@@ -807,7 +807,7 @@
3034 A priority-65532 flow that allows any traffic that is considered
3035 related to a committed flow in the connection tracker (e.g., an
3036 ICMP Port Unreachable from a non-listening UDP port), as long
3037- as the committed flow does not have <code>ct_label.blocked</code> set.
3038+ as the committed flow does not have <code>ct_mark.blocked</code> set.
3039 If ACL logging and logging of related packets is enabled, then a
3040 companion priority-65533 flow will be installed that accomplishes the
3041 same thing but also logs the traffic.
3042@@ -820,7 +820,7 @@
3043
3044 <li>
3045 A priority-65532 flow that drops all traffic in the reply direction
3046- with <code>ct_label.blocked</code> set meaning that the connection
3047+ with <code>ct_mark.blocked</code> set meaning that the connection
3048 should no longer be allowed due to a policy change. Packets
3049 in the request direction are skipped here to let a newly created
3050 ACL re-allow this connection.
3051@@ -908,7 +908,7 @@
3052 <var>P</var>.dst == <var>PORT</var></code>. For IPv6 <var>VIPs</var>,
3053 the flow matches <code>ct.new &amp;&amp; ip &amp;&amp; ip6.dst == <var>
3054 VIP </var>&amp;&amp; <var>P</var> &amp;&amp; <var>P</var>.dst == <var>
3055- PORT</var></code>. The flow's action is <code>ct_lb(<var>args</var>)
3056+ PORT</var></code>. The flow's action is <code>ct_lb_mark(<var>args</var>)
3057 </code>, where <var>args</var> contains comma separated IP addresses
3058 (and optional port numbers) to load balance to. The address family of
3059 the IP addresses of <var>args</var> is the same as the address family
3060@@ -929,7 +929,7 @@
3061 ip4.dst == <var>VIP</var></code>. For IPv6 <var>VIPs</var>,
3062 the flow matches <code>ct.new &amp;&amp; ip &amp;&amp; ip6.dst == <var>
3063 VIP</var></code>. The action on this flow is <code>
3064- ct_lb(<var>args</var>)</code>, where <var>args</var> contains comma
3065+ ct_lb_mark(<var>args</var>)</code>, where <var>args</var> contains comma
3066 separated IP addresses of the same address family as <var>VIP</var>.
3067 For IPv4 traffic the flow also loads the original destination
3068 IP and transport port in registers <code>reg1</code> and
3069@@ -1929,11 +1929,11 @@ output;
3070 <ul>
3071 <li>
3072 A Priority-120 flow that send the packets to connection tracker using
3073- <code>ct_lb;</code> as the action so that the already established
3074+ <code>ct_lb_mark;</code> as the action so that the already established
3075 traffic gets unDNATted from the backend IP to the load balancer VIP
3076 based on a hint provided by the previous tables with a match
3077 for <code>reg0[2] == 1</code>. If the packet was not DNATted earlier,
3078- then <code>ct_lb</code> functions like <code>ct_next</code>.
3079+ then <code>ct_lb_mark</code> functions like <code>ct_next</code>.
3080 </li>
3081
3082 <li>
3083@@ -2302,6 +2302,12 @@ next;
3084 </li>
3085
3086 <li>
3087+ A priority-95 flow with the match <code>nd_na &amp;&amp;
3088+ nd.tll == 0</code> and applies the action
3089+ <code>put_nd(inport, nd.target, eth.src); next;</code>
3090+ </li>
3091+
3092+ <li>
3093 A priority-90 flow with the match <code>nd_na</code> and
3094 applies the action
3095 <code>put_nd(inport, nd.target, nd.tll); next;</code>
3096@@ -3149,14 +3155,14 @@ icmp6 {
3097 &amp;&amp; <var>P</var> &amp;&amp; reg9[16..31] == </code>
3098 <code><var>PORT</var></code> (<code>xxreg0 == <var>VIP</var></code>
3099 in the IPv6 case) with an action of
3100- <code>ct_lb(<var>args</var>)</code>, where <var>args</var> contains
3101+ <code>ct_lb_mark(<var>args</var>)</code>, where <var>args</var> contains
3102 comma separated IPv4 or IPv6 addresses (and optional port numbers) to
3103 load balance to. If the router is configured to force SNAT any
3104 load-balanced packets, the above action will be replaced by
3105- <code>flags.force_snat_for_lb = 1; ct_lb(<var>args</var>);</code>.
3106+ <code>flags.force_snat_for_lb = 1; ct_lb_mark(<var>args</var>);</code>.
3107 If the load balancing rule is configured with <code>skip_snat</code>
3108 set to true, the above action will be replaced by
3109- <code>flags.skip_snat_for_lb = 1; ct_lb(<var>args</var>);</code>.
3110+ <code>flags.skip_snat_for_lb = 1; ct_lb_mark(<var>args</var>);</code>.
3111 If health check is enabled, then
3112 <var>args</var> will only contain those endpoints whose service
3113 monitor status entry in <code>OVN_Southbound</code> db is
3114@@ -3205,14 +3211,14 @@ icmp6 {
3115 <code>ct.new &amp;&amp; ip4 &amp;&amp; reg0 ==
3116 <var>VIP</var></code> (<code>ip6</code> and <code>xxreg0 ==
3117 <var>VIP</var></code> in the IPv6 case) with an action of
3118- <code>ct_lb(<var>args</var>)</code>, where <var>args</var> contains
3119+ <code>ct_lb_mark(<var>args</var>)</code>, where <var>args</var> contains
3120 comma separated IPv4 or IPv6 addresses. If the router is configured
3121 to force SNAT any load-balanced packets, the above action will be
3122 replaced by <code>flags.force_snat_for_lb = 1;
3123- ct_lb(<var>args</var>);</code>.
3124+ ct_lb_mark(<var>args</var>);</code>.
3125 If the load balancing rule is configured with <code>skip_snat</code>
3126 set to true, the above action will be replaced by
3127- <code>flags.skip_snat_for_lb = 1; ct_lb(<var>args</var>);</code>.
3128+ <code>flags.skip_snat_for_lb = 1; ct_lb_mark(<var>args</var>);</code>.
3129 </p>
3130
3131 <p>
3132@@ -3365,7 +3371,7 @@ icmp6 {
3133 route with a destination routing policy will instead match if the
3134 source IP address matches the static route's prefix. The flow uses
3135 the action <code>ct_commit { ct_label.ecmp_reply_eth = eth.src;"
3136- " ct_label.ecmp_reply_port = <var>K</var>;}; next; </code> to commit
3137+ " ct_mark.ecmp_reply_port = <var>K</var>;}; next; </code> to commit
3138 the connection and storing <code>eth.src</code> and the ECMP
3139 reply port binding tunnel key <var>K</var> in the
3140 <code>ct_label</code>.
3141@@ -3502,12 +3508,15 @@ output;
3142 <code>reg8[16..31]</code>. This step is skipped with a priority-10300
3143 rule if the traffic going out the ECMP route is reply traffic, and the
3144 ECMP route was configured to use symmetric replies. Instead, the stored
3145- <code>ct_label</code> value is used to choose the destination. The least
3146- significant 48 bits of the <code>ct_label</code> tell the destination MAC
3147- address to which the packet should be sent. The next 16 bits tell the
3148- logical router port on which the packet should be sent. These values in
3149- the <code>ct_label</code> are set when the initial ingress traffic is
3150- received over the ECMP route.
3151+ values in conntrack is used to choose the destination. The
3152+ <code>ct_label.ecmp_reply_eth</code> tells the destination MAC address to
3153+ which the packet should be sent. The <code>ct_mark.ecmp_reply_port</code>
3154+ tells the logical router port on which the packet should be sent. These
3155+ values saved to the conntrack fields when the initial ingress traffic is
3156+ received over the ECMP route and committed to conntrack. The
3157+ priority-10300 flows in this stage set the <code>outport</code>,
3158+ while the <code>eth.dst</code> is set by flows at the ARP/ND Resolution
3159+ stage.
3160 </p>
3161
3162 <p>
3163@@ -3847,6 +3856,16 @@ outport = <var>P</var>
3164
3165 <li>
3166 <p>
3167+ Priority-200 flows that match ECMP reply traffic for the routes
3168+ configured to use symmetric replies, with actions
3169+ <code>push(xxreg1); xxreg1 = ct_label; eth.dst = xxreg1[32..79]; pop(xxreg1); next;</code>.
3170+ <code>xxreg1</code> is used here to avoid masked access to ct_label,
3171+ to make the flow HW-offloading friendly.
3172+ </p>
3173+ </li>
3174+
3175+ <li>
3176+ <p>
3177 Static MAC bindings. MAC bindings can be known statically based on
3178 data in the <code>OVN_Northbound</code> database. For router ports
3179 connected to logical switches, MAC bindings can be known statically
3180@@ -4452,7 +4471,8 @@ nd_ns {
3181 to change the source IP address of a packet from an IP address of
3182 <var>A</var> or to change the source IP address of a packet that
3183 belongs to network <var>A</var> to <var>B</var>, a flow matches
3184- <code>ip &amp;&amp; ip4.src == <var>A</var></code> with an action
3185+ <code>ip &amp;&amp; ip4.src == <var>A</var> &amp;&amp;
3186+ (!ct.trk || !ct.rpl)</code> with an action
3187 <code>ct_snat(<var>B</var>);</code>. The priority of the flow
3188 is calculated based on the mask of <var>A</var>, with matches
3189 having larger masks getting higher priorities. If the NAT rule is
3190diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
3191index 95b3959..9d191ce 100644
3192--- a/northd/ovn-northd.c
3193+++ b/northd/ovn-northd.c
3194@@ -723,10 +723,18 @@ main(int argc, char *argv[])
3195 unixctl_command_register("nb-connection-status", "", 0, 0,
3196 ovn_conn_show, ovnnb_idl_loop.idl);
3197
3198- /* We want to detect all changes to the ovn-sb db. */
3199+ /* We want to detect all changes to the ovn-sb db so enable change
3200+ * tracking but, for performance reasons, and because northd
3201+ * reconciles all database changes, also configure the IDL to only
3202+ * write columns that actually change value.
3203+ */
3204 struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
3205 ovsdb_idl_create(ovnsb_db, &sbrec_idl_class, true, true));
3206 ovsdb_idl_track_add_all(ovnsb_idl_loop.idl);
3207+ ovsdb_idl_set_write_changed_only_all(ovnsb_idl_loop.idl, true);
3208+
3209+ /* Disable alerting for pure write-only columns. */
3210+ ovsdb_idl_omit_alert(ovnsb_idl_loop.idl, &sbrec_sb_global_col_nb_cfg);
3211
3212 unixctl_command_register("sb-connection-status", "", 0, 0,
3213 ovn_conn_show, ovnsb_idl_loop.idl);
3214diff --git a/ovn-nb.xml b/ovn-nb.xml
3215index 4d7a23c..0535f11 100644
3216--- a/ovn-nb.xml
3217+++ b/ovn-nb.xml
3218@@ -2357,9 +2357,9 @@
3219 <ref column="match"/> with the highest-<ref column="priority"/>
3220 will have QoS applied to it. If the <ref column="action"/> column is
3221 specified, then matching packets will have DSCP marking applied.
3222- If the <ref column="bandwdith"/> column is specified, then matching
3223+ If the <ref column="bandwidth"/> column is specified, then matching
3224 packets will have metering applied. <ref column="action"/> and
3225- <ref column="bandwdith"/> are not exclusive, so both marking and
3226+ <ref column="bandwidth"/> are not exclusive, so both marking and
3227 metering by defined for the same QoS entry. If no row matches,
3228 packets will not have any QoS applied.
3229 </p>
3230diff --git a/ovn-sb.xml b/ovn-sb.xml
3231index f7c41cc..3edefff 100644
3232--- a/ovn-sb.xml
3233+++ b/ovn-sb.xml
3234@@ -199,6 +199,22 @@
3235 tunnel interfaces.
3236 </column>
3237 </group>
3238+
3239+ <group title="Options for configuring Load Balancers">
3240+ <p>
3241+ These options apply when <code>ovn-controller</code> configures
3242+ load balancer related flows.
3243+ </p>
3244+
3245+ <column name="options" key="lb_hairpin_use_ct_mark">
3246+ This value is automatically set to <code>true</code> by
3247+ <code>ovn-northd</code> when action <code>ct_lb_mark</code> is used
3248+ for new load balancer sessions. <code>ovn-controller</code> then
3249+ knows that it should check <code>ct_mark.natted</code> to detect
3250+ load balanced traffic.
3251+ </column>
3252+ </group>
3253+
3254 </group>
3255
3256 <group title="Connection Options">
3257@@ -1271,6 +1287,21 @@
3258 </p>
3259 </dd>
3260
3261+ <dt><code>push(<var>field</var>);</code></dt>
3262+ <dd>
3263+ <p>
3264+ Push the value of <var>field</var> to the stack top.
3265+ </p>
3266+ </dd>
3267+
3268+ <dt><code>pop(<var>field</var>);</code></dt>
3269+ <dd>
3270+ <p>
3271+ Pop the stack top and store the value to <var>field</var>,
3272+ which must be modifiable.
3273+ </p>
3274+ </dd>
3275+
3276 <dt><code>ip.ttl--;</code></dt>
3277 <dd>
3278 <p>
3279@@ -1955,21 +1986,19 @@
3280 </dd>
3281
3282 <dt><code>ct_lb;</code></dt>
3283- <dt><code>ct_lb(</code><var>ip</var>[<code>:</code><var>port</var>]...<code>);</code></dt>
3284+ <dt><code>ct_lb(backends=<var>ip</var>[:<var>port</var>][,...][; hash_fields=<var>field1</var>,<var>field2</var>,...]);</code></dt>
3285 <dd>
3286 <p>
3287- With one or more arguments, <code>ct_lb</code> commits the packet
3288+ With arguments, <code>ct_lb</code> commits the packet
3289 to the connection tracking table and DNATs the packet's destination
3290 IP address (and port) to the IP address or addresses (and optional
3291- ports) specified in the string. If multiple comma-separated IP
3292- addresses are specified, each is given equal weight for picking the
3293- DNAT address. Processing automatically moves on to the next table,
3294- as if <code>next;</code> were specified, and later tables act on
3295- the packet as modified by the connection tracker. Connection
3296- tracking state is scoped by the logical port when the action is
3297- used in a flow for a logical switch, so overlapping
3298- addresses may be used. Connection tracking state is scoped by the
3299- logical topology when the action is used in a flow for a router.
3300+ ports) specified in the <code>backends</code>. If multiple
3301+ comma-separated IP addresses are specified, each is given equal
3302+ weight for picking the DNAT address. By default,
3303+ <code>dp_hash</code> is used as the OpenFlow group selection
3304+ method, but if <code>hash_fields</code> is specified,
3305+ <code>hash</code> is used as the selection method, and the fields
3306+ listed are used as the hash fields.
3307 </p>
3308 <p>
3309 Without arguments, <code>ct_lb</code> sends the packet to the
3310@@ -1979,6 +2008,25 @@
3311 will automatically get DNATed to the same IP address as the first
3312 packet in that connection.
3313 </p>
3314+ <p>
3315+ Processing automatically moves on to the next table,
3316+ as if <code>next;</code> were specified, and later tables act on
3317+ the packet as modified by the connection tracker. Connection
3318+ tracking state is scoped by the logical port when the action is
3319+ used in a flow for a logical switch, so overlapping
3320+ addresses may be used. Connection tracking state is scoped by the
3321+ logical topology when the action is used in a flow for a router.
3322+ </p>
3323+ </dd>
3324+
3325+ <dt><code>ct_lb_mark;</code></dt>
3326+ <dt><code>ct_lb_mark(backends=<var>ip</var>[:<var>port</var>][,...][; hash_fields=<var>field1</var>,<var>field2</var>,...]);</code></dt>
3327+ <dd>
3328+ <p>
3329+ Same as <code>ct_lb</code>, except that it internally uses ct_mark
3330+ to store the NAT flag, while <code>ct_lb</code> uses ct_label for
3331+ the same purpose.
3332+ </p>
3333 </dd>
3334
3335 <dt>
3336diff --git a/rhel/ovn-fedora.spec.in b/rhel/ovn-fedora.spec.in
3337index 3fb854a..821eb03 100644
3338--- a/rhel/ovn-fedora.spec.in
3339+++ b/rhel/ovn-fedora.spec.in
3340@@ -323,7 +323,7 @@ ln -sf ovn_detrace.py %{_bindir}/ovn-detrace
3341 %if %{with libcapng}
3342 if [ $1 -eq 1 ]; then
3343 sed -i 's:^#OVN_USER_ID=:OVN_USER_ID=:' %{_sysconfdir}/sysconfig/ovn
3344- sed -i 's:\(.*su\).*:\1 ovn ovn:' %{_sysconfdir}/logrotate.d/ovn
3345+ sed -i 's:\(.*su\).*:\1 openvswitch openvswitch:' %{_sysconfdir}/logrotate.d/ovn
3346 fi
3347 %endif
3348
3349diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at
3350index 6e4c24f..5d53712 100644
3351--- a/tests/ovn-controller.at
3352+++ b/tests/ovn-controller.at
3353@@ -2057,3 +2057,132 @@ AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0], [2
3354
3355 OVN_CLEANUP([hv1])
3356 AT_CLEANUP
3357+
3358+AT_SETUP([ovn-controller - I-P handle lb_hairpin_use_ct_mark change])
3359+
3360+ovn_start --backup-northd=none
3361+
3362+net_add n1
3363+sim_add hv1
3364+as hv1
3365+check ovs-vsctl add-br br-phys
3366+ovn_attach n1 br-phys 192.168.0.1
3367+check ovs-vsctl -- add-port br-int hv1-vif1 -- \
3368+ set interface hv1-vif1 external-ids:iface-id=ls1-lp1
3369+
3370+check ovn-nbctl ls-add ls1
3371+
3372+check ovn-nbctl lsp-add ls1 ls1-lp1 \
3373+-- lsp-set-addresses ls1-lp1 "f0:00:00:00:00:01"
3374+
3375+wait_for_ports_up
3376+ovn-appctl -t ovn-controller vlog/set file:dbg
3377+
3378+read_counter() {
3379+ ovn-appctl -t ovn-controller coverage/read-counter $1
3380+}
3381+
3382+# nb_cfg update in sb_global shouldn't trigger lflow_run.
3383+lflow_run_old=$(read_counter lflow_run)
3384+check ovn-nbctl --wait=hv sync
3385+lflow_run_new=$(read_counter lflow_run)
3386+AT_CHECK([echo $(($lflow_run_new - $lflow_run_old))], [0], [0
3387+])
3388+
3389+# lb_hairpin_use_ct_mark update in sb_global:options should trigger lflow_run.
3390+# The below steps should cause lb_hairpin_use_ct_mark change twice. One by
3391+# ovn-sbctl, and the other by ovn-northd to change it back.
3392+
3393+lflow_run_old=$(read_counter lflow_run)
3394+check ovn-sbctl set SB_Global . options:lb_hairpin_use_ct_mark=false
3395+check ovn-nbctl --wait=hv sync
3396+lflow_run_new=$(read_counter lflow_run)
3397+AT_CHECK([echo $(($lflow_run_new - $lflow_run_old))], [0], [2
3398+])
3399+
3400+OVN_CLEANUP([hv1])
3401+AT_CLEANUP
3402+
3403+
3404+AT_SETUP([ovn-controller - check ovn-chassis-mac-mappings])
3405+
3406+ovn_start
3407+
3408+net_add n1
3409+sim_add hv1
3410+as hv1
3411+ovs-vsctl add-br br-phys
3412+ovn_attach n1 br-phys 192.168.0.1
3413+
3414+pid=$(cat hv1/ovn-controller.pid)
3415+
3416+# Add chassis with some ovn-chassis-mac-mappings
3417+AT_CHECK([ovn-sbctl chassis-add foo geneve 127.0.0.2])
3418+AT_CHECK([ovn-sbctl set chassis foo other_config:ovn-chassis-mac-mappings="invalid1,invalid2,br1:00:00:00:00:00:00"])
3419+AT_CHECK([ovn-nbctl --wait=hv sync])
3420+
3421+# Check if ovn-controller is still alive
3422+AT_CHECK([ps $pid], [0], [ignore])
3423+# Check if we got warnings for invalid
3424+AT_CHECK([grep "Parsing of ovn-chassis-mac-mappings failed" hv1/ovn-controller.log | grep -q invalid1])
3425+AT_CHECK([grep "Parsing of ovn-chassis-mac-mappings failed" hv1/ovn-controller.log | grep -q invalid2])
3426+AT_CHECK([grep "Parsing of ovn-chassis-mac-mappings failed" hv1/ovn-controller.log | grep -q br1], [1])
3427+
3428+OVN_CLEANUP([hv1])
3429+AT_CLEANUP
3430+
3431+AT_SETUP([ovn-controller - localport can be recreated])
3432+
3433+ovn_start
3434+
3435+net_add n1
3436+sim_add hv1
3437+as hv1
3438+ovs-vsctl add-br br-phys
3439+ovn_attach n1 br-phys 192.168.0.1
3440+
3441+port_binding_cookie() {
3442+ name=$1
3443+ ovn-sbctl --bare --columns _uuid find port_binding logical_port=$name |\
3444+ cut -d '-' -f 1 | tr -d '\n' | sed 's/^0\{0,8\}//'
3445+}
3446+
3447+create_localport() {
3448+ AT_CHECK([ovn-nbctl lsp-add ls0 metadata])
3449+ AT_CHECK([ovn-nbctl lsp-set-type metadata localport])
3450+ AT_CHECK([ovn-nbctl lsp-set-addresses metadata "00:00:00:00:10:25 192.168.10.25"])
3451+}
3452+
3453+bind_ports() {
3454+ AT_CHECK([ovs-vsctl add-port br-int vm0 -- set interface vm0 type=internal external_ids:iface-id=vm0])
3455+ AT_CHECK([ovs-vsctl add-port br-int metadata -- set interface metadata type=internal external_ids:iface-id=metadata])
3456+}
3457+
3458+# Create one VIF and localport and bind it to chassis
3459+AT_CHECK([ovn-nbctl ls-add ls0])
3460+AT_CHECK([ovn-nbctl lsp-add ls0 vm0])
3461+AT_CHECK([ovn-nbctl lsp-set-addresses vm0 "00:00:00:00:10:10 192.168.10.10"])
3462+create_localport
3463+bind_ports
3464+
3465+# Check that localport has all physical flows defined
3466+OVS_WAIT_UNTIL([test 6 = $(as hv1 ovs-ofctl dump-flows br-int | grep -c $(port_binding_cookie metadata))])
3467+
3468+# Remove ls0 from local datapaths
3469+AT_CHECK([ovs-vsctl del-port br-int vm0])
3470+AT_CHECK([ovn-appctl inc-engine/recompute])
3471+
3472+# Check that localports physical flows are removed
3473+OVS_WAIT_UNTIL([test 0 = $(as hv1 ovs-ofctl dump-flows br-int | grep -c $(port_binding_cookie metadata))])
3474+
3475+# The order is impotant, if the port is removed first, the bug wouldn't be triggered
3476+AT_CHECK([ovn-nbctl lsp-del metadata])
3477+AT_CHECK([ovs-vsctl del-port br-int metadata])
3478+create_localport
3479+bind_ports
3480+
3481+# Check that localport has all physical flows re-defined
3482+OVS_WAIT_UNTIL([test 6 = $(as hv1 ovs-ofctl dump-flows br-int | grep -c $(port_binding_cookie metadata))])
3483+
3484+OVN_CLEANUP([hv1])
3485+AT_CLEANUP
3486diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at
3487index 539a121..efc1b60 100644
3488--- a/tests/ovn-nbctl.at
3489+++ b/tests/ovn-nbctl.at
3490@@ -597,6 +597,8 @@ AT_CHECK([ovn-nbctl --stateless lr-nat-add lr0 dnat_and_snat 40.0.0.3 192.168.1.
3491 [ovn-nbctl: 40.0.0.3, 192.168.1.7: External ip cannot be shared across stateless and stateful NATs
3492 ])
3493
3494+AT_CHECK([ovn-nbctl --stateless --may-exist lr-nat-add lr0 dnat_and_snat 40.0.0.3 192.168.1.7])
3495+
3496 dnl Deletes the NATs
3497 AT_CHECK([ovn-nbctl lr-nat-del lr0 dnat_and_snat 30.0.0.3], [1], [],
3498 [ovn-nbctl: no matching NAT with the type (dnat_and_snat) and external_ip (30.0.0.3)
3499diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
3500index 3865003..47d0d77 100644
3501--- a/tests/ovn-northd.at
3502+++ b/tests/ovn-northd.at
3503@@ -895,7 +895,7 @@ ovn-nbctl lr-nat-del R1 dnat_and_snat 172.16.1.1
3504 echo
3505 echo "IPv4: stateless"
3506 ovn-nbctl --wait=sb --stateless lr-nat-add R1 dnat_and_snat 172.16.1.1 50.0.0.11
3507-check_flow_match_sets 2 0 0 2 2 0 0
3508+check_flow_match_sets 2 0 0 1 1 0 0
3509 ovn-nbctl lr-nat-del R1 dnat_and_snat 172.16.1.1
3510
3511 echo
3512@@ -907,7 +907,7 @@ ovn-nbctl lr-nat-del R1 dnat_and_snat fd01::1
3513 echo
3514 echo "IPv6: stateless"
3515 ovn-nbctl --wait=sb --stateless lr-nat-add R1 dnat_and_snat fd01::1 fd11::2
3516-check_flow_match_sets 2 0 0 0 0 2 2
3517+check_flow_match_sets 2 0 0 0 0 1 1
3518
3519 AT_CLEANUP
3520 ])
3521@@ -1030,7 +1030,7 @@ AT_CHECK([grep -e "lr_out_snat" drflows | sed 's/table=../table=??/' | sort], [0
3522 AT_CHECK([grep -e "lr_out_snat" crflows | sed 's/table=../table=??/' | sort], [0], [dnl
3523 table=??(lr_out_snat ), priority=0 , match=(1), action=(next;)
3524 table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
3525- table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $allowed_range), action=(ct_snat(172.16.1.1);)
3526+ table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $allowed_range && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.1);)
3527 ])
3528
3529
3530@@ -1062,7 +1062,7 @@ AT_CHECK([grep -e "lr_out_snat" drflows2 | sed 's/table=../table=??/' | sort], [
3531 AT_CHECK([grep -e "lr_out_snat" crflows2 | sed 's/table=../table=??/' | sort], [0], [dnl
3532 table=??(lr_out_snat ), priority=0 , match=(1), action=(next;)
3533 table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
3534- table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == 50.0.0.11), action=(ct_snat(172.16.1.1);)
3535+ table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == 50.0.0.11 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.1);)
3536 table=??(lr_out_snat ), priority=35 , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $disallowed_range), action=(next;)
3537 ])
3538
3539@@ -1091,7 +1091,7 @@ AT_CHECK([grep -e "lr_out_snat" drflows3 | sed 's/table=../table=??/' | sort], [
3540 AT_CHECK([grep -e "lr_out_snat" crflows3 | sed 's/table=../table=??/' | sort], [0], [dnl
3541 table=??(lr_out_snat ), priority=0 , match=(1), action=(next;)
3542 table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
3543- table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $allowed_range), action=(ct_snat(172.16.1.2);)
3544+ table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $allowed_range && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.2);)
3545 ])
3546
3547 # Stateful FIP with DISALLOWED_IPs
3548@@ -1120,7 +1120,7 @@ AT_CHECK([grep -e "lr_out_snat" drflows4 | sed 's/table=../table=??/' | sort], [
3549 AT_CHECK([grep -e "lr_out_snat" crflows4 | sed 's/table=../table=??/' | sort], [0], [dnl
3550 table=??(lr_out_snat ), priority=0 , match=(1), action=(next;)
3551 table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
3552- table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == 50.0.0.11), action=(ct_snat(172.16.1.2);)
3553+ table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == 50.0.0.11 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.2);)
3554 table=??(lr_out_snat ), priority=35 , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $disallowed_range), action=(next;)
3555 ])
3556
3557@@ -1226,7 +1226,7 @@ check ovn-nbctl --wait=sb ls-lb-add sw0 lb1
3558 AT_CAPTURE_FILE([sbflows])
3559 OVS_WAIT_FOR_OUTPUT(
3560 [ovn-sbctl dump-flows sw0 | tee sbflows | grep 'priority=120.*backends' | sed 's/table=..//'], 0, [dnl
3561- (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80);)
3562+ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
3563 ])
3564
3565 AS_BOX([Delete the Load_Balancer_Health_Check])
3566@@ -1236,7 +1236,7 @@ wait_row_count Service_Monitor 0
3567 AT_CAPTURE_FILE([sbflows2])
3568 OVS_WAIT_FOR_OUTPUT(
3569 [ovn-sbctl dump-flows sw0 | tee sbflows2 | grep 'priority=120.*backends' | sed 's/table=..//'], [0],
3570-[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80);)
3571+[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
3572 ])
3573
3574 AS_BOX([Create the Load_Balancer_Health_Check again.])
3575@@ -1248,7 +1248,7 @@ check ovn-nbctl --wait=sb sync
3576
3577 ovn-sbctl dump-flows sw0 | grep backends | grep priority=120 > lflows.txt
3578 AT_CHECK([cat lflows.txt | sed 's/table=..//'], [0], [dnl
3579- (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80);)
3580+ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
3581 ])
3582
3583 AS_BOX([Get the uuid of both the service_monitor])
3584@@ -1258,7 +1258,7 @@ sm_sw1_p1=$(fetch_column Service_Monitor _uuid logical_port=sw1-p1)
3585 AT_CAPTURE_FILE([sbflows3])
3586 OVS_WAIT_FOR_OUTPUT(
3587 [ovn-sbctl dump-flows sw0 | tee sbflows 3 | grep 'priority=120.*backends' | sed 's/table=..//'], [0],
3588-[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80);)
3589+[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
3590 ])
3591
3592 AS_BOX([Set the service monitor for sw1-p1 to offline])
3593@@ -1269,7 +1269,7 @@ check ovn-nbctl --wait=sb sync
3594 AT_CAPTURE_FILE([sbflows4])
3595 OVS_WAIT_FOR_OUTPUT(
3596 [ovn-sbctl dump-flows sw0 | tee sbflows4 | grep 'priority=120.*backends' | sed 's/table=..//'], [0],
3597-[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80);)
3598+[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.3:80);)
3599 ])
3600
3601 AS_BOX([Set the service monitor for sw0-p1 to offline])
3602@@ -1298,7 +1298,7 @@ check ovn-nbctl --wait=sb sync
3603 AT_CAPTURE_FILE([sbflows7])
3604 OVS_WAIT_FOR_OUTPUT(
3605 [ovn-sbctl dump-flows sw0 | tee sbflows7 | grep backends | grep priority=120 | sed 's/table=..//'], 0,
3606-[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80);)
3607+[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
3608 ])
3609
3610 AS_BOX([Set the service monitor for sw1-p1 to error])
3611@@ -1309,7 +1309,7 @@ check ovn-nbctl --wait=sb sync
3612 ovn-sbctl dump-flows sw0 | grep "ip4.dst == 10.0.0.10 && tcp.dst == 80" \
3613 | grep priority=120 > lflows.txt
3614 AT_CHECK([cat lflows.txt | sed 's/table=..//'], [0], [dnl
3615- (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80);)
3616+ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.3:80);)
3617 ])
3618
3619 AS_BOX([Add one more vip to lb1])
3620@@ -1335,8 +1335,8 @@ AT_CAPTURE_FILE([sbflows9])
3621 OVS_WAIT_FOR_OUTPUT(
3622 [ovn-sbctl dump-flows sw0 | tee sbflows9 | grep backends | grep priority=120 | sed 's/table=..//' | sort],
3623 0,
3624-[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80);)
3625- (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(reg0[[1]] = 0; reg1 = 10.0.0.40; reg2[[0..15]] = 1000; ct_lb(backends=10.0.0.3:1000);)
3626+[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.3:80);)
3627+ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(reg0[[1]] = 0; reg1 = 10.0.0.40; reg2[[0..15]] = 1000; ct_lb_mark(backends=10.0.0.3:1000);)
3628 ])
3629
3630 AS_BOX([Set the service monitor for sw1-p1 to online])
3631@@ -1349,8 +1349,8 @@ AT_CAPTURE_FILE([sbflows10])
3632 OVS_WAIT_FOR_OUTPUT(
3633 [ovn-sbctl dump-flows sw0 | tee sbflows10 | grep backends | grep priority=120 | sed 's/table=..//' | sort],
3634 0,
3635-[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80);)
3636- (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(reg0[[1]] = 0; reg1 = 10.0.0.40; reg2[[0..15]] = 1000; ct_lb(backends=10.0.0.3:1000,20.0.0.3:80);)
3637+[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
3638+ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(reg0[[1]] = 0; reg1 = 10.0.0.40; reg2[[0..15]] = 1000; ct_lb_mark(backends=10.0.0.3:1000,20.0.0.3:80);)
3639 ])
3640
3641 AS_BOX([Associate lb1 to sw1])
3642@@ -1359,8 +1359,8 @@ AT_CAPTURE_FILE([sbflows11])
3643 OVS_WAIT_FOR_OUTPUT(
3644 [ovn-sbctl dump-flows sw1 | tee sbflows11 | grep backends | grep priority=120 | sed 's/table=..//' | sort],
3645 0, [dnl
3646- (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80);)
3647- (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(reg0[[1]] = 0; reg1 = 10.0.0.40; reg2[[0..15]] = 1000; ct_lb(backends=10.0.0.3:1000,20.0.0.3:80);)
3648+ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
3649+ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(reg0[[1]] = 0; reg1 = 10.0.0.40; reg2[[0..15]] = 1000; ct_lb_mark(backends=10.0.0.3:1000,20.0.0.3:80);)
3650 ])
3651
3652 AS_BOX([Now create lb2 same as lb1 but udp protocol.])
3653@@ -2071,15 +2071,15 @@ AT_CAPTURE_FILE([sw1flows3])
3654 AT_CHECK([grep "ls_out_acl" sw0flows3 sw1flows3 | grep pg0 | sort], [0], [dnl
3655 sw0flows3: table=4 (ls_out_acl ), priority=2001 , match=(reg0[[7]] == 1 && (outport == @pg0 && ip)), action=(reg0[[1]] = 1; next;)
3656 sw0flows3: table=4 (ls_out_acl ), priority=2001 , match=(reg0[[8]] == 1 && (outport == @pg0 && ip)), action=(next;)
3657-sw0flows3: table=4 (ls_out_acl ), priority=2002 , match=((reg0[[10]] == 1) && outport == @pg0 && ip4 && udp), action=(ct_commit { ct_label.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };)
3658+sw0flows3: table=4 (ls_out_acl ), priority=2002 , match=((reg0[[10]] == 1) && outport == @pg0 && ip4 && udp), action=(ct_commit { ct_mark.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };)
3659 sw0flows3: table=4 (ls_out_acl ), priority=2002 , match=((reg0[[9]] == 1) && outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };)
3660-sw0flows3: table=4 (ls_out_acl ), priority=2003 , match=((reg0[[10]] == 1) && outport == @pg0 && ip6 && udp), action=(ct_commit { ct_label.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };)
3661+sw0flows3: table=4 (ls_out_acl ), priority=2003 , match=((reg0[[10]] == 1) && outport == @pg0 && ip6 && udp), action=(ct_commit { ct_mark.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };)
3662 sw0flows3: table=4 (ls_out_acl ), priority=2003 , match=((reg0[[9]] == 1) && outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };)
3663 sw1flows3: table=4 (ls_out_acl ), priority=2001 , match=(reg0[[7]] == 1 && (outport == @pg0 && ip)), action=(reg0[[1]] = 1; next;)
3664 sw1flows3: table=4 (ls_out_acl ), priority=2001 , match=(reg0[[8]] == 1 && (outport == @pg0 && ip)), action=(next;)
3665-sw1flows3: table=4 (ls_out_acl ), priority=2002 , match=((reg0[[10]] == 1) && outport == @pg0 && ip4 && udp), action=(ct_commit { ct_label.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };)
3666+sw1flows3: table=4 (ls_out_acl ), priority=2002 , match=((reg0[[10]] == 1) && outport == @pg0 && ip4 && udp), action=(ct_commit { ct_mark.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };)
3667 sw1flows3: table=4 (ls_out_acl ), priority=2002 , match=((reg0[[9]] == 1) && outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };)
3668-sw1flows3: table=4 (ls_out_acl ), priority=2003 , match=((reg0[[10]] == 1) && outport == @pg0 && ip6 && udp), action=(ct_commit { ct_label.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };)
3669+sw1flows3: table=4 (ls_out_acl ), priority=2003 , match=((reg0[[10]] == 1) && outport == @pg0 && ip6 && udp), action=(ct_commit { ct_mark.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };)
3670 sw1flows3: table=4 (ls_out_acl ), priority=2003 , match=((reg0[[9]] == 1) && outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };)
3671 ])
3672 AT_CLEANUP
3673@@ -2220,28 +2220,28 @@ check ovn-nbctl --wait=sb \
3674 -- acl-add ls from-lport 2 "udp" allow-related \
3675 -- acl-add ls to-lport 2 "udp" allow-related
3676 AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e ls_in_acl -e ls_out_acl | grep 'ct\.' | sort], [0], [dnl
3677- table=3 (ls_out_acl_hint ), priority=1 , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;)
3678- table=3 (ls_out_acl_hint ), priority=2 , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;)
3679+ table=3 (ls_out_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
3680+ table=3 (ls_out_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
3681 table=3 (ls_out_acl_hint ), priority=3 , match=(!ct.est), action=(reg0[[9]] = 1; next;)
3682- table=3 (ls_out_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
3683+ table=3 (ls_out_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
3684 table=3 (ls_out_acl_hint ), priority=5 , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
3685- table=3 (ls_out_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
3686+ table=3 (ls_out_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
3687 table=3 (ls_out_acl_hint ), priority=7 , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
3688- table=4 (ls_out_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
3689- table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
3690- table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;)
3691- table=4 (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
3692- table=8 (ls_in_acl_hint ), priority=1 , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;)
3693- table=8 (ls_in_acl_hint ), priority=2 , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;)
3694+ table=4 (ls_out_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;)
3695+ table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
3696+ table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;)
3697+ table=4 (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
3698+ table=8 (ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
3699+ table=8 (ls_in_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
3700 table=8 (ls_in_acl_hint ), priority=3 , match=(!ct.est), action=(reg0[[9]] = 1; next;)
3701- table=8 (ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
3702+ table=8 (ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
3703 table=8 (ls_in_acl_hint ), priority=5 , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
3704- table=8 (ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
3705+ table=8 (ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
3706 table=8 (ls_in_acl_hint ), priority=7 , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
3707- table=9 (ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
3708- table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
3709- 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;)
3710- table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
3711+ table=9 (ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;)
3712+ table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
3713+ table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
3714+ table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
3715 ])
3716
3717 AS_BOX([Check match ct_state with load balancer])
3718@@ -2254,38 +2254,38 @@ check ovn-nbctl --wait=sb \
3719 AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e ls_in_acl -e ls_out_acl | sort], [0], [dnl
3720 table=13(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;)
3721 table=3 (ls_out_acl_hint ), priority=0 , match=(1), action=(next;)
3722- table=3 (ls_out_acl_hint ), priority=1 , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;)
3723- table=3 (ls_out_acl_hint ), priority=2 , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;)
3724+ table=3 (ls_out_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
3725+ table=3 (ls_out_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
3726 table=3 (ls_out_acl_hint ), priority=3 , match=(!ct.est), action=(reg0[[9]] = 1; next;)
3727- table=3 (ls_out_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
3728+ table=3 (ls_out_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
3729 table=3 (ls_out_acl_hint ), priority=5 , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
3730- table=3 (ls_out_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
3731+ table=3 (ls_out_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
3732 table=3 (ls_out_acl_hint ), priority=7 , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
3733 table=4 (ls_out_acl ), priority=0 , match=(1), action=(next;)
3734- table=4 (ls_out_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
3735+ table=4 (ls_out_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;)
3736 table=4 (ls_out_acl ), priority=1001 , match=(reg0[[7]] == 1 && (ip)), action=(reg0[[1]] = 1; next;)
3737 table=4 (ls_out_acl ), priority=1001 , match=(reg0[[8]] == 1 && (ip)), action=(next;)
3738 table=4 (ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
3739- table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
3740- table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;)
3741- table=4 (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
3742+ table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
3743+ table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;)
3744+ table=4 (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
3745 table=4 (ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
3746 table=8 (ls_in_acl_hint ), priority=0 , match=(1), action=(next;)
3747- table=8 (ls_in_acl_hint ), priority=1 , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;)
3748- table=8 (ls_in_acl_hint ), priority=2 , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;)
3749+ table=8 (ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
3750+ table=8 (ls_in_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
3751 table=8 (ls_in_acl_hint ), priority=3 , match=(!ct.est), action=(reg0[[9]] = 1; next;)
3752- table=8 (ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
3753+ table=8 (ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
3754 table=8 (ls_in_acl_hint ), priority=5 , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
3755- table=8 (ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
3756+ table=8 (ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
3757 table=8 (ls_in_acl_hint ), priority=7 , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
3758 table=9 (ls_in_acl ), priority=0 , match=(1), action=(next;)
3759- table=9 (ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
3760+ table=9 (ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;)
3761 table=9 (ls_in_acl ), priority=1001 , match=(reg0[[7]] == 1 && (ip)), action=(reg0[[1]] = 1; next;)
3762 table=9 (ls_in_acl ), priority=1001 , match=(reg0[[8]] == 1 && (ip)), action=(next;)
3763 table=9 (ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
3764- table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
3765- 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;)
3766- table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
3767+ table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
3768+ table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
3769+ table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
3770 table=9 (ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
3771 ])
3772
3773@@ -2928,12 +2928,12 @@ ovn-nbctl --wait=sb sync
3774 flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_tcp}"
3775 AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
3776 # tcp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80,tcp_flags=0
3777-ct_lb {
3778- ct_lb {
3779+ct_lb_mark {
3780+ ct_lb_mark {
3781 reg0[[6]] = 0;
3782 *** chk_lb_hairpin_reply action not implemented;
3783 reg0[[12]] = 0;
3784- ct_lb /* default (use --ct to customize) */ {
3785+ ct_lb_mark /* default (use --ct to customize) */ {
3786 output("lsp2");
3787 };
3788 };
3789@@ -2944,12 +2944,12 @@ ct_lb {
3790 flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_udp}"
3791 AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
3792 # udp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80
3793-ct_lb {
3794- ct_lb {
3795+ct_lb_mark {
3796+ ct_lb_mark {
3797 reg0[[6]] = 0;
3798 *** chk_lb_hairpin_reply action not implemented;
3799 reg0[[12]] = 0;
3800- ct_lb /* default (use --ct to customize) */ {
3801+ ct_lb_mark /* default (use --ct to customize) */ {
3802 output("lsp2");
3803 };
3804 };
3805@@ -2966,12 +2966,12 @@ ovn-nbctl --wait=sb sync
3806 flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_tcp}"
3807 AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
3808 # tcp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80,tcp_flags=0
3809-ct_lb {
3810- ct_lb {
3811+ct_lb_mark {
3812+ ct_lb_mark {
3813 reg0[[6]] = 0;
3814 *** chk_lb_hairpin_reply action not implemented;
3815 reg0[[12]] = 0;
3816- ct_lb /* default (use --ct to customize) */ {
3817+ ct_lb_mark /* default (use --ct to customize) */ {
3818 output("lsp2");
3819 };
3820 };
3821@@ -2982,12 +2982,12 @@ ct_lb {
3822 flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_udp}"
3823 AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
3824 # udp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80
3825-ct_lb {
3826- ct_lb {
3827+ct_lb_mark {
3828+ ct_lb_mark {
3829 reg0[[6]] = 0;
3830 *** chk_lb_hairpin_reply action not implemented;
3831 reg0[[12]] = 0;
3832- ct_lb /* default (use --ct to customize) */ {
3833+ ct_lb_mark /* default (use --ct to customize) */ {
3834 output("lsp2");
3835 };
3836 };
3837@@ -3084,12 +3084,12 @@ ovn-nbctl --wait=sb sync
3838 flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_tcp}"
3839 AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
3840 # tcp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80,tcp_flags=0
3841-ct_lb {
3842- ct_lb {
3843+ct_lb_mark {
3844+ ct_lb_mark {
3845 reg0[[6]] = 0;
3846 *** chk_lb_hairpin_reply action not implemented;
3847 reg0[[12]] = 0;
3848- ct_lb /* default (use --ct to customize) */ {
3849+ ct_lb_mark /* default (use --ct to customize) */ {
3850 output("lsp2");
3851 };
3852 };
3853@@ -3100,12 +3100,12 @@ ct_lb {
3854 flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_udp}"
3855 AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
3856 # udp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80
3857-ct_lb {
3858- ct_lb {
3859+ct_lb_mark {
3860+ ct_lb_mark {
3861 reg0[[6]] = 0;
3862 *** chk_lb_hairpin_reply action not implemented;
3863 reg0[[12]] = 0;
3864- ct_lb /* default (use --ct to customize) */ {
3865+ ct_lb_mark /* default (use --ct to customize) */ {
3866 output("lsp2");
3867 };
3868 };
3869@@ -3122,12 +3122,12 @@ ovn-nbctl --wait=sb sync
3870 flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_tcp}"
3871 AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
3872 # tcp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80,tcp_flags=0
3873-ct_lb {
3874- ct_lb {
3875+ct_lb_mark {
3876+ ct_lb_mark {
3877 reg0[[6]] = 0;
3878 *** chk_lb_hairpin_reply action not implemented;
3879 reg0[[12]] = 0;
3880- ct_lb /* default (use --ct to customize) */ {
3881+ ct_lb_mark /* default (use --ct to customize) */ {
3882 output("lsp2");
3883 };
3884 };
3885@@ -3138,12 +3138,12 @@ ct_lb {
3886 flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_udp}"
3887 AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
3888 # udp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80
3889-ct_lb {
3890- ct_lb {
3891+ct_lb_mark {
3892+ ct_lb_mark {
3893 reg0[[6]] = 0;
3894 *** chk_lb_hairpin_reply action not implemented;
3895 reg0[[12]] = 0;
3896- ct_lb /* default (use --ct to customize) */ {
3897+ ct_lb_mark /* default (use --ct to customize) */ {
3898 output("lsp2");
3899 };
3900 };
3901@@ -3447,7 +3447,7 @@ ls_copp_uuid=$(fetch_column nb:Logical_Switch copp)
3902 AT_CHECK([test "$ls_copp_uuid" = "$copp_uuid"])
3903
3904 check ovn-nbctl --wait=hv copp-add $copp_uuid igmp meter0
3905-AT_CHECK([ovn-nbctl copp-list copp0], [0], [dnl
3906+AT_CHECK([ovn-nbctl copp-list copp0 | sort], [0], [dnl
3907 arp: meter0
3908 igmp: meter0
3909 ])
3910@@ -3589,10 +3589,10 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
3911
3912 AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
3913 table=6 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
3914- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(next;)
3915- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(next;)
3916- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(ct_lb(backends=10.0.0.4:8080);)
3917- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(ct_lb(backends=10.0.0.40:8080);)
3918+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(next;)
3919+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(next;)
3920+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(ct_lb_mark(backends=10.0.0.4:8080);)
3921+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(ct_lb_mark(backends=10.0.0.40:8080);)
3922 ])
3923
3924 AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
3925@@ -3625,10 +3625,10 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
3926
3927 AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
3928 table=6 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
3929- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
3930- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
3931- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.4:8080);)
3932- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.40:8080);)
3933+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
3934+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
3935+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080);)
3936+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080);)
3937 ])
3938
3939 AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
3940@@ -3671,10 +3671,10 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
3941
3942 AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
3943 table=6 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
3944- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
3945- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
3946- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.4:8080);)
3947- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.40:8080);)
3948+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
3949+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
3950+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080);)
3951+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080);)
3952 ])
3953
3954 AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
3955@@ -3731,10 +3731,10 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
3956
3957 AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
3958 table=6 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
3959- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
3960- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
3961- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.4:8080);)
3962- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.40:8080);)
3963+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
3964+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
3965+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080);)
3966+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080);)
3967 ])
3968
3969 AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
3970@@ -3777,8 +3777,8 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
3971 ])
3972
3973 AT_CHECK([grep "lr_in_dnat" lr0flows | grep skip_snat_for_lb | sort], [0], [dnl
3974- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.20 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(flags.skip_snat_for_lb = 1; next;)
3975- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.20 && tcp && reg9[[16..31]] == 80), action=(flags.skip_snat_for_lb = 1; ct_lb(backends=10.0.0.40:8080);)
3976+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.20 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.skip_snat_for_lb = 1; next;)
3977+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.20 && tcp && reg9[[16..31]] == 80), action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080);)
3978 ])
3979
3980 AT_CHECK([grep "lr_out_snat" lr0flows | grep skip_snat_for_lb | sed 's/table=./table=?/' | sort], [0], [dnl
3981@@ -3941,25 +3941,25 @@ check_stateful_flows() {
3982 AT_CHECK([grep "ls_in_pre_stateful" sw0flows | sort], [0], [dnl
3983 table=7 (ls_in_pre_stateful ), priority=0 , match=(1), action=(next;)
3984 table=7 (ls_in_pre_stateful ), priority=100 , match=(reg0[[0]] == 1), action=(ct_next;)
3985- table=7 (ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb;)
3986- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && sctp), action=(reg1 = ip4.dst; reg2[[0..15]] = sctp.dst; ct_lb;)
3987- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && tcp), action=(reg1 = ip4.dst; reg2[[0..15]] = tcp.dst; ct_lb;)
3988- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && udp), action=(reg1 = ip4.dst; reg2[[0..15]] = udp.dst; ct_lb;)
3989- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && sctp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = sctp.dst; ct_lb;)
3990- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && tcp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = tcp.dst; ct_lb;)
3991- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && udp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = udp.dst; ct_lb;)
3992+ table=7 (ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;)
3993+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && sctp), action=(reg1 = ip4.dst; reg2[[0..15]] = sctp.dst; ct_lb_mark;)
3994+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && tcp), action=(reg1 = ip4.dst; reg2[[0..15]] = tcp.dst; ct_lb_mark;)
3995+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && udp), action=(reg1 = ip4.dst; reg2[[0..15]] = udp.dst; ct_lb_mark;)
3996+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && sctp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = sctp.dst; ct_lb_mark;)
3997+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && tcp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = tcp.dst; ct_lb_mark;)
3998+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && udp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = udp.dst; ct_lb_mark;)
3999 ])
4000
4001 AT_CHECK([grep "ls_in_lb" sw0flows | sort], [0], [dnl
4002 table=12(ls_in_lb ), priority=0 , match=(1), action=(next;)
4003- table=12(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.4:8080);)
4004- table=12(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.20 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.20; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.40:8080);)
4005+ table=12(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.4:8080);)
4006+ table=12(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.20 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.20; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.40:8080);)
4007 ])
4008
4009 AT_CHECK([grep "ls_in_stateful" sw0flows | sort], [0], [dnl
4010 table=14(ls_in_stateful ), priority=0 , match=(1), action=(next;)
4011- table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;)
4012- table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;)
4013+ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
4014+ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
4015 ])
4016
4017 AT_CHECK([grep "ls_out_pre_lb" sw0flows | sort], [0], [dnl
4018@@ -3974,15 +3974,15 @@ check_stateful_flows() {
4019 AT_CHECK([grep "ls_out_pre_stateful" sw0flows | sort], [0], [dnl
4020 table=2 (ls_out_pre_stateful), priority=0 , match=(1), action=(next;)
4021 table=2 (ls_out_pre_stateful), priority=100 , match=(reg0[[0]] == 1), action=(ct_next;)
4022- table=2 (ls_out_pre_stateful), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb;)
4023+ table=2 (ls_out_pre_stateful), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;)
4024 ])
4025
4026 AT_CHECK([grep "ls_out_lb" sw0flows | sort], [0], [])
4027
4028 AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl
4029 table=7 (ls_out_stateful ), priority=0 , match=(1), action=(next;)
4030- table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;)
4031- table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;)
4032+ table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
4033+ table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
4034 ])
4035 }
4036
4037@@ -4013,13 +4013,13 @@ AT_CHECK([grep "ls_in_pre_lb" sw0flows | sort], [0], [dnl
4038 AT_CHECK([grep "ls_in_pre_stateful" sw0flows | sort], [0], [dnl
4039 table=7 (ls_in_pre_stateful ), priority=0 , match=(1), action=(next;)
4040 table=7 (ls_in_pre_stateful ), priority=100 , match=(reg0[[0]] == 1), action=(ct_next;)
4041- table=7 (ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb;)
4042- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && sctp), action=(reg1 = ip4.dst; reg2[[0..15]] = sctp.dst; ct_lb;)
4043- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && tcp), action=(reg1 = ip4.dst; reg2[[0..15]] = tcp.dst; ct_lb;)
4044- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && udp), action=(reg1 = ip4.dst; reg2[[0..15]] = udp.dst; ct_lb;)
4045- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && sctp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = sctp.dst; ct_lb;)
4046- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && tcp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = tcp.dst; ct_lb;)
4047- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && udp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = udp.dst; ct_lb;)
4048+ table=7 (ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;)
4049+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && sctp), action=(reg1 = ip4.dst; reg2[[0..15]] = sctp.dst; ct_lb_mark;)
4050+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && tcp), action=(reg1 = ip4.dst; reg2[[0..15]] = tcp.dst; ct_lb_mark;)
4051+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && udp), action=(reg1 = ip4.dst; reg2[[0..15]] = udp.dst; ct_lb_mark;)
4052+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && sctp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = sctp.dst; ct_lb_mark;)
4053+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && tcp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = tcp.dst; ct_lb_mark;)
4054+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && udp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = udp.dst; ct_lb_mark;)
4055 ])
4056
4057 AT_CHECK([grep "ls_in_lb" sw0flows | sort], [0], [dnl
4058@@ -4028,8 +4028,8 @@ AT_CHECK([grep "ls_in_lb" sw0flows | sort], [0], [dnl
4059
4060 AT_CHECK([grep "ls_in_stateful" sw0flows | sort], [0], [dnl
4061 table=14(ls_in_stateful ), priority=0 , match=(1), action=(next;)
4062- table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;)
4063- table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;)
4064+ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
4065+ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
4066 ])
4067
4068 AT_CHECK([grep "ls_out_pre_lb" sw0flows | sort], [0], [dnl
4069@@ -4043,13 +4043,13 @@ AT_CHECK([grep "ls_out_pre_lb" sw0flows | sort], [0], [dnl
4070 AT_CHECK([grep "ls_out_pre_stateful" sw0flows | sort], [0], [dnl
4071 table=2 (ls_out_pre_stateful), priority=0 , match=(1), action=(next;)
4072 table=2 (ls_out_pre_stateful), priority=100 , match=(reg0[[0]] == 1), action=(ct_next;)
4073- table=2 (ls_out_pre_stateful), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb;)
4074+ table=2 (ls_out_pre_stateful), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;)
4075 ])
4076
4077 AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl
4078 table=7 (ls_out_stateful ), priority=0 , match=(1), action=(next;)
4079- table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;)
4080- table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;)
4081+ table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
4082+ table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
4083 ])
4084
4085 AT_CLEANUP
4086@@ -4074,8 +4074,8 @@ AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 2002 | sort], [0], [dnl
4087 ])
4088 AT_CHECK([grep "ls_in_stateful" sw0flows | sort], [0], [dnl
4089 table=14(ls_in_stateful ), priority=0 , match=(1), action=(next;)
4090- table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;)
4091- table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;)
4092+ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
4093+ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
4094 ])
4095
4096 AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 2002 | sort], [0], [dnl
4097@@ -4084,8 +4084,8 @@ AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 2002 | sort], [0], [dnl
4098 ])
4099 AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl
4100 table=7 (ls_out_stateful ), priority=0 , match=(1), action=(next;)
4101- table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;)
4102- table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;)
4103+ table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
4104+ table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
4105 ])
4106
4107 # Add new ACL without label
4108@@ -4103,8 +4103,8 @@ AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 2002 | sort], [0], [dnl
4109 ])
4110 AT_CHECK([grep "ls_in_stateful" sw0flows | sort], [0], [dnl
4111 table=14(ls_in_stateful ), priority=0 , match=(1), action=(next;)
4112- table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;)
4113- table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;)
4114+ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
4115+ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
4116 ])
4117
4118 AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 2002 | sort], [0], [dnl
4119@@ -4115,8 +4115,8 @@ AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 2002 | sort], [0], [dnl
4120 ])
4121 AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl
4122 table=7 (ls_out_stateful ), priority=0 , match=(1), action=(next;)
4123- table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;)
4124- table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;)
4125+ table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
4126+ table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
4127 ])
4128
4129 # Delete new ACL with label
4130@@ -4132,8 +4132,8 @@ AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 2002 | sort], [0], [dnl
4131 ])
4132 AT_CHECK([grep "ls_in_stateful" sw0flows | sort], [0], [dnl
4133 table=14(ls_in_stateful ), priority=0 , match=(1), action=(next;)
4134- table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;)
4135- table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;)
4136+ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
4137+ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
4138 ])
4139
4140 AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 2002 | sort], [0], [dnl
4141@@ -4142,8 +4142,8 @@ AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 2002 | sort], [0], [dnl
4142 ])
4143 AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl
4144 table=7 (ls_out_stateful ), priority=0 , match=(1), action=(next;)
4145- table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;)
4146- table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;)
4147+ table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
4148+ table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
4149 ])
4150 AT_CLEANUP
4151 ])
4152@@ -4161,16 +4161,16 @@ ovn-sbctl dump-flows sw0 > sw0flows
4153 AT_CAPTURE_FILE([sw0flows])
4154
4155 AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 6553 | sort], [0], [dnl
4156- table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
4157- 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;)
4158- table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
4159+ table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
4160+ table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
4161+ table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
4162 table=9 (ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
4163 ])
4164
4165 AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 6553 | sort], [0], [dnl
4166- table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
4167- table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;)
4168- table=4 (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
4169+ table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
4170+ table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;)
4171+ table=4 (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
4172 table=4 (ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
4173 ])
4174
4175@@ -4181,16 +4181,16 @@ ovn-sbctl dump-flows sw0 > sw0flows
4176 AT_CAPTURE_FILE([sw0flows])
4177
4178 AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 6553 | sort], [0], [dnl
4179- table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && ct_label.blocked == 0), action=(next;)
4180- table=9 (ls_in_acl ), priority=65532, match=((ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
4181- table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
4182+ table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && ct_mark.blocked == 0), action=(next;)
4183+ table=9 (ls_in_acl ), priority=65532, match=((ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
4184+ table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
4185 table=9 (ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
4186 ])
4187
4188 AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 6553 | sort], [0], [dnl
4189- table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && ct_label.blocked == 0), action=(next;)
4190- table=4 (ls_out_acl ), priority=65532, match=((ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
4191- table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && ct.rpl && ct_label.blocked == 0), action=(next;)
4192+ table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && ct_mark.blocked == 0), action=(next;)
4193+ table=4 (ls_out_acl ), priority=65532, match=((ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
4194+ table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && ct.rpl && ct_mark.blocked == 0), action=(next;)
4195 table=4 (ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
4196 ])
4197
4198@@ -4205,16 +4205,16 @@ ovn-sbctl dump-flows sw0 > sw0flows
4199 AT_CAPTURE_FILE([sw0flows])
4200
4201 AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 6553 | sort], [0], [dnl
4202- table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
4203- 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;)
4204- table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
4205+ table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
4206+ table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
4207+ table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
4208 table=9 (ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
4209 ])
4210
4211 AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 6553 | sort], [0], [dnl
4212- table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
4213- table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;)
4214- table=4 (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
4215+ table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
4216+ table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;)
4217+ table=4 (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
4218 table=4 (ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
4219 ])
4220
4221@@ -4946,7 +4946,8 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [
4222 table=? (lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
4223 ])
4224
4225-ovn-sbctl chassis-add gw1 geneve 127.0.0.1
4226+check ovn-sbctl chassis-add gw1 geneve 127.0.0.1 \
4227+ -- set chassis gw1 other_config:ct-no-masked-label="true"
4228
4229 # Create a distributed gw port on lr0
4230 check ovn-nbctl ls-add public
4231@@ -5045,14 +5046,14 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
4232 AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
4233 table=6 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
4234 table=6 (lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 172.168.0.20 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_dnat_in_czone(10.0.0.3);)
4235- table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 172.168.0.200 && ct_label.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;)
4236- table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 172.168.0.200 && is_chassis_resident("cr-lr0-public")), action=(ct_lb(backends=10.0.0.80,10.0.0.81);)
4237- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;)
4238- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_label.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;)
4239- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_label.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;)
4240- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb(backends=10.0.0.4:8080);)
4241- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && is_chassis_resident("cr-lr0-public")), action=(ct_lb(backends=10.0.0.50:82,10.0.0.60:82);)
4242- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && is_chassis_resident("cr-lr0-public")), action=(ct_lb(backends=10.0.0.50:6062,10.0.0.60:6062);)
4243+ table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 172.168.0.200 && ct_mark.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;)
4244+ table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 172.168.0.200 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.80,10.0.0.81);)
4245+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;)
4246+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_mark.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;)
4247+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;)
4248+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.4:8080);)
4249+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);)
4250+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);)
4251 ])
4252
4253 AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
4254@@ -5113,14 +5114,14 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
4255 AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
4256 table=6 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
4257 table=6 (lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);)
4258- table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 172.168.0.200 && ct_label.natted == 1), action=(next;)
4259- table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 172.168.0.200), action=(ct_lb(backends=10.0.0.80,10.0.0.81);)
4260- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(next;)
4261- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_label.natted == 1), action=(next;)
4262- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_label.natted == 1), action=(next;)
4263- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(ct_lb(backends=10.0.0.4:8080);)
4264- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(ct_lb(backends=10.0.0.50:82,10.0.0.60:82);)
4265- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(ct_lb(backends=10.0.0.50:6062,10.0.0.60:6062);)
4266+ table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 172.168.0.200 && ct_mark.natted == 1), action=(next;)
4267+ table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 172.168.0.200), action=(ct_lb_mark(backends=10.0.0.80,10.0.0.81);)
4268+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(next;)
4269+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_mark.natted == 1), action=(next;)
4270+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(next;)
4271+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(ct_lb_mark(backends=10.0.0.4:8080);)
4272+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);)
4273+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);)
4274 ])
4275
4276 AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
4277@@ -5140,11 +5141,12 @@ AT_CHECK([grep "lr_out_post_undnat" lr0flows | sed 's/table=./table=?/' | sort],
4278 AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
4279 table=? (lr_out_snat ), priority=0 , match=(1), action=(next;)
4280 table=? (lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
4281- table=? (lr_out_snat ), priority=25 , match=(ip && ip4.src == 10.0.0.0/24), action=(ct_snat(172.168.0.10);)
4282- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.10), action=(ct_snat(172.168.0.30);)
4283- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.3), action=(ct_snat(172.168.0.20);)
4284+ table=? (lr_out_snat ), priority=25 , match=(ip && ip4.src == 10.0.0.0/24 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.10);)
4285+ table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.10 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.30);)
4286+ table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.3 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.20);)
4287 ])
4288
4289+
4290 # Set lb force snat logical router.
4291 check ovn-nbctl --wait=sb set logical_router lr0 options:lb_force_snat_ip="router_ip"
4292 check ovn-nbctl --wait=sb sync
4293@@ -5172,14 +5174,14 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
4294 AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
4295 table=6 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
4296 table=6 (lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);)
4297- table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 172.168.0.200 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4298- table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.80,10.0.0.81);)
4299- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4300- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4301- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4302- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.4:8080);)
4303- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.50:82,10.0.0.60:82);)
4304- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.50:6062,10.0.0.60:6062);)
4305+ table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 172.168.0.200 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4306+ table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.80,10.0.0.81);)
4307+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4308+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4309+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4310+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080);)
4311+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);)
4312+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);)
4313 ])
4314
4315 AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
4316@@ -5201,9 +5203,9 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [
4317 table=? (lr_out_snat ), priority=110 , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"), action=(ct_snat(172.168.0.10);)
4318 table=? (lr_out_snat ), priority=110 , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"), action=(ct_snat(10.0.0.1);)
4319 table=? (lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
4320- table=? (lr_out_snat ), priority=25 , match=(ip && ip4.src == 10.0.0.0/24), action=(ct_snat(172.168.0.10);)
4321- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.10), action=(ct_snat(172.168.0.30);)
4322- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.3), action=(ct_snat(172.168.0.20);)
4323+ table=? (lr_out_snat ), priority=25 , match=(ip && ip4.src == 10.0.0.0/24 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.10);)
4324+ table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.10 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.30);)
4325+ table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.3 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.20);)
4326 ])
4327
4328 # Add a LB VIP same as router ip.
4329@@ -5235,16 +5237,16 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
4330 AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
4331 table=6 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
4332 table=6 (lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);)
4333- table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 172.168.0.200 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4334- table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.80,10.0.0.81);)
4335- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4336- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4337- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4338- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4339- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.4:8080);)
4340- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.50:82,10.0.0.60:82);)
4341- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.50:82,10.0.0.60:82);)
4342- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.50:6062,10.0.0.60:6062);)
4343+ table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 172.168.0.200 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4344+ table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.80,10.0.0.81);)
4345+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4346+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4347+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4348+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4349+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080);)
4350+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);)
4351+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);)
4352+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);)
4353 ])
4354
4355 AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
4356@@ -5266,9 +5268,9 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [
4357 table=? (lr_out_snat ), priority=110 , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"), action=(ct_snat(172.168.0.10);)
4358 table=? (lr_out_snat ), priority=110 , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"), action=(ct_snat(10.0.0.1);)
4359 table=? (lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
4360- table=? (lr_out_snat ), priority=25 , match=(ip && ip4.src == 10.0.0.0/24), action=(ct_snat(172.168.0.10);)
4361- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.10), action=(ct_snat(172.168.0.30);)
4362- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.3), action=(ct_snat(172.168.0.20);)
4363+ table=? (lr_out_snat ), priority=25 , match=(ip && ip4.src == 10.0.0.0/24 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.10);)
4364+ table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.10 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.30);)
4365+ table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.3 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.20);)
4366 ])
4367
4368 # Add IPv6 router port and LB.
4369@@ -5311,18 +5313,18 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
4370 AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
4371 table=6 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
4372 table=6 (lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);)
4373- table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 172.168.0.200 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4374- table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.80,10.0.0.81);)
4375- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4376- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4377- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4378- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4379- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip6 && xxreg0 == def0::2 && tcp && reg9[[16..31]] == 8000 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4380- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.4:8080);)
4381- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.50:82,10.0.0.60:82);)
4382- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.50:82,10.0.0.60:82);)
4383- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.50:6062,10.0.0.60:6062);)
4384- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip6 && xxreg0 == def0::2 && tcp && reg9[[16..31]] == 8000), action=(flags.force_snat_for_lb = 1; ct_lb(backends=[[aef0::2]]:80,[[aef0::3]]:80);)
4385+ table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 172.168.0.200 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4386+ table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.80,10.0.0.81);)
4387+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4388+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4389+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4390+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4391+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip6 && xxreg0 == def0::2 && tcp && reg9[[16..31]] == 8000 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4392+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080);)
4393+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);)
4394+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);)
4395+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);)
4396+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip6 && xxreg0 == def0::2 && tcp && reg9[[16..31]] == 8000), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=[[aef0::2]]:80,[[aef0::3]]:80);)
4397 ])
4398
4399 AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
4400@@ -5346,9 +5348,9 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [
4401 table=? (lr_out_snat ), priority=110 , match=(flags.force_snat_for_lb == 1 && ip6 && outport == "lr0-public"), action=(ct_snat(def0::10);)
4402 table=? (lr_out_snat ), priority=110 , match=(flags.force_snat_for_lb == 1 && ip6 && outport == "lr0-sw0"), action=(ct_snat(aef0::1);)
4403 table=? (lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
4404- table=? (lr_out_snat ), priority=25 , match=(ip && ip4.src == 10.0.0.0/24), action=(ct_snat(172.168.0.10);)
4405- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.10), action=(ct_snat(172.168.0.30);)
4406- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.3), action=(ct_snat(172.168.0.20);)
4407+ table=? (lr_out_snat ), priority=25 , match=(ip && ip4.src == 10.0.0.0/24 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.10);)
4408+ table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.10 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.30);)
4409+ table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.3 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.20);)
4410 ])
4411
4412 check ovn-nbctl lrp-del lr0-sw0
4413@@ -5377,10 +5379,10 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
4414
4415 AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
4416 table=6 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
4417- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && tcp && reg9[[16..31]] == 60 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4418- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4419- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && tcp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.50:6062,10.0.0.60:6062);)
4420- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.50:6062,10.0.0.60:6062);)
4421+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && tcp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4422+ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
4423+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && tcp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);)
4424+ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);)
4425 ])
4426
4427 AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
4428@@ -5490,7 +5492,7 @@ AT_CAPTURE_FILE([lr0flows])
4429
4430 AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl
4431 table=??(lr_in_chk_pkt_len ), priority=0 , match=(1), action=(next;)
4432- table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); next;)
4433+ table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); next;)
4434 table=??(lr_in_larger_pkts ), priority=0 , match=(1), action=(next;)
4435 table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress, table=0); };)
4436 table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };)
4437@@ -5499,8 +5501,8 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=.
4438 ])
4439
4440 AT_CHECK([grep -E "lr_in_admission.*check_pkt_larger" lr0flows | sort], [0], [dnl
4441- table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4442- table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4443+ table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4444+ table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4445 ])
4446
4447 AT_CHECK([grep -E "lr_in_ip_input.*icmp4_error" lr0flows | sort], [0], [dnl
4448@@ -5521,7 +5523,7 @@ AT_CAPTURE_FILE([lr0flows])
4449
4450 AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl
4451 table=??(lr_in_chk_pkt_len ), priority=0 , match=(1), action=(next;)
4452- table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); next;)
4453+ table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); next;)
4454 table=??(lr_in_larger_pkts ), priority=0 , match=(1), action=(next;)
4455 table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress, table=0); };)
4456 table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };)
4457@@ -5530,8 +5532,8 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=.
4458 ])
4459
4460 AT_CHECK([grep -E "lr_in_admission.*check_pkt_larger" lr0flows | sort], [0], [dnl
4461- table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4462- table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4463+ table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4464+ table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4465 ])
4466
4467 AT_CHECK([grep -E "lr_in_ip_input.*icmp4_error" lr0flows | sort], [0], [dnl
4468@@ -5549,7 +5551,7 @@ AT_CAPTURE_FILE([lr0flows])
4469
4470 AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl
4471 table=??(lr_in_chk_pkt_len ), priority=0 , match=(1), action=(next;)
4472- table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); next;)
4473+ table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); next;)
4474 table=??(lr_in_chk_pkt_len ), priority=55 , match=(outport == "lr0-public" && (tcp)), action=(next;)
4475 table=??(lr_in_larger_pkts ), priority=0 , match=(1), action=(next;)
4476 table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress, table=0); };)
4477@@ -5559,8 +5561,8 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=.
4478 ])
4479
4480 AT_CHECK([grep "lr_in_admission" lr0flows | grep -e "check_pkt_larger" -e "tcp" | sort], [0], [dnl
4481- table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4482- table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4483+ table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4484+ table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4485 table=0 (lr_in_admission ), priority=55 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public" && (tcp)), action=(xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4486 table=0 (lr_in_admission ), priority=55 , match=(eth.mcast && inport == "lr0-public" && (tcp)), action=(xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4487 ])
4488@@ -5573,8 +5575,8 @@ AT_CAPTURE_FILE([lr0flows])
4489
4490 AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl
4491 table=??(lr_in_chk_pkt_len ), priority=0 , match=(1), action=(next;)
4492- table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); next;)
4493- table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1418); next;)
4494+ table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); next;)
4495+ table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); next;)
4496 table=??(lr_in_chk_pkt_len ), priority=55 , match=(outport == "lr0-public" && (tcp)), action=(next;)
4497 table=??(lr_in_larger_pkts ), priority=0 , match=(1), action=(next;)
4498 table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip4.dst = ip4.src; ip4.src = 172.168.0.100; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1400; next(pipeline=ingress, table=0); };)
4499@@ -5588,10 +5590,10 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=.
4500 ])
4501
4502 AT_CHECK([grep "lr_in_admission.*check_pkt_larger" lr0flows | sort], [0], [dnl
4503- table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:00:00:ff:01 && inport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1418); xreg0[[0..47]] = 00:00:00:00:ff:01; next;)
4504- table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4505- table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4506- table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1418); xreg0[[0..47]] = 00:00:00:00:ff:01; next;)
4507+ table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:00:00:ff:01 && inport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); xreg0[[0..47]] = 00:00:00:00:ff:01; next;)
4508+ table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4509+ table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4510+ table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); xreg0[[0..47]] = 00:00:00:00:ff:01; next;)
4511 ])
4512
4513 AT_CHECK([grep -E "lr_in_ip_input.*icmp4_error" lr0flows | sort], [0], [dnl
4514@@ -5611,8 +5613,8 @@ AT_CAPTURE_FILE([lr0flows])
4515
4516 AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl
4517 table=??(lr_in_chk_pkt_len ), priority=0 , match=(1), action=(next;)
4518- table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); next;)
4519- table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1418); next;)
4520+ table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); next;)
4521+ table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); next;)
4522 table=??(lr_in_chk_pkt_len ), priority=55 , match=(outport == "lr0-public" && (tcp)), action=(next;)
4523 table=??(lr_in_chk_pkt_len ), priority=55 , match=(outport == "lr0-sw0" && (tcp)), action=(next;)
4524 table=??(lr_in_larger_pkts ), priority=0 , match=(1), action=(next;)
4525@@ -5627,10 +5629,10 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=.
4526 ])
4527
4528 AT_CHECK([grep "lr_in_admission" lr0flows | grep -e "check_pkt_larger" -e "tcp" | sort], [0], [dnl
4529- table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:00:00:ff:01 && inport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1418); xreg0[[0..47]] = 00:00:00:00:ff:01; next;)
4530- table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4531- table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4532- table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1418); xreg0[[0..47]] = 00:00:00:00:ff:01; next;)
4533+ table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:00:00:ff:01 && inport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); xreg0[[0..47]] = 00:00:00:00:ff:01; next;)
4534+ table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4535+ table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4536+ table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); xreg0[[0..47]] = 00:00:00:00:ff:01; next;)
4537 table=0 (lr_in_admission ), priority=55 , match=(eth.dst == 00:00:00:00:ff:01 && inport == "lr0-sw0" && (tcp)), action=(xreg0[[0..47]] = 00:00:00:00:ff:01; next;)
4538 table=0 (lr_in_admission ), priority=55 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public" && (tcp)), action=(xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4539 table=0 (lr_in_admission ), priority=55 , match=(eth.mcast && inport == "lr0-public" && (tcp)), action=(xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4540@@ -5644,7 +5646,7 @@ AT_CAPTURE_FILE([lr0flows])
4541
4542 AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl
4543 table=??(lr_in_chk_pkt_len ), priority=0 , match=(1), action=(next;)
4544- table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1418); next;)
4545+ table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); next;)
4546 table=??(lr_in_chk_pkt_len ), priority=55 , match=(outport == "lr0-sw0" && (tcp)), action=(next;)
4547 table=??(lr_in_larger_pkts ), priority=0 , match=(1), action=(next;)
4548 table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip4.dst = ip4.src; ip4.src = 172.168.0.100; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1400; next(pipeline=ingress, table=0); };)
4549@@ -5653,6 +5655,19 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=.
4550 table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw1" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400; next(pipeline=ingress, table=0); };)
4551 ])
4552
4553+check ovn-nbctl --wait=sb clear logical_router_port lr0-sw0 options
4554+check ovn-nbctl --wait=sb set logical_router_port lr0-public options:gateway_mtu=1500
4555+check ovn-nbctl lsp-add public ext-port
4556+check ovn-nbctl lsp-set-addresses ext-port unknown
4557+check ovn-nbctl lsp-set-type ext-port localnet
4558+check ovn-nbctl --wait=sb set Logical_Switch_Port ext-port tag_request=2
4559+ovn-sbctl dump-flows lr0 > lr0flows
4560+
4561+AT_CHECK([grep "lr_in_admission" lr0flows | grep -e "check_pkt_larger" | sort], [0], [dnl
4562+ table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4563+ table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
4564+])
4565+
4566 AT_CLEANUP
4567 ])
4568
4569@@ -5664,6 +5679,7 @@ ovn_start
4570 check ovn-sbctl chassis-add ch1 geneve 127.0.0.1
4571
4572 check ovn-nbctl lr-add lr0
4573+check ovn-nbctl set logical_router lr0 options:chassis=ch1
4574 check ovn-nbctl ls-add public
4575 check ovn-nbctl lrp-add lr0 lr0-public 00:00:20:20:12:13 192.168.0.1/24
4576 check ovn-nbctl lsp-add public public-lr0
4577@@ -5693,6 +5709,22 @@ AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed 's/192\.168\.0\..0/192.
4578 table=??(lr_in_ip_routing_ecmp), priority=150 , match=(reg8[[0..15]] == 0), action=(next;)
4579 ])
4580
4581+dnl The chassis was created with other_config:ct-no-masked-label=false, the flows
4582+dnl should be using ct_label.ecmp_reply_port.
4583+AT_CHECK([grep -e "lr_in_arp_resolve.*ecmp" lr0flows | sed 's/table=../table=??/'], [0], [dnl
4584+ 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;)
4585+])
4586+
4587+dnl Simulate an ovn-controller upgrade to a version that supports
4588+dnl ct-no-masked-label. ovn-northd should start using ct_mark.ecmp_reply_port.
4589+
4590+check ovn-sbctl set chassis ch1 other_config:ct-no-masked-label=true
4591+check ovn-nbctl --wait=sb sync
4592+ovn-sbctl dump-flows lr0 > lr0flows
4593+AT_CHECK([grep -e "lr_in_arp_resolve.*ecmp" lr0flows | sed 's/table=../table=??/'], [0], [dnl
4594+ 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;)
4595+])
4596+
4597 # add ecmp route with wrong nexthop
4598 check ovn-nbctl --wait=sb --ecmp-symmetric-reply lr-route-add lr0 1.0.0.1 192.168.1.20
4599
4600@@ -5804,6 +5836,12 @@ AT_CHECK([grep lr_in_gw_redirect lrflows | grep cr-DR | sed 's/table=../table=??
4601 table=??(lr_in_gw_redirect ), priority=50 , match=(outport == "DR-S3"), action=(outport = "cr-DR-S3"; next;)
4602 ])
4603
4604+# Check that ovn-northd logs a warning when trying to configure NAT
4605+# on the router with multiple distributed gw ports. Such configurations are
4606+# not supported yet.
4607+check ovn-nbctl lr-nat-add DR dnat_and_snat 42.42.42.1 20.0.0.2
4608+AT_CHECK([grep -q 'NAT is configured on logical router DR, which has 2 distributed gateway ports. NAT is not supported yet when there is more than one distributed gateway port on the router.' northd/ovn-northd.log], [0])
4609+
4610 AT_CLEANUP
4611 ])
4612
4613@@ -5888,7 +5926,7 @@ flow="eth.dst == 00:00:00:00:01:00 && inport == \"rtr-ls\" && ip4.src == 42.42.4
4614 AT_CHECK_UNQUOTED([ovn-trace --ct new --minimal "${flow}" --lb-dst 42.42.42.42:4242], [0], [dnl
4615 # tcp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:01:00,nw_src=42.42.42.42,nw_dst=43.43.43.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=4343,tcp_flags=0
4616 ct_dnat /* assuming no un-dnat entry, so no change */ {
4617- ct_lb /* default (use --ct to customize) */ {
4618+ ct_lb_mark /* default (use --ct to customize) */ {
4619 ip.ttl--;
4620 eth.src = 00:00:00:00:01:00;
4621 eth.dst = 00:00:00:00:00:00;
4622@@ -6078,10 +6116,10 @@ check_log_flows_count 0 in
4623
4624 # Now ensure the flows are what we expect them to be for the ACLs we created
4625 AT_CHECK([cat log_flows], [0], [dnl
4626- table=??(ls_out_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4627- table=??(ls_out_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
4628- table=??(ls_out_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4629- table=??(ls_out_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
4630+ table=??(ls_out_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4631+ table=??(ls_out_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
4632+ table=??(ls_out_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4633+ table=??(ls_out_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
4634 ])
4635
4636 rm log_flows
4637@@ -6099,10 +6137,10 @@ check_log_flows_count 0 in
4638
4639 # And the log flows will remain the same since the stateless ACL will not be represented.
4640 AT_CHECK([cat log_flows], [0], [dnl
4641- table=??(ls_out_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4642- table=??(ls_out_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
4643- table=??(ls_out_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4644- table=??(ls_out_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
4645+ table=??(ls_out_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4646+ table=??(ls_out_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
4647+ table=??(ls_out_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4648+ table=??(ls_out_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
4649 ])
4650
4651 rm log_flows
4652@@ -6121,8 +6159,8 @@ check_log_flows_count 0 in
4653
4654 # And make sure only the allow ACL has the log flows installed
4655 AT_CHECK([cat log_flows], [0], [dnl
4656- table=??(ls_out_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4657- table=??(ls_out_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4658+ table=??(ls_out_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4659+ table=??(ls_out_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4660 ])
4661
4662 rm log_flows
4663@@ -6138,8 +6176,8 @@ check_log_flows_count 0 in
4664
4665 # And make sure only the allow ACL has the log flows installed
4666 AT_CHECK([cat log_flows], [0], [dnl
4667- table=??(ls_out_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4668- table=??(ls_out_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4669+ table=??(ls_out_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4670+ table=??(ls_out_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4671 ])
4672
4673 rm log_flows
4674@@ -6183,10 +6221,10 @@ check_log_flows_count 0 out
4675
4676 # Now ensure the flows are what we expect them to be for the ACLs we created
4677 AT_CHECK([cat log_flows], [0], [dnl
4678- table=??(ls_in_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4679- table=??(ls_in_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
4680- table=??(ls_in_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4681- table=??(ls_in_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
4682+ table=??(ls_in_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4683+ table=??(ls_in_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
4684+ table=??(ls_in_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4685+ table=??(ls_in_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
4686 ])
4687
4688 rm log_flows
4689@@ -6204,10 +6242,10 @@ check_log_flows_count 0 out
4690
4691 # And the log flows will remain the same since the stateless ACL will not be represented.
4692 AT_CHECK([cat log_flows], [0], [dnl
4693- table=??(ls_in_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4694- table=??(ls_in_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
4695- table=??(ls_in_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4696- table=??(ls_in_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
4697+ table=??(ls_in_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4698+ table=??(ls_in_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
4699+ table=??(ls_in_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4700+ table=??(ls_in_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 2), action=(log(name="allow_related_acl", severity=info, verdict=allow); next;)
4701 ])
4702
4703 rm log_flows
4704@@ -6226,8 +6264,8 @@ check_log_flows_count 0 out
4705
4706 # And make sure only the allow ACL has the log flows installed
4707 AT_CHECK([cat log_flows], [0], [dnl
4708- table=??(ls_in_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4709- table=??(ls_in_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4710+ table=??(ls_in_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4711+ table=??(ls_in_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4712 ])
4713
4714 rm log_flows
4715@@ -6243,8 +6281,8 @@ check_log_flows_count 0 out
4716
4717 # And make sure only the allow ACL has the log flows installed
4718 AT_CHECK([cat log_flows], [0], [dnl
4719- table=??(ls_in_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4720- table=??(ls_in_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4721+ table=??(ls_in_acl ), priority=65533, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4722+ table=??(ls_in_acl ), priority=65533, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0 && ct_label.label == 1), action=(log(name="allow_acl", severity=info, verdict=allow); next;)
4723 ])
4724
4725 rm log_flows
4726@@ -6284,40 +6322,40 @@ AT_CAPTURE_FILE([lsflows])
4727
4728 AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
4729 table=??(ls_in_acl ), priority=0 , match=(1), action=(next;)
4730- table=??(ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
4731- table=??(ls_in_acl ), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(ct_commit { ct_label.blocked = 1; }; /* drop */)
4732+ table=??(ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;)
4733+ table=??(ls_in_acl ), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */)
4734 table=??(ls_in_acl ), priority=2001 , match=(reg0[[9]] == 1 && (ip4)), action=(/* drop */)
4735 table=??(ls_in_acl ), priority=2002 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
4736 table=??(ls_in_acl ), priority=2002 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(next;)
4737 table=??(ls_in_acl ), priority=2003 , match=(reg0[[7]] == 1 && (ip4 && icmp)), action=(reg0[[1]] = 1; next;)
4738 table=??(ls_in_acl ), priority=2003 , match=(reg0[[8]] == 1 && (ip4 && icmp)), action=(next;)
4739- table=??(ls_in_acl ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_label.blocked = 1; }; /* drop */)
4740+ table=??(ls_in_acl ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */)
4741 table=??(ls_in_acl ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(/* drop */)
4742 table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
4743- table=??(ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
4744- 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;)
4745- table=??(ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
4746+ table=??(ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
4747+ table=??(ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
4748+ table=??(ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
4749 table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
4750 table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;)
4751 table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;)
4752- table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;)
4753- table=??(ls_in_acl_hint ), priority=2 , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;)
4754+ table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
4755+ table=??(ls_in_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
4756 table=??(ls_in_acl_hint ), priority=3 , match=(!ct.est), action=(reg0[[9]] = 1; next;)
4757- table=??(ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
4758+ table=??(ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
4759 table=??(ls_in_acl_hint ), priority=5 , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
4760- table=??(ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
4761+ table=??(ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
4762 table=??(ls_in_acl_hint ), priority=7 , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
4763 ])
4764
4765 AT_CHECK([grep -e "ls_in_lb" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
4766 table=??(ls_in_lb ), priority=0 , match=(1), action=(next;)
4767- table=??(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 10.0.0.2), action=(reg0[[1]] = 0; reg1 = 10.0.0.2; ct_lb(backends=10.0.0.10);)
4768+ table=??(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 10.0.0.2), action=(reg0[[1]] = 0; reg1 = 10.0.0.2; ct_lb_mark(backends=10.0.0.10);)
4769 ])
4770
4771 AT_CHECK([grep -e "ls_in_stateful" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
4772 table=??(ls_in_stateful ), priority=0 , match=(1), action=(next;)
4773- table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;)
4774- table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;)
4775+ table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
4776+ table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
4777 ])
4778
4779 AS_BOX([Remove and add the ACLs back with the apply-after-lb option])
4780@@ -6336,40 +6374,40 @@ AT_CAPTURE_FILE([lsflows])
4781
4782 AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
4783 table=??(ls_in_acl ), priority=0 , match=(1), action=(next;)
4784- table=??(ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
4785+ table=??(ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;)
4786 table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
4787- table=??(ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
4788- 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;)
4789- table=??(ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
4790+ table=??(ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
4791+ table=??(ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
4792+ table=??(ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
4793 table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
4794 table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;)
4795- table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(ct_commit { ct_label.blocked = 1; }; /* drop */)
4796+ table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */)
4797 table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[9]] == 1 && (ip4)), action=(/* drop */)
4798 table=??(ls_in_acl_after_lb ), priority=2002 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
4799 table=??(ls_in_acl_after_lb ), priority=2002 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(next;)
4800 table=??(ls_in_acl_after_lb ), priority=2003 , match=(reg0[[7]] == 1 && (ip4 && icmp)), action=(reg0[[1]] = 1; next;)
4801 table=??(ls_in_acl_after_lb ), priority=2003 , match=(reg0[[8]] == 1 && (ip4 && icmp)), action=(next;)
4802- table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_label.blocked = 1; }; /* drop */)
4803+ table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */)
4804 table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(/* drop */)
4805 table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;)
4806- table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;)
4807- table=??(ls_in_acl_hint ), priority=2 , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;)
4808+ table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
4809+ table=??(ls_in_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
4810 table=??(ls_in_acl_hint ), priority=3 , match=(!ct.est), action=(reg0[[9]] = 1; next;)
4811- table=??(ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
4812+ table=??(ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
4813 table=??(ls_in_acl_hint ), priority=5 , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
4814- table=??(ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
4815+ table=??(ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
4816 table=??(ls_in_acl_hint ), priority=7 , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
4817 ])
4818
4819 AT_CHECK([grep -e "ls_in_lb" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
4820 table=??(ls_in_lb ), priority=0 , match=(1), action=(next;)
4821- table=??(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 10.0.0.2), action=(reg0[[1]] = 0; reg1 = 10.0.0.2; ct_lb(backends=10.0.0.10);)
4822+ table=??(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 10.0.0.2), action=(reg0[[1]] = 0; reg1 = 10.0.0.2; ct_lb_mark(backends=10.0.0.10);)
4823 ])
4824
4825 AT_CHECK([grep -e "ls_in_stateful" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
4826 table=??(ls_in_stateful ), priority=0 , match=(1), action=(next;)
4827- table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;)
4828- table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;)
4829+ table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
4830+ table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
4831 ])
4832
4833 AS_BOX([Remove and add the ACLs back with a few ACLs with apply-after-lb option])
4834@@ -6388,40 +6426,209 @@ AT_CAPTURE_FILE([lsflows])
4835
4836 AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
4837 table=??(ls_in_acl ), priority=0 , match=(1), action=(next;)
4838- table=??(ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
4839+ table=??(ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;)
4840 table=??(ls_in_acl ), priority=2002 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
4841 table=??(ls_in_acl ), priority=2002 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(next;)
4842 table=??(ls_in_acl ), priority=2003 , match=(reg0[[7]] == 1 && (ip4 && icmp)), action=(reg0[[1]] = 1; next;)
4843 table=??(ls_in_acl ), priority=2003 , match=(reg0[[8]] == 1 && (ip4 && icmp)), action=(next;)
4844 table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
4845- table=??(ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
4846- 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;)
4847- table=??(ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
4848+ table=??(ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
4849+ table=??(ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
4850+ table=??(ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
4851 table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
4852 table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;)
4853- table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(ct_commit { ct_label.blocked = 1; }; /* drop */)
4854+ table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */)
4855 table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[9]] == 1 && (ip4)), action=(/* drop */)
4856- table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_label.blocked = 1; }; /* drop */)
4857+ table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */)
4858 table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(/* drop */)
4859 table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;)
4860- table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;)
4861- table=??(ls_in_acl_hint ), priority=2 , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;)
4862+ table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
4863+ table=??(ls_in_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
4864 table=??(ls_in_acl_hint ), priority=3 , match=(!ct.est), action=(reg0[[9]] = 1; next;)
4865- table=??(ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
4866+ table=??(ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
4867 table=??(ls_in_acl_hint ), priority=5 , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
4868- table=??(ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
4869+ table=??(ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
4870 table=??(ls_in_acl_hint ), priority=7 , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
4871 ])
4872
4873 AT_CHECK([grep -e "ls_in_lb" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
4874 table=??(ls_in_lb ), priority=0 , match=(1), action=(next;)
4875- table=??(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 10.0.0.2), action=(reg0[[1]] = 0; reg1 = 10.0.0.2; ct_lb(backends=10.0.0.10);)
4876+ table=??(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 10.0.0.2), action=(reg0[[1]] = 0; reg1 = 10.0.0.2; ct_lb_mark(backends=10.0.0.10);)
4877 ])
4878
4879 AT_CHECK([grep -e "ls_in_stateful" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
4880 table=??(ls_in_stateful ), priority=0 , match=(1), action=(next;)
4881- table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;)
4882- table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;)
4883+ table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;)
4884+ table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
4885+])
4886+
4887+AT_CLEANUP
4888+])
4889+
4890+OVN_FOR_EACH_NORTHD([
4891+AT_SETUP([LR neighbor lookup and learning flows])
4892+ovn_start
4893+
4894+# Create logical routers
4895+ovn-nbctl --wait=sb lr-add lr0
4896+
4897+ovn-sbctl dump-flows lr0 > lrflows
4898+AT_CAPTURE_FILE([lrflows])
4899+
4900+AT_CHECK([cat lrflows | grep -e lr_in_lookup_neighbor -e lr_in_learn_neighbor | sort], [0], [dnl
4901+ table=1 (lr_in_lookup_neighbor), priority=0 , match=(1), action=(reg9[[2]] = 1; next;)
4902+ table=1 (lr_in_lookup_neighbor), priority=100 , match=(arp.op == 2), action=(reg9[[2]] = lookup_arp(inport, arp.spa, arp.sha); next;)
4903+ table=1 (lr_in_lookup_neighbor), priority=100 , match=(nd_na), action=(reg9[[2]] = lookup_nd(inport, nd.target, nd.tll); next;)
4904+ table=1 (lr_in_lookup_neighbor), priority=100 , match=(nd_ns), action=(reg9[[2]] = lookup_nd(inport, ip6.src, nd.sll); next;)
4905+ table=2 (lr_in_learn_neighbor), priority=100 , match=(reg9[[2]] == 1), action=(next;)
4906+ table=2 (lr_in_learn_neighbor), priority=90 , match=(arp), action=(put_arp(inport, arp.spa, arp.sha); next;)
4907+ table=2 (lr_in_learn_neighbor), priority=90 , match=(nd_na), action=(put_nd(inport, nd.target, nd.tll); next;)
4908+ table=2 (lr_in_learn_neighbor), priority=90 , match=(nd_ns), action=(put_nd(inport, ip6.src, nd.sll); next;)
4909+ table=2 (lr_in_learn_neighbor), priority=95 , match=(nd_na && nd.tll == 0), action=(put_nd(inport, nd.target, eth.src); next;)
4910+])
4911+
4912+AT_CLEANUP
4913+])
4914+
4915+OVN_FOR_EACH_NORTHD([
4916+AT_SETUP([Load balancer ct_lb_mark backwards compatibility])
4917+AT_KEYWORDS([lb])
4918+ovn_start
4919+
4920+check ovn-nbctl \
4921+ -- ls-add ls \
4922+ -- lr-add lr -- set logical_router lr options:chassis=local \
4923+ -- lb-add lb-test 66.66.66.66 42.42.42.2 \
4924+ -- ls-lb-add ls lb-test \
4925+ -- lr-lb-add lr lb-test
4926+
4927+AS_BOX([No chassis registered - use ct_lb_mark and ct_mark.natted])
4928+check ovn-nbctl --wait=sb sync
4929+AT_CHECK([ovn-sbctl lflow-list | grep -e natted -e ct_lb], [0], [dnl
4930+ table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 66.66.66.66 && ct_mark.natted == 1), action=(next;)
4931+ table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 66.66.66.66), action=(ct_lb_mark(backends=42.42.42.2);)
4932+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && sctp), action=(reg1 = ip4.dst; reg2[[0..15]] = sctp.dst; ct_lb_mark;)
4933+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && tcp), action=(reg1 = ip4.dst; reg2[[0..15]] = tcp.dst; ct_lb_mark;)
4934+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && udp), action=(reg1 = ip4.dst; reg2[[0..15]] = udp.dst; ct_lb_mark;)
4935+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && sctp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = sctp.dst; ct_lb_mark;)
4936+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && tcp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = tcp.dst; ct_lb_mark;)
4937+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && udp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = udp.dst; ct_lb_mark;)
4938+ table=7 (ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;)
4939+ table=12(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 66.66.66.66), action=(reg0[[1]] = 0; reg1 = 66.66.66.66; ct_lb_mark(backends=42.42.42.2);)
4940+ table=2 (ls_out_pre_stateful), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;)
4941+])
4942+
4943+AS_BOX([Chassis registered that doesn't support ct_lb_mark - use ct_lb and ct_label.natted])
4944+check ovn-sbctl chassis-add hv geneve 127.0.0.1
4945+check ovn-nbctl --wait=sb sync
4946+AT_CHECK([ovn-sbctl lflow-list | grep -e natted -e ct_lb], [0], [dnl
4947+ table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 66.66.66.66 && ct_label.natted == 1), action=(next;)
4948+ table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 66.66.66.66), action=(ct_lb(backends=42.42.42.2);)
4949+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && sctp), action=(reg1 = ip4.dst; reg2[[0..15]] = sctp.dst; ct_lb;)
4950+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && tcp), action=(reg1 = ip4.dst; reg2[[0..15]] = tcp.dst; ct_lb;)
4951+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && udp), action=(reg1 = ip4.dst; reg2[[0..15]] = udp.dst; ct_lb;)
4952+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && sctp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = sctp.dst; ct_lb;)
4953+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && tcp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = tcp.dst; ct_lb;)
4954+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && udp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = udp.dst; ct_lb;)
4955+ table=7 (ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb;)
4956+ table=12(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 66.66.66.66), action=(reg0[[1]] = 0; reg1 = 66.66.66.66; ct_lb(backends=42.42.42.2);)
4957+ table=2 (ls_out_pre_stateful), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb;)
4958+])
4959+
4960+AS_BOX([Chassis upgrades and supports ct_lb_mark - use ct_lb_mark and ct_mark.natted])
4961+check ovn-sbctl set chassis hv other_config:ct-no-masked-label=true
4962+check ovn-nbctl --wait=sb sync
4963+AT_CHECK([ovn-sbctl lflow-list | grep -e natted -e ct_lb], [0], [dnl
4964+ table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 66.66.66.66 && ct_mark.natted == 1), action=(next;)
4965+ table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 66.66.66.66), action=(ct_lb_mark(backends=42.42.42.2);)
4966+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && sctp), action=(reg1 = ip4.dst; reg2[[0..15]] = sctp.dst; ct_lb_mark;)
4967+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && tcp), action=(reg1 = ip4.dst; reg2[[0..15]] = tcp.dst; ct_lb_mark;)
4968+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && udp), action=(reg1 = ip4.dst; reg2[[0..15]] = udp.dst; ct_lb_mark;)
4969+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && sctp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = sctp.dst; ct_lb_mark;)
4970+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && tcp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = tcp.dst; ct_lb_mark;)
4971+ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && udp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = udp.dst; ct_lb_mark;)
4972+ table=7 (ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;)
4973+ table=12(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 66.66.66.66), action=(reg0[[1]] = 0; reg1 = 66.66.66.66; ct_lb_mark(backends=42.42.42.2);)
4974+ table=2 (ls_out_pre_stateful), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;)
4975+])
4976+
4977+AT_CLEANUP
4978+])
4979+
4980+OVN_FOR_EACH_NORTHD([
4981+AT_SETUP([ACL ct_mark.blocked backwards compatibility])
4982+AT_KEYWORDS([acl])
4983+ovn_start
4984+
4985+check ovn-nbctl \
4986+ -- ls-add ls \
4987+ -- acl-add ls from-lport 1 1 allow-related \
4988+ -- --apply-after-lb acl-add ls from-lport 1 1 allow-related \
4989+ -- acl-add ls to-lport 1 1 allow-related
4990+
4991+AS_BOX([No chassis registered - use ct_mark.blocked])
4992+check ovn-nbctl --wait=sb sync
4993+AT_CHECK([ovn-sbctl lflow-list | grep 'ls.*acl.*blocked' ], [0], [dnl
4994+ table=8 (ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
4995+ table=8 (ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
4996+ table=8 (ls_in_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;)
4997+ table=8 (ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
4998+ table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;)
4999+ table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
5000+ table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches