diff --git a/.ovn.metadata b/.ovn.metadata index 5e00597..df4ddae 100644 --- a/.ovn.metadata +++ b/.ovn.metadata @@ -1,5 +1,5 @@ 002450621b33c5690060345b0aac25bc2426d675 SOURCES/docutils-0.12.tar.gz -5953db6f7d13eeaa4335f558659865c07abd3d95 SOURCES/openvswitch-ba159ee.tar.gz -54b0b39b351e7b650d4de61ac8029b4b1186896c SOURCES/ovn-22.03.0.tar.gz +18ee4650f5907758dbd949b7b82bfb029666d8f8 SOURCES/openvswitch-6f24c2b.tar.gz +8fc7b574476db8f38307923fd6e476df9b65b009 SOURCES/ovn-22.06.0.tar.gz d34f96421a86004aa5d26ecf975edefd09f948b1 SOURCES/Pygments-1.4.tar.gz 6beb30f18ffac3de7689b7fd63e9a8a7d9c8df3a SOURCES/Sphinx-1.1.3.tar.gz diff --git a/SOURCES/ovn22.03.patch b/SOURCES/ovn22.03.patch deleted file mode 100644 index ef85019..0000000 --- a/SOURCES/ovn22.03.patch +++ /dev/null @@ -1,1351 +0,0 @@ -diff --git a/AUTHORS.rst b/AUTHORS.rst -index 8572c24c8..d3747f8d1 100644 ---- a/AUTHORS.rst -+++ b/AUTHORS.rst -@@ -147,6 +147,7 @@ Fabrizio D'Angelo fdangelo@redhat.com - Flavio Fernandes flavio@flaviof.com - Flavio Leitner fbl@redhat.com - Francesco Fusco ffusco@redhat.com -+François Rigault frigo@amadeus.com - Frank Wang wangpeihuixyz@126.com - Frédéric Tobias Christ fchrist@live.de - Frode Nordahl frode.nordahl@gmail.com -diff --git a/NEWS b/NEWS -index 9f3ce3cf3..15fa545d2 100644 ---- a/NEWS -+++ b/NEWS -@@ -1,4 +1,7 @@ --OVN v22.03.0 - XX XXX XXXX -+OVN v22.03.1 - xx xxx xxxx -+-------------------------- -+ -+OVN v22.03.0 - 11 Mar 2022 - -------------------------- - - Refactor CoPP commands introducing a unique name index in CoPP NB table. - Add following new CoPP commands to manage CoPP table: -diff --git a/configure.ac b/configure.ac -index 283381b4e..70f86e1f5 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -13,7 +13,7 @@ - # limitations under the License. - - AC_PREREQ(2.63) --AC_INIT(ovn, 22.03.0, bugs@openvswitch.org) -+AC_INIT(ovn, 22.03.1, bugs@openvswitch.org) - AC_CONFIG_MACRO_DIR([m4]) - AC_CONFIG_AUX_DIR([build-aux]) - AC_CONFIG_HEADERS([config.h]) -diff --git a/controller-vtep/binding.c b/controller-vtep/binding.c -index 01d5a16d2..1ee52b592 100644 ---- a/controller-vtep/binding.c -+++ b/controller-vtep/binding.c -@@ -109,12 +109,10 @@ update_pb_chassis(const struct sbrec_port_binding *port_binding_rec, - port_binding_rec->chassis->name, - chassis_rec->name); - } -- - sbrec_port_binding_set_chassis(port_binding_rec, chassis_rec); -- if (port_binding_rec->n_up) { -- bool up = true; -- sbrec_port_binding_set_up(port_binding_rec, &up, 1); -- } -+ } else if (port_binding_rec->n_up) { -+ bool up = true; -+ sbrec_port_binding_set_up(port_binding_rec, &up, 1); - } - } - -diff --git a/controller/binding.c b/controller/binding.c -index 4d62b0858..1259e6b3b 100644 ---- a/controller/binding.c -+++ b/controller/binding.c -@@ -481,6 +481,16 @@ remove_related_lport(const struct sbrec_port_binding *pb, - } - } - -+static void -+delete_active_pb_ras_pd(const struct sbrec_port_binding *pb, -+ struct shash *ras_pd_map) -+{ -+ struct pb_ld_binding *ras_pd = -+ shash_find_and_delete(ras_pd_map, pb->logical_port); -+ -+ free(ras_pd); -+} -+ - static void - update_active_pb_ras_pd(const struct sbrec_port_binding *pb, - struct hmap *local_datapaths, -@@ -2251,6 +2261,9 @@ binding_handle_port_binding_changes(struct binding_ctx_in *b_ctx_in, - continue; - } - -+ delete_active_pb_ras_pd(pb, b_ctx_out->local_active_ports_ipv6_pd); -+ delete_active_pb_ras_pd(pb, b_ctx_out->local_active_ports_ras); -+ - enum en_lport_type lport_type = get_lport_type(pb); - - struct binding_lport *b_lport = -diff --git a/controller/ofctrl.c b/controller/ofctrl.c -index a7c2d2011..3b9d71733 100644 ---- a/controller/ofctrl.c -+++ b/controller/ofctrl.c -@@ -943,7 +943,12 @@ link_installed_to_desired(struct installed_flow *i, struct desired_flow *d) - break; - } - } -- ovs_list_insert(&f->installed_ref_list_node, &d->installed_ref_list_node); -+ if (!f) { -+ ovs_list_insert(&i->desired_refs, &d->installed_ref_list_node); -+ } else { -+ ovs_list_insert(&f->installed_ref_list_node, -+ &d->installed_ref_list_node); -+ } - d->installed_flow = i; - return installed_flow_get_active(i) == d; - } -@@ -2324,7 +2329,20 @@ deleted_flow_lookup(struct hmap *deleted_flows, struct ovn_flow *target) - && f->cookie == target->cookie - && ofpacts_equal(f->ofpacts, f->ofpacts_len, target->ofpacts, - target->ofpacts_len)) { -- return d; -+ /* del_f must have been installed, otherwise it should have -+ * been removed during track_flow_del. */ -+ ovs_assert(d->installed_flow); -+ -+ /* Now we also need to make sure the desired flow being -+ * added/updated has exact same action and cookie as the installed -+ * flow of d. Otherwise, don't merge them, so that the -+ * installed flow can be updated later. */ -+ struct ovn_flow *f_i = &d->installed_flow->flow; -+ if (f_i->cookie == target->cookie -+ && ofpacts_equal(f_i->ofpacts, f_i->ofpacts_len, -+ target->ofpacts, target->ofpacts_len)) { -+ return d; -+ } - } - } - return NULL; -@@ -2353,10 +2371,6 @@ merge_tracked_flows(struct ovn_desired_flow_table *flow_table) - continue; - } - -- /* del_f must have been installed, otherwise it should have been -- * removed during track_flow_add_or_modify. */ -- ovs_assert(del_f->installed_flow); -- - if (!f->installed_flow) { - /* f is not installed yet. */ - replace_installed_to_desired(del_f->installed_flow, del_f, f); -@@ -2665,6 +2679,13 @@ ofctrl_put(struct ovn_desired_flow_table *lflow_table, - EXTEND_TABLE_FOR_EACH_INSTALLED (m_installed, next_meter, meters) { - /* Delete the meter. */ - ofctrl_meter_bands_erase(m_installed, &msgs); -+ if (!strncmp(m_installed->name, "__string: ", 10)) { -+ struct ofputil_meter_mod mm = { -+ .command = OFPMC13_DELETE, -+ .meter = { .meter_id = m_installed->table_id }, -+ }; -+ add_meter_mod(&mm, &msgs); -+ } - ovn_extend_table_remove_existing(meters, m_installed); - } - -diff --git a/controller/pinctrl.c b/controller/pinctrl.c -index 25b37ee88..2f718aca7 100644 ---- a/controller/pinctrl.c -+++ b/controller/pinctrl.c -@@ -5523,7 +5523,7 @@ get_localnet_vifs_l3gwports( - } - const struct sbrec_port_binding *pb - = lport_lookup_by_name(sbrec_port_binding_by_name, iface_id); -- if (!pb) { -+ if (!pb || pb->chassis != chassis) { - continue; - } - struct local_datapath *ld -@@ -5554,7 +5554,7 @@ get_localnet_vifs_l3gwports( - sbrec_port_binding_index_set_datapath(target, ld->datapath); - SBREC_PORT_BINDING_FOR_EACH_EQUAL (pb, target, - sbrec_port_binding_by_datapath) { -- if (!strcmp(pb->type, "l3gateway") -+ if ((!strcmp(pb->type, "l3gateway") && pb->chassis == chassis) - || !strcmp(pb->type, "patch")) { - sset_add(local_l3gw_ports, pb->logical_port); - } -@@ -5781,7 +5781,8 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn *ovnsb_idl_txn, - const struct sbrec_port_binding *pb = lport_lookup_by_name( - sbrec_port_binding_by_name, iface_id); - if (pb) { -- send_garp_rarp_update(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip, -+ send_garp_rarp_update(ovnsb_idl_txn, -+ sbrec_mac_binding_by_lport_ip, - local_datapaths, pb, &nat_addresses); - } - } -diff --git a/debian/changelog b/debian/changelog -index f1167591b..18a1a042e 100644 ---- a/debian/changelog -+++ b/debian/changelog -@@ -1,3 +1,9 @@ -+OVN (22.03.1-1) unstable; urgency=low -+ [ OVN team ] -+ * New upstream version -+ -+ -- OVN team Fri, 11 Mar 2022 13:22:32 -0500 -+ - ovn (22.03.0-1) unstable; urgency=low - - * New upstream version -diff --git a/lib/actions.c b/lib/actions.c -index 5d3caaf2b..2219c5b37 100644 ---- a/lib/actions.c -+++ b/lib/actions.c -@@ -2336,7 +2336,7 @@ validate_empty_lb_backends(struct action_context *ctx, - - switch (o->option->code) { - case EMPTY_LB_VIP: -- if (!inet_parse_active(c->string, 0, &ss, false)) { -+ if (!inet_parse_active(c->string, 0, &ss, false, NULL)) { - lexer_error(ctx->lexer, "Invalid load balancer VIP '%s'", - c->string); - return; -diff --git a/lib/expr.c b/lib/expr.c -index 47ef6108e..058390a16 100644 ---- a/lib/expr.c -+++ b/lib/expr.c -@@ -211,16 +211,17 @@ expr_combine(enum expr_type type, struct expr *a, struct expr *b) - } - - static void --expr_insert_andor(struct expr *andor, struct expr *before, struct expr *new) -+expr_insert_andor(struct expr *andor, struct ovs_list *before, -+ struct expr *new) - { - if (new->type == andor->type) { - if (andor->type == EXPR_T_AND) { - /* Conjunction junction, what's your function? */ - } -- ovs_list_splice(&before->node, new->andor.next, &new->andor); -+ ovs_list_splice(before, new->andor.next, &new->andor); - expr_destroy(new); - } else { -- ovs_list_insert(&before->node, &new->node); -+ ovs_list_insert(before, &new->node); - } - } - -@@ -2101,7 +2102,8 @@ expr_annotate__(struct expr *expr, const struct shash *symtab, - expr_destroy(expr); - return NULL; - } -- expr_insert_andor(expr, next, new_sub); -+ expr_insert_andor(expr, next ? &next->node : &expr->andor, -+ new_sub); - } - *errorp = NULL; - return expr; -@@ -2301,7 +2303,7 @@ expr_evaluate_condition(struct expr *expr, - struct expr *e = expr_evaluate_condition(sub, is_chassis_resident, - c_aux); - e = expr_fix(e); -- expr_insert_andor(expr, next, e); -+ expr_insert_andor(expr, next ? &next->node : &expr->andor, e); - } - return expr_fix(expr); - -@@ -2334,7 +2336,8 @@ expr_simplify(struct expr *expr) - case EXPR_T_OR: - LIST_FOR_EACH_SAFE (sub, next, node, &expr->andor) { - ovs_list_remove(&sub->node); -- expr_insert_andor(expr, next, expr_simplify(sub)); -+ expr_insert_andor(expr, next ? &next->node : &expr->andor, -+ expr_simplify(sub)); - } - return expr_fix(expr); - -@@ -2444,12 +2447,13 @@ crush_and_string(struct expr *expr, const struct expr_symbol *symbol) - * EXPR_T_OR with EXPR_T_CMP subexpressions. */ - struct expr *sub, *next = NULL; - LIST_FOR_EACH_SAFE (sub, next, node, &expr->andor) { -+ struct ovs_list *next_list = next ? &next->node : &expr->andor; - ovs_list_remove(&sub->node); - struct expr *new = crush_cmps(sub, symbol); - switch (new->type) { - case EXPR_T_CMP: - if (!singleton) { -- ovs_list_insert(&next->node, &new->node); -+ ovs_list_insert(next_list, &new->node); - singleton = new; - } else { - bool match = !strcmp(new->cmp.string, singleton->cmp.string); -@@ -2463,7 +2467,7 @@ crush_and_string(struct expr *expr, const struct expr_symbol *symbol) - case EXPR_T_AND: - OVS_NOT_REACHED(); - case EXPR_T_OR: -- ovs_list_insert(&next->node, &new->node); -+ ovs_list_insert(next_list, &new->node); - break; - case EXPR_T_BOOLEAN: - if (!new->boolean) { -@@ -2559,7 +2563,7 @@ crush_and_numeric(struct expr *expr, const struct expr_symbol *symbol) - case EXPR_T_AND: - OVS_NOT_REACHED(); - case EXPR_T_OR: -- ovs_list_insert(&next->node, &new->node); -+ ovs_list_insert(next ? &next->node : &expr->andor, &new->node); - break; - case EXPR_T_BOOLEAN: - if (!new->boolean) { -@@ -2725,7 +2729,8 @@ crush_or(struct expr *expr, const struct expr_symbol *symbol) - * is now a disjunction of cmps over the same symbol. */ - LIST_FOR_EACH_SAFE (sub, next, node, &expr->andor) { - ovs_list_remove(&sub->node); -- expr_insert_andor(expr, next, crush_cmps(sub, symbol)); -+ expr_insert_andor(expr, next ? &next->node : &expr->andor, -+ crush_cmps(sub, symbol)); - } - expr = expr_fix(expr); - if (expr->type != EXPR_T_OR) { -@@ -2886,8 +2891,7 @@ expr_normalize_and(struct expr *expr) - - struct expr *a, *b; - LIST_FOR_EACH_SAFE (a, b, node, &expr->andor) { -- if (&b->node == &expr->andor -- || a->type != EXPR_T_CMP || b->type != EXPR_T_CMP -+ if (!b || a->type != EXPR_T_CMP || b->type != EXPR_T_CMP - || a->cmp.symbol != b->cmp.symbol) { - continue; - } else if (a->cmp.symbol->width -@@ -2964,7 +2968,8 @@ expr_normalize_or(struct expr *expr) - } - expr_destroy(new); - } else { -- expr_insert_andor(expr, next, new); -+ expr_insert_andor(expr, next ? &next->node : &expr->andor, -+ new); - } - } else { - ovs_assert(sub->type == EXPR_T_CMP || -diff --git a/lib/inc-proc-eng.c b/lib/inc-proc-eng.c -index 7b4391700..575b774ae 100644 ---- a/lib/inc-proc-eng.c -+++ b/lib/inc-proc-eng.c -@@ -354,14 +354,11 @@ engine_recompute(struct engine_node *node, bool allowed, - const char *reason_fmt, ...) - { - char *reason = NULL; -+ va_list reason_args; - -- if (VLOG_IS_DBG_ENABLED()) { -- va_list reason_args; -- -- va_start(reason_args, reason_fmt); -- reason = xvasprintf(reason_fmt, reason_args); -- va_end(reason_args); -- } -+ va_start(reason_args, reason_fmt); -+ reason = xvasprintf(reason_fmt, reason_args); -+ va_end(reason_args); - - if (!allowed) { - VLOG_DBG("node: %s, recompute (%s) aborted", node->name, reason); -diff --git a/lib/ovn-parallel-hmap.h b/lib/ovn-parallel-hmap.h -index 897208ef8..0f7d68770 100644 ---- a/lib/ovn-parallel-hmap.h -+++ b/lib/ovn-parallel-hmap.h -@@ -58,11 +58,11 @@ extern "C" { - * ThreadID + step * i as the JOBID parameter. - */ - --#define HMAP_FOR_EACH_IN_PARALLEL(NODE, MEMBER, JOBID, HMAP) \ -- for (INIT_CONTAINER(NODE, hmap_first_in_bucket_num(HMAP, JOBID), MEMBER); \ -- (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)) \ -- || ((NODE = NULL), false); \ -- ASSIGN_CONTAINER(NODE, hmap_next_in_bucket(&(NODE)->MEMBER), MEMBER)) -+#define HMAP_FOR_EACH_IN_PARALLEL(NODE, MEMBER, JOBID, HMAP) \ -+ for (INIT_MULTIVAR(NODE, MEMBER, hmap_first_in_bucket_num(HMAP, JOBID), \ -+ struct hmap_node); \ -+ CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL); \ -+ UPDATE_MULTIVAR(NODE, hmap_next_in_bucket(ITER_VAR(NODE)))) - - /* We do not have a SAFE version of the macro, because the hash size is not - * atomic and hash removal operations would need to be wrapped with -diff --git a/lib/ovn-util.c b/lib/ovn-util.c -index a22ae84fe..2f2f7ae39 100644 ---- a/lib/ovn-util.c -+++ b/lib/ovn-util.c -@@ -735,7 +735,7 @@ ip_address_and_port_from_lb_key(const char *key, char **ip_address, - uint16_t *port, int *addr_family) - { - struct sockaddr_storage ss; -- if (!inet_parse_active(key, 0, &ss, false)) { -+ if (!inet_parse_active(key, 0, &ss, false, NULL)) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); - VLOG_WARN_RL(&rl, "bad ip address or port for load balancer key %s", - key); -diff --git a/northd/northd.c b/northd/northd.c -index b22da67e9..217f180eb 100644 ---- a/northd/northd.c -+++ b/northd/northd.c -@@ -763,16 +763,6 @@ init_nat_entries(struct ovn_datapath *od) - return; - } - -- if (od->n_l3dgw_ports > 1) { -- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); -- VLOG_WARN_RL(&rl, "NAT is configured on logical router %s, which has %" -- PRIuSIZE" distributed gateway ports. NAT is not supported" -- " yet when there is more than one distributed gateway " -- "port on the router.", -- od->nbr->name, od->n_l3dgw_ports); -- return; -- } -- - od->nat_entries = xmalloc(od->nbr->n_nat * sizeof *od->nat_entries); - - for (size_t i = 0; i < od->nbr->n_nat; i++) { -@@ -6418,6 +6408,72 @@ ovn_port_group_destroy(struct hmap *pgs, struct ovn_port_group *pg) - } - } - -+static void -+copy_ra_to_sb(struct ovn_port *op, const char *address_mode); -+ -+static void -+ovn_update_ipv6_options(struct hmap *ports) -+{ -+ struct ovn_port *op; -+ HMAP_FOR_EACH (op, key_node, ports) { -+ if (!op->nbrp || op->nbrp->peer || !op->peer) { -+ continue; -+ } -+ -+ if (!op->lrp_networks.n_ipv6_addrs) { -+ continue; -+ } -+ -+ struct smap options; -+ smap_clone(&options, &op->sb->options); -+ -+ /* enable IPv6 prefix delegation */ -+ bool prefix_delegation = smap_get_bool(&op->nbrp->options, -+ "prefix_delegation", false); -+ if (!lrport_is_enabled(op->nbrp)) { -+ prefix_delegation = false; -+ } -+ if (smap_get_bool(&options, "ipv6_prefix_delegation", -+ false) != prefix_delegation) { -+ smap_add(&options, "ipv6_prefix_delegation", -+ prefix_delegation ? "true" : "false"); -+ } -+ -+ bool ipv6_prefix = smap_get_bool(&op->nbrp->options, -+ "prefix", false); -+ if (!lrport_is_enabled(op->nbrp)) { -+ ipv6_prefix = false; -+ } -+ if (smap_get_bool(&options, "ipv6_prefix", false) != ipv6_prefix) { -+ smap_add(&options, "ipv6_prefix", -+ ipv6_prefix ? "true" : "false"); -+ } -+ sbrec_port_binding_set_options(op->sb, &options); -+ -+ smap_destroy(&options); -+ -+ const char *address_mode = smap_get( -+ &op->nbrp->ipv6_ra_configs, "address_mode"); -+ -+ if (!address_mode) { -+ continue; -+ } -+ if (strcmp(address_mode, "slaac") && -+ strcmp(address_mode, "dhcpv6_stateful") && -+ strcmp(address_mode, "dhcpv6_stateless")) { -+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); -+ VLOG_WARN_RL(&rl, "Invalid address mode [%s] defined", -+ address_mode); -+ continue; -+ } -+ -+ if (smap_get_bool(&op->nbrp->ipv6_ra_configs, "send_periodic", -+ false)) { -+ copy_ra_to_sb(op, address_mode); -+ } -+ } -+} -+ - static void - build_port_group_lswitches(struct northd_input *input_data, - struct hmap *pgs, -@@ -10759,6 +10815,12 @@ build_neigh_learning_flows_for_lrouter( - copp_meter_get(COPP_ARP, od->nbr->copp, - meter_groups)); - -+ ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 95, -+ "nd_na && nd.tll == 0", -+ "put_nd(inport, nd.target, eth.src); next;", -+ copp_meter_get(COPP_ND_NA, od->nbr->copp, -+ meter_groups)); -+ - ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90, - "nd_na", "put_nd(inport, nd.target, nd.tll); next;", - copp_meter_get(COPP_ND_NA, od->nbr->copp, -@@ -10851,34 +10913,6 @@ build_ND_RA_flows_for_lrouter_port( - return; - } - -- struct smap options; -- smap_clone(&options, &op->sb->options); -- -- /* enable IPv6 prefix delegation */ -- bool prefix_delegation = smap_get_bool(&op->nbrp->options, -- "prefix_delegation", false); -- if (!lrport_is_enabled(op->nbrp)) { -- prefix_delegation = false; -- } -- if (smap_get_bool(&options, "ipv6_prefix_delegation", -- false) != prefix_delegation) { -- smap_add(&options, "ipv6_prefix_delegation", -- prefix_delegation ? "true" : "false"); -- } -- -- bool ipv6_prefix = smap_get_bool(&op->nbrp->options, -- "prefix", false); -- if (!lrport_is_enabled(op->nbrp)) { -- ipv6_prefix = false; -- } -- if (smap_get_bool(&options, "ipv6_prefix", false) != ipv6_prefix) { -- smap_add(&options, "ipv6_prefix", -- ipv6_prefix ? "true" : "false"); -- } -- sbrec_port_binding_set_options(op->sb, &options); -- -- smap_destroy(&options); -- - const char *address_mode = smap_get( - &op->nbrp->ipv6_ra_configs, "address_mode"); - -@@ -10894,11 +10928,6 @@ build_ND_RA_flows_for_lrouter_port( - return; - } - -- if (smap_get_bool(&op->nbrp->ipv6_ra_configs, "send_periodic", -- false)) { -- copy_ra_to_sb(op, address_mode); -- } -- - ds_clear(match); - ds_put_format(match, "inport == %s && ip6.dst == ff02::2 && nd_rs", - op->json_key); -@@ -12805,6 +12834,7 @@ build_lrouter_out_snat_flow(struct hmap *lflows, struct ovn_datapath *od, - ds_put_format(actions, "ip%s.src=%s; next;", - is_v6 ? "6" : "4", nat->external_ip); - } else { -+ ds_put_format(match, " && (!ct.trk || !ct.rpl)"); - ds_put_format(actions, "ct_snat(%s", nat->external_ip); - - if (nat->external_port_range[0]) { -@@ -13155,6 +13185,18 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, - return; - } - -+ /* NAT rules are not currently supported on logical routers with multiple -+ * distributed gateway ports. */ -+ if (od->n_l3dgw_ports > 1) { -+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); -+ VLOG_WARN_RL(&rl, "NAT is configured on logical router %s, which has %" -+ PRIuSIZE" distributed gateway ports. NAT is not supported" -+ " yet when there is more than one distributed gateway " -+ "port on the router.", -+ od->nbr->name, od->n_l3dgw_ports); -+ return; -+ } -+ - struct sset nat_entries = SSET_INITIALIZER(&nat_entries); - - bool dnat_force_snat_ip = -@@ -15048,6 +15090,7 @@ ovnnb_db_run(struct northd_input *input_data, - build_meter_groups(input_data, &data->meter_groups); - stopwatch_stop(BUILD_LFLOWS_CTX_STOPWATCH_NAME, time_msec()); - stopwatch_start(CLEAR_LFLOWS_CTX_STOPWATCH_NAME, time_msec()); -+ ovn_update_ipv6_options(&data->ports); - ovn_update_ipv6_prefix(&data->ports); - - sync_address_sets(input_data, ovnsb_txn, &data->datapaths); -diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml -index 1c9d408af..4cb70e185 100644 ---- a/northd/ovn-northd.8.xml -+++ b/northd/ovn-northd.8.xml -@@ -2301,6 +2301,12 @@ next; - put_arp(inport, arp.spa, arp.sha); next; - - -+
  • -+ A priority-95 flow with the match nd_na && -+ nd.tll == 0 and applies the action -+ put_nd(inport, nd.target, eth.src); next; -+
  • -+ -
  • - A priority-90 flow with the match nd_na and - applies the action -@@ -4452,7 +4458,8 @@ nd_ns { - to change the source IP address of a packet from an IP address of - A or to change the source IP address of a packet that - belongs to network A to B, a flow matches -- ip && ip4.src == A with an action -+ ip && ip4.src == A && -+ (!ct.trk || !ct.rpl) with an action - ct_snat(B);. The priority of the flow - is calculated based on the mask of A, with matches - having larger masks getting higher priorities. If the NAT rule is -diff --git a/rhel/ovn-fedora.spec.in b/rhel/ovn-fedora.spec.in -index 3fb854a37..821eb03cc 100644 ---- a/rhel/ovn-fedora.spec.in -+++ b/rhel/ovn-fedora.spec.in -@@ -323,7 +323,7 @@ ln -sf ovn_detrace.py %{_bindir}/ovn-detrace - %if %{with libcapng} - if [ $1 -eq 1 ]; then - sed -i 's:^#OVN_USER_ID=:OVN_USER_ID=:' %{_sysconfdir}/sysconfig/ovn -- sed -i 's:\(.*su\).*:\1 ovn ovn:' %{_sysconfdir}/logrotate.d/ovn -+ sed -i 's:\(.*su\).*:\1 openvswitch openvswitch:' %{_sysconfdir}/logrotate.d/ovn - fi - %endif - -diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at -index 3865003bf..b7dfcd151 100644 ---- a/tests/ovn-northd.at -+++ b/tests/ovn-northd.at -@@ -1030,7 +1030,7 @@ AT_CHECK([grep -e "lr_out_snat" drflows | sed 's/table=../table=??/' | sort], [0 - AT_CHECK([grep -e "lr_out_snat" crflows | sed 's/table=../table=??/' | sort], [0], [dnl - table=??(lr_out_snat ), priority=0 , match=(1), action=(next;) - table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) -- 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);) -+ 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);) - ]) - - -@@ -1062,7 +1062,7 @@ AT_CHECK([grep -e "lr_out_snat" drflows2 | sed 's/table=../table=??/' | sort], [ - AT_CHECK([grep -e "lr_out_snat" crflows2 | sed 's/table=../table=??/' | sort], [0], [dnl - table=??(lr_out_snat ), priority=0 , match=(1), action=(next;) - table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) -- table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == 50.0.0.11), action=(ct_snat(172.16.1.1);) -+ 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);) - table=??(lr_out_snat ), priority=35 , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $disallowed_range), action=(next;) - ]) - -@@ -1091,7 +1091,7 @@ AT_CHECK([grep -e "lr_out_snat" drflows3 | sed 's/table=../table=??/' | sort], [ - AT_CHECK([grep -e "lr_out_snat" crflows3 | sed 's/table=../table=??/' | sort], [0], [dnl - table=??(lr_out_snat ), priority=0 , match=(1), action=(next;) - table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) -- 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);) -+ 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);) - ]) - - # Stateful FIP with DISALLOWED_IPs -@@ -1120,7 +1120,7 @@ AT_CHECK([grep -e "lr_out_snat" drflows4 | sed 's/table=../table=??/' | sort], [ - AT_CHECK([grep -e "lr_out_snat" crflows4 | sed 's/table=../table=??/' | sort], [0], [dnl - table=??(lr_out_snat ), priority=0 , match=(1), action=(next;) - table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) -- table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == 50.0.0.11), action=(ct_snat(172.16.1.2);) -+ 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);) - table=??(lr_out_snat ), priority=35 , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $disallowed_range), action=(next;) - ]) - -@@ -3447,7 +3447,7 @@ ls_copp_uuid=$(fetch_column nb:Logical_Switch copp) - AT_CHECK([test "$ls_copp_uuid" = "$copp_uuid"]) - - check ovn-nbctl --wait=hv copp-add $copp_uuid igmp meter0 --AT_CHECK([ovn-nbctl copp-list copp0], [0], [dnl -+AT_CHECK([ovn-nbctl copp-list copp0 | sort], [0], [dnl - arp: meter0 - igmp: meter0 - ]) -@@ -5140,11 +5140,12 @@ AT_CHECK([grep "lr_out_post_undnat" lr0flows | sed 's/table=./table=?/' | sort], - AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl - table=? (lr_out_snat ), priority=0 , match=(1), action=(next;) - table=? (lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) -- table=? (lr_out_snat ), priority=25 , match=(ip && ip4.src == 10.0.0.0/24), action=(ct_snat(172.168.0.10);) -- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.10), action=(ct_snat(172.168.0.30);) -- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.3), action=(ct_snat(172.168.0.20);) -+ 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);) -+ 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);) -+ 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);) - ]) - -+ - # Set lb force snat logical router. - check ovn-nbctl --wait=sb set logical_router lr0 options:lb_force_snat_ip="router_ip" - check ovn-nbctl --wait=sb sync -@@ -5201,9 +5202,9 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [ - table=? (lr_out_snat ), priority=110 , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"), action=(ct_snat(172.168.0.10);) - table=? (lr_out_snat ), priority=110 , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"), action=(ct_snat(10.0.0.1);) - table=? (lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) -- table=? (lr_out_snat ), priority=25 , match=(ip && ip4.src == 10.0.0.0/24), action=(ct_snat(172.168.0.10);) -- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.10), action=(ct_snat(172.168.0.30);) -- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.3), action=(ct_snat(172.168.0.20);) -+ 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);) -+ 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);) -+ 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);) - ]) - - # Add a LB VIP same as router ip. -@@ -5266,9 +5267,9 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [ - table=? (lr_out_snat ), priority=110 , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"), action=(ct_snat(172.168.0.10);) - table=? (lr_out_snat ), priority=110 , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"), action=(ct_snat(10.0.0.1);) - table=? (lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) -- table=? (lr_out_snat ), priority=25 , match=(ip && ip4.src == 10.0.0.0/24), action=(ct_snat(172.168.0.10);) -- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.10), action=(ct_snat(172.168.0.30);) -- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.3), action=(ct_snat(172.168.0.20);) -+ 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);) -+ 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);) -+ 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);) - ]) - - # Add IPv6 router port and LB. -@@ -5346,9 +5347,9 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [ - table=? (lr_out_snat ), priority=110 , match=(flags.force_snat_for_lb == 1 && ip6 && outport == "lr0-public"), action=(ct_snat(def0::10);) - table=? (lr_out_snat ), priority=110 , match=(flags.force_snat_for_lb == 1 && ip6 && outport == "lr0-sw0"), action=(ct_snat(aef0::1);) - table=? (lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) -- table=? (lr_out_snat ), priority=25 , match=(ip && ip4.src == 10.0.0.0/24), action=(ct_snat(172.168.0.10);) -- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.10), action=(ct_snat(172.168.0.30);) -- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.3), action=(ct_snat(172.168.0.20);) -+ 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);) -+ 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);) -+ 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);) - ]) - - check ovn-nbctl lrp-del lr0-sw0 -@@ -5804,6 +5805,12 @@ AT_CHECK([grep lr_in_gw_redirect lrflows | grep cr-DR | sed 's/table=../table=?? - table=??(lr_in_gw_redirect ), priority=50 , match=(outport == "DR-S3"), action=(outport = "cr-DR-S3"; next;) - ]) - -+# Check that ovn-northd logs a warning when trying to configure NAT -+# on the router with multiple distributed gw ports. Such configurations are -+# not supported yet. -+check ovn-nbctl lr-nat-add DR dnat_and_snat 42.42.42.1 20.0.0.2 -+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]) -+ - AT_CLEANUP - ]) - -@@ -6426,3 +6433,28 @@ AT_CHECK([grep -e "ls_in_stateful" lsflows | sed 's/table=../table=??/' | sort], - - AT_CLEANUP - ]) -+ -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([LR neighbor lookup and learning flows]) -+ovn_start -+ -+# Create logical routers -+ovn-nbctl --wait=sb lr-add lr0 -+ -+ovn-sbctl dump-flows lr0 > lrflows -+AT_CAPTURE_FILE([lrflows]) -+ -+AT_CHECK([cat lrflows | grep -e lr_in_lookup_neighbor -e lr_in_learn_neighbor | sort], [0], [dnl -+ table=1 (lr_in_lookup_neighbor), priority=0 , match=(1), action=(reg9[[2]] = 1; next;) -+ table=1 (lr_in_lookup_neighbor), priority=100 , match=(arp.op == 2), action=(reg9[[2]] = lookup_arp(inport, arp.spa, arp.sha); next;) -+ table=1 (lr_in_lookup_neighbor), priority=100 , match=(nd_na), action=(reg9[[2]] = lookup_nd(inport, nd.target, nd.tll); next;) -+ table=1 (lr_in_lookup_neighbor), priority=100 , match=(nd_ns), action=(reg9[[2]] = lookup_nd(inport, ip6.src, nd.sll); next;) -+ table=2 (lr_in_learn_neighbor), priority=100 , match=(reg9[[2]] == 1), action=(next;) -+ table=2 (lr_in_learn_neighbor), priority=90 , match=(arp), action=(put_arp(inport, arp.spa, arp.sha); next;) -+ table=2 (lr_in_learn_neighbor), priority=90 , match=(nd_na), action=(put_nd(inport, nd.target, nd.tll); next;) -+ table=2 (lr_in_learn_neighbor), priority=90 , match=(nd_ns), action=(put_nd(inport, ip6.src, nd.sll); next;) -+ table=2 (lr_in_learn_neighbor), priority=95 , match=(nd_na && nd.tll == 0), action=(put_nd(inport, nd.target, eth.src); next;) -+]) -+ -+AT_CLEANUP -+]) -diff --git a/tests/ovn.at b/tests/ovn.at -index 4f65d1ecd..4ee9aebc9 100644 ---- a/tests/ovn.at -+++ b/tests/ovn.at -@@ -8588,6 +8588,114 @@ OVN_CLEANUP([hv1]) - AT_CLEANUP - ]) - -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([send gratuitous arp for l3gateway only on selected chassis]) -+ovn_start -+ -+# Create logical switch -+ovn-nbctl ls-add ls0 -+# Create gateway router -+ovn-nbctl lr-add lr0 -+# Add router port to gateway router -+ovn-nbctl lrp-add lr0 lr0-ls0 f0:00:00:00:00:01 192.168.0.1/24 -+ovn-nbctl lsp-add ls0 ls0-lr0 -- set Logical_Switch_Port ls0-lr0 \ -+ type=router options:router-port=lr0-ls0 addresses='"f0:00:00:00:00:01"' -+ -+# Create a localnet port. -+ovn-nbctl lsp-add ls0 ln_port -+ovn-nbctl lsp-set-addresses ln_port unknown -+ovn-nbctl lsp-set-type ln_port localnet -+ovn-nbctl --wait=hv lsp-set-options ln_port network_name=physnet1 -+ -+# Prepare packets -+touch empty_expected -+echo "fffffffffffff0000000000108060001080006040001f00000000001c0a80001000000000000c0a80001" > arp_expected -+ -+net_add n1 -+sim_add hv1 -+as hv1 -+ovs-vsctl \ -+ -- add-br br-phys \ -+ -- add-br br-eth0 -+ -+ovn_attach n1 br-phys 192.168.0.10 -+ -+AT_CHECK([ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=physnet1:br-eth0]) -+AT_CHECK([ovs-vsctl add-port br-eth0 snoopvif -- set Interface snoopvif options:tx_pcap=hv1/snoopvif-tx.pcap options:rxq_pcap=hv1/snoopvif-rx.pcap]) -+ -+sim_add hv2 -+as hv2 -+ovs-vsctl \ -+ -- add-br br-phys \ -+ -- add-br br-eth0 -+ -+ovn_attach n1 br-phys 192.168.0.20 -+ -+AT_CHECK([ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=physnet1:br-eth0]) -+AT_CHECK([ovs-vsctl add-port br-eth0 snoopvif -- set Interface snoopvif options:tx_pcap=hv2/snoopvif-tx.pcap options:rxq_pcap=hv2/snoopvif-rx.pcap]) -+ -+ovn-sbctl dump-flows > sbflows -+AT_CAPTURE_FILE([sbflows]) -+ -+# Wait until the patch ports are created in hv1 and hv2 to connect br-int to br-eth0 -+AT_CHECK([ovn-nbctl set logical_router lr0 options:chassis=hv1]) -+OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-vsctl show | \ -+grep "Port patch-br-int-to-ln_port" | wc -l`]) -+AT_CHECK([ovn-nbctl set logical_router lr0 options:chassis=hv2]) -+OVS_WAIT_UNTIL([test 1 = `as hv2 ovs-vsctl show | \ -+grep "Port patch-br-int-to-ln_port" | wc -l`]) -+ -+# Temporarily remove lr0 chassis -+AT_CHECK([ovn-nbctl remove logical_router lr0 options chassis]) -+ -+reset_pcap_file() { -+ local hv=$1 -+ local iface=$2 -+ local pcap_file=$3 -+ as $hv -+ ovs-vsctl -- set Interface $iface options:tx_pcap=dummy-tx.pcap \ -+options:rxq_pcap=dummy-rx.pcap -+ rm -f ${pcap_file}*.pcap -+ ovs-vsctl -- set Interface $iface options:tx_pcap=${pcap_file}-tx.pcap \ -+options:rxq_pcap=${pcap_file}-rx.pcap -+} -+ -+reset_pcap_file hv1 snoopvif hv1/snoopvif -+reset_pcap_file hv2 snoopvif hv2/snoopvif -+ -+hv1_uuid=$(ovn-sbctl --bare --columns _uuid list chassis hv1) -+AT_CHECK([ovn-nbctl set logical_router lr0 options:chassis=hv1]) -+OVS_WAIT_UNTIL([ -+ ls0_lr0=$(ovn-sbctl --bare --columns chassis list port_binding ls0-lr0) -+ test "$ls0_lr0" = $hv1_uuid -+]) -+ -+sleep 2 -+OVN_CHECK_PACKETS_CONTAIN([hv1/snoopvif-tx.pcap], [arp_expected]) -+OVN_CHECK_PACKETS([hv2/snoopvif-tx.pcap], [empty_expected]) -+ -+# Temporarily remove lr0 chassis -+AT_CHECK([ovn-nbctl remove logical_router lr0 options chassis]) -+ -+reset_pcap_file hv1 snoopvif hv1/snoopvif -+reset_pcap_file hv2 snoopvif hv2/snoopvif -+ -+hv2_uuid=$(ovn-sbctl --bare --columns _uuid list chassis hv2) -+AT_CHECK([ovn-nbctl set logical_router lr0 options:chassis=hv2]) -+OVS_WAIT_UNTIL([ -+ ls0_lr0=$(ovn-sbctl --bare --columns chassis list port_binding ls0-lr0) -+ test "$ls0_lr0" = $hv2_uuid -+]) -+ -+sleep 2 -+OVN_CHECK_PACKETS_CONTAIN([hv2/snoopvif-tx.pcap], [arp_expected]) -+OVN_CHECK_PACKETS([hv1/snoopvif-tx.pcap], [empty_expected]) -+ -+OVN_CLEANUP([hv1],[hv2]) -+ -+AT_CLEANUP -+]) -+ - OVN_FOR_EACH_NORTHD([ - AT_SETUP([send gratuitous arp with nat-addresses router in localnet]) - ovn_start -@@ -9403,6 +9511,10 @@ check ovn-nbctl --wait=hv qos-add lsw0 to-lport 1002 'inport=="lp2" && is_chassi - AT_CHECK([as hv ovs-ofctl dump-meters br-int -O OpenFlow13 | grep meter | wc -l], [0], [4 - ]) - -+check ovn-nbctl qos-del lsw0 -+AT_CHECK([as hv ovs-ofctl dump-meters br-int -O OpenFlow13 | grep meter | wc -l], [0], [0 -+]) -+ - OVN_CLEANUP([hv]) - AT_CLEANUP - ]) -@@ -13988,6 +14100,99 @@ OVN_CLEANUP([hv1],[hv2]) - AT_CLEANUP - ]) - -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([garps disabled when port no longer bound to chassis]) -+ovn_start -+ -+net_add n1 -+for i in 1 2; do -+ sim_add hv$i -+ as hv$i -+ check ovs-vsctl add-br br-phys -+ ovn_attach n1 br-phys 192.168.0.$i -+ check ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys -+done -+ -+check ovn-nbctl ls-add ls0 -+check ovn-nbctl lsp-add ls0 port -+check ovn-nbctl lsp-set-addresses port "00:00:00:00:00:01 10.0.0.1" -+ -+check ovn-nbctl lsp-add ls0 public -+check ovn-nbctl lsp-set-addresses public unknown -+check ovn-nbctl lsp-set-type public localnet -+check ovn-nbctl lsp-set-options public network_name=phys -+ -+for hv in hv1 hv2; do -+ as $hv check ovs-vsctl -- add-port br-int port -- \ -+ set Interface port external-ids:iface-id=port \ -+ options:tx_pcap=$hv/port-tx.pcap \ -+ options:rxq_pcap=$hv/port-rx.pcap -+done -+ -+reset_pcap_file() { -+ local hv=$1 -+ local iface=$2 -+ local pcap_file=$3 -+ as $hv check ovs-vsctl -- set Interface $iface options:tx_pcap=dummy-tx.pcap \ -+ options:rxq_pcap=dummy-rx.pcap -+ check rm -f ${pcap_file}*.pcap -+ as $hv check ovs-vsctl -- set Interface $iface options:tx_pcap=${pcap_file}-tx.pcap \ -+ options:rxq_pcap=${pcap_file}-rx.pcap -+} -+ -+reset_env() { -+ reset_pcap_file hv1 br-phys_n1 hv1/br-phys_n1 -+ reset_pcap_file hv2 br-phys_n1 hv2/br-phys_n1 -+ -+ for port in hv1/n1 hv2/n1; do -+ : > $port.expected -+ done -+} -+ -+for hv in hv1 hv2; do -+ wait_row_count Chassis 1 name=$hv -+done -+hv1_uuid=$(fetch_column Chassis _uuid name=hv1) -+hv2_uuid=$(fetch_column Chassis _uuid name=hv2) -+ -+OVN_POPULATE_ARP -+ -+# Activate port on each hv giving a chance to each chassis to enable garps -+check ovn-nbctl lsp-set-options port requested-chassis=hv1 -+wait_column "$hv1_uuid" Port_Binding chassis logical_port=port -+wait_column "$hv1_uuid" Port_Binding requested_chassis logical_port=port -+wait_for_ports_up -+reset_env -+ -+# give chassis some time to generate garps -+sleep 2 -+ -+expected_garp=ffffffffffff000000000001080600010800060400010000000000010a0000010000000000000a000001 -+ -+# check hv1 sends garps and hv2 doesn't -+echo $expected_garp >> hv1/n1.expected -+OVN_CHECK_PACKETS_CONTAIN([hv1/br-phys_n1-tx.pcap], [hv1/n1.expected]) -+OVN_CHECK_PACKETS([hv2/br-phys_n1-tx.pcap], [hv2/n1.expected]) -+ -+check ovn-nbctl lsp-set-options port requested-chassis=hv2 -+wait_column "$hv2_uuid" Port_Binding chassis logical_port=port -+wait_column "$hv2_uuid" Port_Binding requested_chassis logical_port=port -+wait_for_ports_up -+reset_env -+ -+# give chassis some time to generate garps -+sleep 2 -+ -+# check hv2 sends garps and hv1 doesn't -+echo $expected_garp >> hv2/n1.expected -+OVN_CHECK_PACKETS([hv1/br-phys_n1-tx.pcap], [hv1/n1.expected]) -+OVN_CHECK_PACKETS_CONTAIN([hv2/br-phys_n1-tx.pcap], [hv2/n1.expected]) -+ -+OVN_CLEANUP([hv1],[hv2]) -+ -+AT_CLEANUP -+]) -+ - OVN_FOR_EACH_NORTHD([ - AT_SETUP([IPv6 periodic RA disabled for localnet adjacent switch ports]) - ovn_start -@@ -15243,6 +15448,92 @@ OVN_CLEANUP([hv1]) - AT_CLEANUP - ]) - -+# This test ensures that the incremental flow installation works well when -+# handling update->delete->add/update for the same OVS flow. -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([ACL conjunction append and reprocess]) -+ovn_start -+ -+net_add n1 -+sim_add hv1 -+as hv1 -+check ovs-vsctl add-br br-phys -+ovn_attach n1 br-phys 192.168.0.1 -+ -+# Setup the desired state: -+# - Two ACLs, each matches its own port-group (pg1 & pg2), and matches the same -+# set of IP addresses. -+# - pg1 includes p1, p2, p3 -+# - pg2 includes p4, p5 -+check ovn-nbctl ls-add sw -+check ovn-nbctl lsp-add sw p1 -- lsp-set-addresses p1 "00:00:00:00:00:02 192.168.0.2" -+check ovn-nbctl lsp-add sw p2 -- lsp-set-addresses p2 "00:00:00:00:00:03 192.168.0.3" -+check ovn-nbctl lsp-add sw p3 -- lsp-set-addresses p3 "00:00:00:00:00:04 192.168.0.4" -+check ovn-nbctl lsp-add sw p4 -- lsp-set-addresses p4 "00:00:00:00:00:05 192.168.0.5" -+check ovn-nbctl lsp-add sw p5 -- lsp-set-addresses p5 "00:00:00:00:00:06 192.168.0.6" -+check ovn-nbctl pg-add pg1 p1 p2 p3 -+check ovn-nbctl pg-add pg2 p4 p5 -+check ovs-vsctl add-port br-int p1 -- set Interface p1 external_ids:iface-id=p1 -+check ovs-vsctl add-port br-int p2 -- set Interface p2 external_ids:iface-id=p2 -+check ovs-vsctl add-port br-int p3 -- set Interface p3 external_ids:iface-id=p3 -+check ovs-vsctl add-port br-int p4 -- set Interface p4 external_ids:iface-id=p4 -+check ovs-vsctl add-port br-int p5 -- set Interface p5 external_ids:iface-id=p5 -+check ovn-nbctl acl-add pg1 to-lport 1000 "outport==@pg1 && ip4 && ip4.src == {10.0.0.1, 10.0.0.2}" allow -+check ovn-nbctl acl-add pg2 to-lport 1000 "outport==@pg2 && ip4 && ip4.src == {10.0.0.1, 10.0.0.2}" allow -+check ovn-nbctl --wait=hv sync -+ -+# Now we should have two flows with combined conjunctions. -+OVS_WAIT_UNTIL([test 2 = `as hv1 ovs-ofctl dump-flows br-int | \ -+grep conjunction.*conjunction | wc -l`]) -+ -+ -+# Test the scenario 10 times to give enough chance to hit the -+# "update->delete->add/update" scenario, because we can't decide the order of -+# change handling inside ovn-controller. -+for i in $(seq 10); do -+# Unbind the p3 and p5, the combined conjunctions should be gone. -+ovs-vsctl del-port br-int p3 -+ovs-vsctl del-port br-int p5 -+OVS_WAIT_UNTIL([test 0 = `as hv1 ovs-ofctl dump-flows br-int | \ -+grep conjunction.*conjunction | wc -l`]) -+ -+# Delete and re-add the ACLs, just to bring some randomness in the lflow -+# processing order, so that there is a chance that the order of adding and -+# appending are the same before & after the flow deletion, so that the -+# generated combined conjunctions are the same before & after the flow -+# deletion. (If the order is different, the combined conjunctions order is -+# different and the action comparison would fail, so won't trigger the tracked -+# flow merging. We want to make sure that we test the merging scenario) -+ovn-nbctl acl-del pg1 to-lport 1000 "outport==@pg1 && ip4 && ip4.src == {10.0.0.1, 10.0.0.2}" -+ovn-nbctl acl-del pg2 to-lport 1000 "outport==@pg2 && ip4 && ip4.src == {10.0.0.1, 10.0.0.2}" -+ovn-nbctl acl-add pg1 to-lport 1000 "outport==@pg1 && ip4 && ip4.src == {10.0.0.1, 10.0.0.2}" allow -+ovn-nbctl acl-add pg2 to-lport 1000 "outport==@pg2 && ip4 && ip4.src == {10.0.0.1, 10.0.0.2}" allow -+ovn-nbctl --wait=hv sync -+ -+# Now re-bind p3 and p5 in the same transaction, so that pg1 and pg2 update are -+# handled in the same I-P engine run. The order of pg1 and pg2 can be random. -+# If the order is pg2 -> pg1, then it should trigger the OVS flow -+# "update->delete->add/update" scenario: -+# 1) when pg2 update is handled, the ACL-2 would append conjunctions to -+# the conjunction flows of ACL-1 -+# 2) when pg1 update is handled, it would flood remove flows of both ACL-1 and -+# ACL-2, including the "appended" conjunction flows. And then reprocess -+# ACL-1 and ACL-2 would re-add and re-append the conjunction flows with -+# combined conjunctions. -+ovs-vsctl add-port br-int p3 -- set Interface p3 external_ids:iface-id=p3 -- \ -+ add-port br-int p5 -- set Interface p5 external_ids:iface-id=p5 -+ovn-nbctl --wait=hv sync -+ -+# Now making sure we end up with two combined conjunctions. -+OVS_WAIT_UNTIL([test 2 = `as hv1 ovs-ofctl dump-flows br-int | \ -+grep conjunction.*conjunction | wc -l`]) -+ -+done -+ -+OVN_CLEANUP([hv1]) -+AT_CLEANUP -+]) -+ - OVN_FOR_EACH_NORTHD([ - AT_SETUP([Superseding ACLs with conjunction]) - ovn_start -diff --git a/tests/system-ovn.at b/tests/system-ovn.at -index c4a2c39f6..018dcea2a 100644 ---- a/tests/system-ovn.at -+++ b/tests/system-ovn.at -@@ -6922,10 +6922,10 @@ p = IP(src="192.168.1.2", dst="192.168.1.1") / UDP(dport = 12345) / Raw(b"X"*64) - send (p, iface='sw01', loop = 0, verbose = 0, count = 20) - EOF - --# 1pps + 1 burst size -+# 1pps - OVS_WAIT_UNTIL([ - n_reject=$(grep unreachable reject.pcap | wc -l) -- test "${n_reject}" = "2" -+ test "${n_reject}" = "1" - ]) - kill $(pidof tcpdump) - rm -f reject.pcap -@@ -6938,10 +6938,10 @@ p = IP(src="192.168.1.2", dst="192.168.1.1") / UDP(dport = 12345) / Raw(b"X"*64) - send (p, iface='sw01', loop = 0, verbose = 0, count = 100) - EOF - --# 10pps + 1 burst size -+# 10pps - OVS_WAIT_UNTIL([ - n_reject=$(grep unreachable reject.pcap | wc -l) -- test "${n_reject}" = "20" -+ test "${n_reject}" = "10" - ]) - - kill $(pidof tcpdump) -@@ -6974,10 +6974,10 @@ p = IP(src="192.168.1.2", dst="172.16.1.100") / TCP(dport = 80, flags="S") / Raw - send (p, iface='sw01', loop = 0, verbose = 0, count = 100) - EOF - --# 1pps + 1 burst size -+# 1pps - OVS_WAIT_UNTIL([ - n_arp=$(grep ARP arp.pcap | wc -l) -- test "${n_arp}" = "2" -+ test "${n_arp}" = "1" - ]) - kill $(pidof tcpdump) - -@@ -6994,10 +6994,10 @@ p = IP(src="192.168.1.2", dst="172.16.1.100", ttl=1) / TCP(dport = 8080, flags=" - send (p, iface='sw01', loop = 0, verbose = 0, count = 100) - EOF - --# 1pps + 1 burst size -+# 1pps - OVS_WAIT_UNTIL([ - n_icmp=$(grep ICMP icmp.pcap | wc -l) -- test "${n_icmp}" = "2" -+ test "${n_icmp}" = "1" - ]) - kill $(pidof tcpdump) - -@@ -7010,7 +7010,7 @@ bfd: bfd-meter - - check ovn-nbctl --bfd lr-route-add R1 240.0.0.0/8 172.16.1.50 rp-public - printf "%08x" $(ovn-sbctl get bfd . disc) > /tmp/disc --NS_EXEC([server], [tcpdump -l -n -i s1 udp port 3784 -Q in > bfd.pcap &]) -+NS_EXEC([server], [tcpdump -l -nn -i s1 udp port 3784 and ip[[29]]==0x90 -Q in > bfd.pcap &]) - ip netns exec server scapy -H <<-EOF - import binascii - f = open("/tmp/disc", "r") -@@ -7023,10 +7023,10 @@ f.close() - EOF - rm /tmp/disc - --# 1pps + 1 burst size -+# 1pps - OVS_WAIT_UNTIL([ -- n_tcp_rst=$(grep Final bfd.pcap | wc -l) -- test "${n_tcp_rst}" = "2" -+ n_bfd=$(grep 3784 bfd.pcap | wc -l) -+ test "${n_bfd}" = "1" - ]) - kill $(pidof tcpdump) - -@@ -7992,3 +7992,122 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d - - AT_CLEANUP - ]) -+ -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([East-West traffic with gateway router if DNAT configured]) -+AT_KEYWORDS([ovnnat]) -+ -+CHECK_CONNTRACK() -+CHECK_CONNTRACK_NAT() -+ovn_start -+OVS_TRAFFIC_VSWITCHD_START() -+ADD_BR([br-int]) -+# Set external-ids in br-int needed for ovn-controller -+ovs-vsctl \ -+ -- set Open_vSwitch . external-ids:system-id=hv1 \ -+ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ -+ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ -+ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ -+ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true -+ -+# Start ovn-controller -+start_daemon ovn-controller -+# Logical network: -+# One LR - R1 has two switches: sw0 and sw1 -+# sw0 -- R1 -- sw1 -+# Logical port 'sw01' in switch 'sw0'. -+# Logical port 'sw11' in switch 'sw1'. -+# nc server running in sw01 -+# nc client running on sw11 -+ -+check ovn-nbctl lr-add R1 -+check ovn-nbctl ls-add sw0 -+check ovn-nbctl ls-add sw1 -+ -+check ovn-nbctl lrp-add R1 rp-sw0 00:00:01:01:02:03 192.168.1.1/24 -+check ovn-nbctl lrp-add R1 rp-sw1 00:00:03:01:02:03 192.168.2.1/24 -+check ovn-nbctl set logical_router R1 options:chassis=hv1 -+ -+check ovn-nbctl lsp-add sw0 sw0-rp -- set Logical_Switch_Port sw0-rp \ -+ type=router options:router-port=rp-sw0 \ -+ -- lsp-set-addresses sw0-rp router -+check ovn-nbctl lsp-add sw1 sw1-rp -- set Logical_Switch_Port sw1-rp \ -+ type=router options:router-port=rp-sw1 \ -+ -- lsp-set-addresses sw1-rp router -+ -+ADD_NAMESPACES(sw01) -+ADD_VETH(sw01, sw01, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \ -+ "192.168.1.1") -+check ovn-nbctl lsp-add sw0 sw01 \ -+ -- lsp-set-addresses sw01 "f0:00:00:01:02:03 192.168.1.2" -+ -+ADD_NAMESPACES(sw11) -+ADD_VETH(sw11, sw11, br-int, "192.168.2.2/24", "f0:00:00:02:02:03", \ -+ "192.168.2.1") -+check ovn-nbctl lsp-add sw1 sw11 \ -+ -- lsp-set-addresses sw11 "f0:00:00:02:02:03 192.168.2.2" -+ -+NETNS_DAEMONIZE([sw01], [nc -k -l 8000], [nc-sw01.pid]) -+ -+test_ping() { -+ NS_CHECK_EXEC([$1], [ping -q -c 1 $2 -w 2 | FORMAT_PING], \ -+[0], [dnl -+1 packets transmitted, 1 received, 0% packet loss, time 0ms -+]) -+} -+ -+# Only SNAT -+check ovn-nbctl --wait=hv lr-nat-add R1 snat 172.16.1.21 192.168.2.0/24 -+ -+echo "foo" > foo -+NS_CHECK_EXEC([sw11], [nc 192.168.1.2 8000 < foo]) -+test_ping sw11 192.168.1.2 -+ -+# Ensure nat has been hit -+OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep -v "n_packets=0" | grep 'nat(src=172.16.1.21)']) -+# Ensure conntrack entry is present -+OVS_WAIT_FOR_OUTPUT([ -+ ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.2.2) | \ -+ sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl -+icmp,orig=(src=192.168.2.2,dst=192.168.1.2,id=,type=8,code=0),reply=(src=192.168.1.2,dst=192.168.2.2,id=,type=0,code=0),zone= -+tcp,orig=(src=192.168.2.2,dst=192.168.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=192.168.2.2,sport=,dport=),zone=,protoinfo=(state=) -+]) -+ -+AT_CHECK([ovs-appctl dpctl/flush-conntrack]) -+ -+# SNAT and DNAT. using Logical IP -+ovn-nbctl --wait=hv lr-nat-add R1 dnat_and_snat 172.16.1.2 192.168.1.2 -+NS_CHECK_EXEC([sw11], [nc 192.168.1.2 8000 < foo ]) -+test_ping sw11 192.168.1.2 -+ -+# Ensure conntrack entry is present -+OVS_WAIT_FOR_OUTPUT([ -+ ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.2.2) | \ -+ sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl -+icmp,orig=(src=192.168.2.2,dst=192.168.1.2,id=,type=8,code=0),reply=(src=192.168.1.2,dst=192.168.2.2,id=,type=0,code=0),zone= -+tcp,orig=(src=192.168.2.2,dst=192.168.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=192.168.2.2,sport=,dport=),zone=,protoinfo=(state=) -+]) -+ -+AT_CHECK([ovs-appctl dpctl/flush-conntrack]) -+ -+# SNAT and DNAT. using floating IP -+NS_CHECK_EXEC([sw11], [nc 172.16.1.2 8000 < foo ]) -+test_ping sw11 172.16.1.2 -+ -+# Ensure conntrack entry is present -+OVS_WAIT_FOR_OUTPUT([ -+ ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.2.2) | \ -+ sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl -+icmp,orig=(src=192.168.2.2,dst=172.16.1.2,id=,type=8,code=0),reply=(src=192.168.1.2,dst=192.168.2.2,id=,type=0,code=0),zone= -+tcp,orig=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=192.168.2.2,sport=,dport=),zone=,protoinfo=(state=) -+]) -+ -+AT_CHECK([ovs-appctl dpctl/flush-conntrack]) -+ -+OVS_APP_EXIT_AND_WAIT([ovn-controller]) -+as -+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d -+/connection dropped.*/d"]) -+ -+AT_CLEANUP -+]) -diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c -index 7bcc2c66a..7fcfa50d4 100644 ---- a/utilities/ovn-nbctl.c -+++ b/utilities/ovn-nbctl.c -@@ -2856,7 +2856,7 @@ nbctl_lb_add(struct ctl_context *ctx) - } - - struct sockaddr_storage ss_vip; -- if (!inet_parse_active(lb_vip, 0, &ss_vip, false)) { -+ if (!inet_parse_active(lb_vip, 0, &ss_vip, false, NULL)) { - ctl_error(ctx, "%s: should be an IP address (or an IP address " - "and a port number with : as a separator).", lb_vip); - return; -@@ -2886,7 +2886,7 @@ nbctl_lb_add(struct ctl_context *ctx) - struct sockaddr_storage ss_dst; - - if (lb_vip_port) { -- if (!inet_parse_active(token, -1, &ss_dst, false)) { -+ if (!inet_parse_active(token, -1, &ss_dst, false, NULL)) { - ctl_error(ctx, "%s: should be an IP address and a port " - "number with : as a separator.", token); - goto out; -@@ -3032,7 +3032,7 @@ lb_info_add_smap(const struct nbrec_load_balancer *lb, - const struct smap_node *node = nodes[i]; - - struct sockaddr_storage ss; -- if (!inet_parse_active(node->key, 0, &ss, false)) { -+ if (!inet_parse_active(node->key, 0, &ss, false, NULL)) { - continue; - } - -diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c -index ece5803f2..096d691d5 100644 ---- a/utilities/ovn-trace.c -+++ b/utilities/ovn-trace.c -@@ -214,7 +214,7 @@ static void - parse_lb_option(const char *s) - { - struct sockaddr_storage ss; -- if (!inet_parse_active(s, 0, &ss, false)) { -+ if (!inet_parse_active(s, 0, &ss, false, NULL)) { - ovs_fatal(0, "%s: bad address", s); - } - -@@ -1388,7 +1388,8 @@ ovntrace_node_prune_summary(struct ovs_list *nodes) - sub->type == OVNTRACE_NODE_TABLE) { - /* Replace 'sub' by its children, if any, */ - ovs_list_remove(&sub->node); -- ovs_list_splice(&next->node, sub->subs.next, &sub->subs); -+ ovs_list_splice(next ? &next->node : nodes, sub->subs.next, -+ &sub->subs); - ovntrace_node_destroy(sub); - } - } -@@ -1432,7 +1433,8 @@ ovntrace_node_prune_hard(struct ovs_list *nodes) - sub->type == OVNTRACE_NODE_OUTPUT) { - /* Replace 'sub' by its children, if any, */ - ovs_list_remove(&sub->node); -- ovs_list_splice(&next->node, sub->subs.next, &sub->subs); -+ ovs_list_splice(next ? &next->node : nodes, sub->subs.next, -+ &sub->subs); - ovntrace_node_destroy(sub); - } - } diff --git a/SOURCES/ovn22.06.patch b/SOURCES/ovn22.06.patch new file mode 100644 index 0000000..426711d --- /dev/null +++ b/SOURCES/ovn22.06.patch @@ -0,0 +1,1519 @@ +diff --git a/NEWS b/NEWS +index e335f64c2..32e342a18 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,3 +1,6 @@ ++OVN v22.06.1 - xx xxx xxxx ++-------------------------- ++ + OVN v22.06.0 - 03 Jun 2022 + -------------------------- + - Support IGMP and MLD snooping on transit logical switches that connect +@@ -24,6 +27,8 @@ OVN v22.06.0 - 03 Jun 2022 + - Added support for setting the Next server IP in the DHCP header + using the private DHCP option - 253 in native OVN DHCPv4 responder. + - Support list of chassis for Logical_Switch_Port:options:requested-chassis. ++ - Support Logical_Switch_Port:options:activation-strategy for live migration ++ scenarios. + + OVN v22.03.0 - 11 Mar 2022 + -------------------------- +diff --git a/configure.ac b/configure.ac +index b649441bc..739e0295e 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -13,7 +13,7 @@ + # limitations under the License. + + AC_PREREQ(2.63) +-AC_INIT(ovn, 22.06.0, bugs@openvswitch.org) ++AC_INIT(ovn, 22.06.1, bugs@openvswitch.org) + AC_CONFIG_MACRO_DIR([m4]) + AC_CONFIG_AUX_DIR([build-aux]) + AC_CONFIG_HEADERS([config.h]) +diff --git a/controller/lport.c b/controller/lport.c +index bf55d83f2..add7e91aa 100644 +--- a/controller/lport.c ++++ b/controller/lport.c +@@ -197,3 +197,25 @@ get_peer_lport(const struct sbrec_port_binding *pb, + peer_name); + return (peer && peer->datapath) ? peer : NULL; + } ++ ++bool ++lport_is_activated_by_activation_strategy(const struct sbrec_port_binding *pb, ++ const struct sbrec_chassis *chassis) ++{ ++ const char *activated_chassis = smap_get(&pb->options, ++ "additional-chassis-activated"); ++ if (activated_chassis) { ++ char *save_ptr; ++ char *tokstr = xstrdup(activated_chassis); ++ for (const char *chassis_name = strtok_r(tokstr, ",", &save_ptr); ++ chassis_name != NULL; ++ chassis_name = strtok_r(NULL, ",", &save_ptr)) { ++ if (!strcmp(chassis_name, chassis->name)) { ++ free(tokstr); ++ return true; ++ } ++ } ++ free(tokstr); ++ } ++ return false; ++} +diff --git a/controller/lport.h b/controller/lport.h +index 115881655..644c67255 100644 +--- a/controller/lport.h ++++ b/controller/lport.h +@@ -70,4 +70,7 @@ const struct sbrec_port_binding *lport_get_peer( + const struct sbrec_port_binding *lport_get_l3gw_peer( + const struct sbrec_port_binding *, + struct ovsdb_idl_index *sbrec_port_binding_by_name); ++bool ++lport_is_activated_by_activation_strategy(const struct sbrec_port_binding *pb, ++ const struct sbrec_chassis *chassis); + #endif /* controller/lport.h */ +diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c +index 2793c8687..69615308e 100644 +--- a/controller/ovn-controller.c ++++ b/controller/ovn-controller.c +@@ -1128,6 +1128,53 @@ ovs_interface_shadow_ovs_interface_handler(struct engine_node *node, + return true; + } + ++struct ed_type_activated_ports { ++ struct ovs_list *activated_ports; ++}; ++ ++static void * ++en_activated_ports_init(struct engine_node *node OVS_UNUSED, ++ struct engine_arg *arg OVS_UNUSED) ++{ ++ struct ed_type_activated_ports *data = xzalloc(sizeof *data); ++ data->activated_ports = NULL; ++ return data; ++} ++ ++static void ++en_activated_ports_cleanup(void *data_) ++{ ++ struct ed_type_activated_ports *data = data_; ++ if (!data->activated_ports) { ++ return; ++ } ++ ++ struct activated_port *pp; ++ LIST_FOR_EACH_POP (pp, list, data->activated_ports) { ++ free(pp); ++ } ++ free(data->activated_ports); ++ data->activated_ports = NULL; ++} ++ ++static void ++en_activated_ports_clear_tracked_data(void *data) ++{ ++ en_activated_ports_cleanup(data); ++} ++ ++static void ++en_activated_ports_run(struct engine_node *node, void *data_) ++{ ++ struct ed_type_activated_ports *data = data_; ++ enum engine_node_state state = EN_UNCHANGED; ++ data->activated_ports = get_ports_to_activate_in_engine(); ++ if (data->activated_ports) { ++ state = EN_UPDATED; ++ } ++ engine_set_node_state(node, state); ++} ++ + struct ed_type_runtime_data { + /* Contains "struct local_datapath" nodes. */ + struct hmap local_datapaths; +@@ -3164,6 +3211,49 @@ pflow_output_ct_zones_handler(struct engine_node *node OVS_UNUSED, + return !ct_zones_data->recomputed; + } + ++static bool ++pflow_output_activated_ports_handler(struct engine_node *node, void *data) ++{ ++ struct ed_type_activated_ports *ap = ++ engine_get_input_data("activated_ports", node); ++ if (!ap->activated_ports) { ++ return true; ++ } ++ ++ struct ed_type_pflow_output *pfo = data; ++ struct ed_type_runtime_data *rt_data = ++ engine_get_input_data("runtime_data", node); ++ struct ed_type_non_vif_data *non_vif_data = ++ engine_get_input_data("non_vif_data", node); ++ ++ struct physical_ctx p_ctx; ++ init_physical_ctx(node, rt_data, non_vif_data, &p_ctx); ++ ++ struct activated_port *pp; ++ LIST_FOR_EACH (pp, list, ap->activated_ports) { ++ struct ovsdb_idl_index *sbrec_datapath_binding_by_key = ++ engine_ovsdb_node_get_index( ++ engine_get_input("SB_datapath_binding", node), ++ "key"); ++ struct ovsdb_idl_index *sbrec_port_binding_by_key = ++ engine_ovsdb_node_get_index( ++ engine_get_input("SB_port_binding", node), ++ "key"); ++ const struct sbrec_port_binding *pb = lport_lookup_by_key( ++ sbrec_datapath_binding_by_key, sbrec_port_binding_by_key, ++ pp->dp_key, pp->port_key); ++ if (pb) { ++ if (!physical_handle_flows_for_lport(pb, false, &p_ctx, ++ &pfo->flow_table)) { ++ return false; ++ } ++ tag_port_as_activated_in_engine(pp); ++ } ++ } ++ engine_set_node_state(node, EN_UPDATED); ++ return true; ++} ++ + static void * + en_flow_output_init(struct engine_node *node OVS_UNUSED, + struct engine_arg *arg OVS_UNUSED) +@@ -3445,6 +3535,7 @@ main(int argc, char *argv[]) + ENGINE_NODE(non_vif_data, "non_vif_data"); + ENGINE_NODE(mff_ovn_geneve, "mff_ovn_geneve"); + ENGINE_NODE(ofctrl_is_connected, "ofctrl_is_connected"); ++ ENGINE_NODE_WITH_CLEAR_TRACK_DATA(activated_ports, "activated_ports"); + ENGINE_NODE(pflow_output, "physical_flow_output"); + ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lflow_output, "logical_flow_output"); + ENGINE_NODE(flow_output, "flow_output"); +@@ -3492,6 +3583,14 @@ main(int argc, char *argv[]) + engine_add_input(&en_pflow_output, &en_sb_multicast_group, + pflow_output_sb_multicast_group_handler); + ++ /* pflow_output needs to access the SB datapath binding and hence a noop ++ * handler. ++ */ ++ engine_add_input(&en_pflow_output, &en_sb_datapath_binding, ++ engine_noop_handler); ++ engine_add_input(&en_pflow_output, &en_activated_ports, ++ pflow_output_activated_ports_handler); ++ + engine_add_input(&en_pflow_output, &en_runtime_data, + pflow_output_runtime_data_handler); + engine_add_input(&en_pflow_output, &en_sb_encap, NULL); +diff --git a/controller/physical.c b/controller/physical.c +index 24de86f24..fc8280a99 100644 +--- a/controller/physical.c ++++ b/controller/physical.c +@@ -40,7 +40,9 @@ + #include "lib/mcast-group-index.h" + #include "lib/ovn-sb-idl.h" + #include "lib/ovn-util.h" ++#include "ovn/actions.h" + #include "physical.h" ++#include "pinctrl.h" + #include "openvswitch/shash.h" + #include "simap.h" + #include "smap.h" +@@ -984,6 +986,94 @@ enum access_type { + PORT_HA_REMOTE, + }; + ++static void ++setup_rarp_activation_strategy(const struct sbrec_port_binding *binding, ++ ofp_port_t ofport, struct zone_ids *zone_ids, ++ struct ovn_desired_flow_table *flow_table, ++ struct ofpbuf *ofpacts_p) ++{ ++ struct match match = MATCH_CATCHALL_INITIALIZER; ++ ++ /* Unblock the port on ingress RARP. */ ++ match_set_dl_type(&match, htons(ETH_TYPE_RARP)); ++ match_set_in_port(&match, ofport); ++ ofpbuf_clear(ofpacts_p); ++ ++ load_logical_ingress_metadata(binding, zone_ids, ofpacts_p); ++ ++ size_t ofs = ofpacts_p->size; ++ struct ofpact_controller *oc = ofpact_put_CONTROLLER(ofpacts_p); ++ oc->max_len = UINT16_MAX; ++ oc->reason = OFPR_ACTION; ++ ++ struct action_header ah = { ++ .opcode = htonl(ACTION_OPCODE_ACTIVATION_STRATEGY_RARP) ++ }; ++ ofpbuf_put(ofpacts_p, &ah, sizeof ah); ++ ++ ofpacts_p->header = oc; ++ oc->userdata_len = ofpacts_p->size - (ofs + sizeof *oc); ++ ofpact_finish_CONTROLLER(ofpacts_p, &oc); ++ put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, ofpacts_p); ++ ++ ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG, 1010, ++ binding->header_.uuid.parts[0], ++ &match, ofpacts_p, &binding->header_.uuid); ++ ofpbuf_clear(ofpacts_p); ++ ++ /* Block all non-RARP traffic for the port, both directions. */ ++ match_init_catchall(&match); ++ match_set_in_port(&match, ofport); ++ ++ ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG, 1000, ++ binding->header_.uuid.parts[0], ++ &match, ofpacts_p, &binding->header_.uuid); ++ ++ match_init_catchall(&match); ++ uint32_t dp_key = binding->datapath->tunnel_key; ++ uint32_t port_key = binding->tunnel_key; ++ match_set_metadata(&match, htonll(dp_key)); ++ match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key); ++ ++ ofctrl_add_flow(flow_table, OFTABLE_LOG_TO_PHY, 1000, ++ binding->header_.uuid.parts[0], ++ &match, ofpacts_p, &binding->header_.uuid); ++} ++ ++static void ++setup_activation_strategy(const struct sbrec_port_binding *binding, ++ const struct sbrec_chassis *chassis, ++ uint32_t dp_key, uint32_t port_key, ++ ofp_port_t ofport, struct zone_ids *zone_ids, ++ struct ovn_desired_flow_table *flow_table, ++ struct ofpbuf *ofpacts_p) ++{ ++ for (size_t i = 0; i < binding->n_additional_chassis; i++) { ++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); ++ if (binding->additional_chassis[i] == chassis) { ++ const char *strategy = smap_get(&binding->options, ++ "activation-strategy"); ++ if (strategy ++ && !lport_is_activated_by_activation_strategy(binding, ++ chassis) ++ && !pinctrl_is_port_activated(dp_key, port_key)) { ++ if (!strcmp(strategy, "rarp")) { ++ setup_rarp_activation_strategy(binding, ofport, ++ zone_ids, flow_table, ++ ofpacts_p); ++ } else { ++ VLOG_WARN_RL(&rl, ++ "Unknown activation strategy defined for " ++ "port %s: %s", ++ binding->logical_port, strategy); ++ return; ++ } ++ } ++ return; ++ } ++ } ++} ++ + static void + consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, + enum mf_field_id mff_ovn_geneve, +@@ -1239,6 +1329,10 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, + } + } + ++ setup_activation_strategy(binding, chassis, dp_key, port_key, ++ ofport, &zone_ids, flow_table, ++ ofpacts_p); ++ + /* Remember the size with just strip vlan added so far, + * as we're going to remove this with ofpbuf_pull() later. */ + uint32_t ofpacts_orig_size = ofpacts_p->size; +diff --git a/controller/pinctrl.c b/controller/pinctrl.c +index 428863293..f954362b7 100644 +--- a/controller/pinctrl.c ++++ b/controller/pinctrl.c +@@ -29,10 +29,12 @@ + #include "lport.h" + #include "mac-learn.h" + #include "nx-match.h" ++#include "ofctrl.h" + #include "latch.h" + #include "lib/packets.h" + #include "lib/sset.h" + #include "openvswitch/ofp-actions.h" ++#include "openvswitch/ofp-flow.h" + #include "openvswitch/ofp-msgs.h" + #include "openvswitch/ofp-packet.h" + #include "openvswitch/ofp-print.h" +@@ -152,8 +154,8 @@ VLOG_DEFINE_THIS_MODULE(pinctrl); + * and pinctrl_run(). + * 'pinctrl_handler_seq' is used by pinctrl_run() to + * wake up pinctrl_handler thread from poll_block() if any changes happened +- * in 'send_garp_rarp_data', 'ipv6_ras' and 'buffered_mac_bindings' +- * structures. ++ * in 'send_garp_rarp_data', 'ipv6_ras', 'ports_to_activate_in_db' and ++ * 'buffered_mac_bindings' structures. + * + * 'pinctrl_main_seq' is used by pinctrl_handler() thread to wake up + * the main thread from poll_block() when mac bindings/igmp groups need to +@@ -198,6 +200,17 @@ static void wait_put_mac_bindings(struct ovsdb_idl_txn *ovnsb_idl_txn); + static void send_mac_binding_buffered_pkts(struct rconn *swconn) + OVS_REQUIRES(pinctrl_mutex); + ++static void pinctrl_rarp_activation_strategy_handler(const struct match *md); ++ ++static void init_activated_ports(void); ++static void destroy_activated_ports(void); ++static void wait_activated_ports(void); ++static void run_activated_ports( ++ struct ovsdb_idl_txn *ovnsb_idl_txn, ++ struct ovsdb_idl_index *sbrec_datapath_binding_by_key, ++ struct ovsdb_idl_index *sbrec_port_binding_by_name, ++ const struct sbrec_chassis *chassis); ++ + static void init_send_garps_rarps(void); + static void destroy_send_garps_rarps(void); + static void send_garp_rarp_wait(long long int send_garp_rarp_time); +@@ -522,6 +535,7 @@ pinctrl_init(void) + init_ipv6_ras(); + init_ipv6_prefixd(); + init_buffered_packets_map(); ++ init_activated_ports(); + init_event_table(); + ip_mcast_snoop_init(); + init_put_vport_bindings(); +@@ -3269,6 +3283,12 @@ process_packet_in(struct rconn *swconn, const struct ofp_header *msg) + ovs_mutex_unlock(&pinctrl_mutex); + break; + ++ case ACTION_OPCODE_ACTIVATION_STRATEGY_RARP: ++ ovs_mutex_lock(&pinctrl_mutex); ++ pinctrl_rarp_activation_strategy_handler(&pin.flow_metadata); ++ ovs_mutex_unlock(&pinctrl_mutex); ++ break; ++ + default: + VLOG_WARN_RL(&rl, "unrecognized packet-in opcode %"PRIu32, + ntohl(ah->opcode)); +@@ -3533,6 +3553,8 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, + bfd_monitor_run(ovnsb_idl_txn, bfd_table, sbrec_port_binding_by_name, + chassis, active_tunnels); + run_put_fdbs(ovnsb_idl_txn, sbrec_fdb_by_dp_key_mac); ++ run_activated_ports(ovnsb_idl_txn, sbrec_datapath_binding_by_key, ++ sbrec_port_binding_by_key, chassis); + ovs_mutex_unlock(&pinctrl_mutex); + } + +@@ -4030,12 +4052,15 @@ prepare_ipv6_ras(const struct shash *local_active_ports_ras, + void + pinctrl_wait(struct ovsdb_idl_txn *ovnsb_idl_txn) + { ++ ovs_mutex_lock(&pinctrl_mutex); + wait_put_mac_bindings(ovnsb_idl_txn); + wait_controller_event(ovnsb_idl_txn); + wait_put_vport_bindings(ovnsb_idl_txn); + int64_t new_seq = seq_read(pinctrl_main_seq); + seq_wait(pinctrl_main_seq, new_seq); + wait_put_fdbs(ovnsb_idl_txn); ++ wait_activated_ports(); ++ ovs_mutex_unlock(&pinctrl_mutex); + } + + /* Called by ovn-controller. */ +@@ -4050,6 +4075,7 @@ pinctrl_destroy(void) + destroy_ipv6_ras(); + destroy_ipv6_prefixd(); + destroy_buffered_packets_map(); ++ destroy_activated_ports(); + event_table_destroy(); + destroy_put_mac_bindings(); + destroy_put_vport_bindings(); +@@ -7727,6 +7753,152 @@ pinctrl_handle_svc_check(struct rconn *swconn, const struct flow *ip_flow, + } + } + ++static struct ovs_list ports_to_activate_in_db = OVS_LIST_INITIALIZER( ++ &ports_to_activate_in_db); ++static struct ovs_list ports_to_activate_in_engine = OVS_LIST_INITIALIZER( ++ &ports_to_activate_in_engine); ++ ++struct ovs_list * ++get_ports_to_activate_in_engine(void) ++{ ++ ovs_mutex_lock(&pinctrl_mutex); ++ if (ovs_list_is_empty(&ports_to_activate_in_engine)) { ++ ovs_mutex_unlock(&pinctrl_mutex); ++ return NULL; ++ } ++ ++ struct ovs_list *ap = xmalloc(sizeof *ap); ++ ovs_list_init(ap); ++ struct activated_port *pp; ++ LIST_FOR_EACH (pp, list, &ports_to_activate_in_engine) { ++ struct activated_port *new = xmalloc(sizeof *new); ++ new->dp_key = pp->dp_key; ++ new->port_key = pp->port_key; ++ ovs_list_push_front(ap, &new->list); ++ } ++ ovs_mutex_unlock(&pinctrl_mutex); ++ return ap; ++} ++ ++static void ++init_activated_ports(void) ++ OVS_REQUIRES(pinctrl_mutex) ++{ ++ ovs_list_init(&ports_to_activate_in_db); ++ ovs_list_init(&ports_to_activate_in_engine); ++} ++ ++static void ++destroy_activated_ports(void) ++ OVS_REQUIRES(pinctrl_mutex) ++{ ++ struct activated_port *pp; ++ LIST_FOR_EACH_POP (pp, list, &ports_to_activate_in_db) { ++ free(pp); ++ } ++ LIST_FOR_EACH_POP (pp, list, &ports_to_activate_in_engine) { ++ free(pp); ++ } ++} ++ ++static void ++wait_activated_ports(void) ++ OVS_REQUIRES(pinctrl_mutex) ++{ ++ if (!ovs_list_is_empty(&ports_to_activate_in_engine)) { ++ poll_immediate_wake(); ++ } ++} ++ ++bool pinctrl_is_port_activated(int64_t dp_key, int64_t port_key) ++{ ++ const struct activated_port *pp; ++ ovs_mutex_lock(&pinctrl_mutex); ++ LIST_FOR_EACH (pp, list, &ports_to_activate_in_db) { ++ if (pp->dp_key == dp_key && pp->port_key == port_key) { ++ ovs_mutex_unlock(&pinctrl_mutex); ++ return true; ++ } ++ } ++ LIST_FOR_EACH (pp, list, &ports_to_activate_in_engine) { ++ if (pp->dp_key == dp_key && pp->port_key == port_key) { ++ ovs_mutex_unlock(&pinctrl_mutex); ++ return true; ++ } ++ } ++ ovs_mutex_unlock(&pinctrl_mutex); ++ return false; ++} ++ ++static void ++run_activated_ports(struct ovsdb_idl_txn *ovnsb_idl_txn, ++ struct ovsdb_idl_index *sbrec_datapath_binding_by_key, ++ struct ovsdb_idl_index *sbrec_port_binding_by_key, ++ const struct sbrec_chassis *chassis) ++ OVS_REQUIRES(pinctrl_mutex) ++{ ++ if (!ovnsb_idl_txn) { ++ return; ++ } ++ ++ struct activated_port *pp; ++ LIST_FOR_EACH_SAFE (pp, list, &ports_to_activate_in_db) { ++ const struct sbrec_port_binding *pb = lport_lookup_by_key( ++ sbrec_datapath_binding_by_key, sbrec_port_binding_by_key, ++ pp->dp_key, pp->port_key); ++ if (!pb || lport_is_activated_by_activation_strategy(pb, chassis)) { ++ ovs_list_remove(&pp->list); ++ free(pp); ++ continue; ++ } ++ const char *activated_chassis = smap_get( ++ &pb->options, "additional-chassis-activated"); ++ char *activated_str; ++ if (activated_chassis) { ++ activated_str = xasprintf( ++ "%s,%s", activated_chassis, chassis->name); ++ sbrec_port_binding_update_options_setkey( ++ pb, "additional-chassis-activated", activated_str); ++ free(activated_str); ++ } else { ++ sbrec_port_binding_update_options_setkey( ++ pb, "additional-chassis-activated", chassis->name); ++ } ++ } ++} ++ ++void ++tag_port_as_activated_in_engine(struct activated_port *ap) { ++ ovs_mutex_lock(&pinctrl_mutex); ++ struct activated_port *pp; ++ LIST_FOR_EACH_SAFE (pp, list, &ports_to_activate_in_engine) { ++ if (pp->dp_key == ap->dp_key && pp->port_key == ap->port_key) { ++ ovs_list_remove(&pp->list); ++ free(pp); ++ } ++ } ++ ovs_mutex_unlock(&pinctrl_mutex); ++} ++ ++static void ++pinctrl_rarp_activation_strategy_handler(const struct match *md) ++ OVS_REQUIRES(pinctrl_mutex) ++{ ++ /* Tag the port as activated in-memory. */ ++ struct activated_port *pp = xmalloc(sizeof *pp); ++ pp->port_key = md->flow.regs[MFF_LOG_INPORT - MFF_REG0]; ++ pp->dp_key = ntohll(md->flow.metadata); ++ ovs_list_push_front(&ports_to_activate_in_db, &pp->list); ++ ++ pp = xmalloc(sizeof *pp); ++ pp->port_key = md->flow.regs[MFF_LOG_INPORT - MFF_REG0]; ++ pp->dp_key = ntohll(md->flow.metadata); ++ ovs_list_push_front(&ports_to_activate_in_engine, &pp->list); ++ ++ /* Notify main thread on pending additional-chassis-activated updates. */ ++ notify_pinctrl_main(); ++} ++ + static struct hmap put_fdbs; + + /* MAC learning (fdb) related functions. Runs within the main +diff --git a/controller/pinctrl.h b/controller/pinctrl.h +index 88f18e983..d4f52e94d 100644 +--- a/controller/pinctrl.h ++++ b/controller/pinctrl.h +@@ -20,6 +20,7 @@ + #include + + #include "lib/sset.h" ++#include "openvswitch/list.h" + #include "openvswitch/meta-flow.h" + + struct hmap; +@@ -33,6 +34,7 @@ struct sbrec_dns_table; + struct sbrec_controller_event_table; + struct sbrec_service_monitor_table; + struct sbrec_bfd_table; ++struct sbrec_port_binding; + + void pinctrl_init(void); + void pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, +@@ -56,4 +58,14 @@ void pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, + void pinctrl_wait(struct ovsdb_idl_txn *ovnsb_idl_txn); + void pinctrl_destroy(void); + void pinctrl_set_br_int_name(char *br_int_name); ++ ++struct activated_port { ++ uint32_t dp_key; ++ uint32_t port_key; ++ struct ovs_list list; ++}; ++ ++void tag_port_as_activated_in_engine(struct activated_port *ap); ++struct ovs_list *get_ports_to_activate_in_engine(void); ++bool pinctrl_is_port_activated(int64_t dp_key, int64_t port_key); + #endif /* controller/pinctrl.h */ +diff --git a/debian/changelog b/debian/changelog +index caef68452..1c2de53bd 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,9 @@ ++OVN (22.06.1-1) unstable; urgency=low ++ [ OVN team ] ++ * New upstream version ++ ++ -- OVN team Fri, 03 Jun 2022 11:54:08 -0400 ++ + ovn (22.06.0-1) unstable; urgency=low + + * New upstream version +diff --git a/include/ovn/actions.h b/include/ovn/actions.h +index 1ae496960..33c319f1c 100644 +--- a/include/ovn/actions.h ++++ b/include/ovn/actions.h +@@ -683,6 +683,9 @@ enum action_opcode { + /* put_fdb(inport, eth.src). + */ + ACTION_OPCODE_PUT_FDB, ++ ++ /* activation_strategy_rarp() */ ++ ACTION_OPCODE_ACTIVATION_STRATEGY_RARP, + }; + + /* Header. */ +diff --git a/northd/northd.c b/northd/northd.c +index f120c2366..dd62c4098 100644 +--- a/northd/northd.c ++++ b/northd/northd.c +@@ -3470,6 +3470,16 @@ ovn_port_update_sbrec(struct northd_input *input_data, + smap_add(&options, "vlan-passthru", "true"); + } + ++ /* Retain activated chassis flags. */ ++ if (op->sb->requested_additional_chassis) { ++ const char *activated_str = smap_get( ++ &op->sb->options, "additional-chassis-activated"); ++ if (activated_str) { ++ smap_add(&options, "additional-chassis-activated", ++ activated_str); ++ } ++ } ++ + sbrec_port_binding_set_options(op->sb, &options); + smap_destroy(&options); + if (ovn_is_known_nb_lsp_type(op->nbsp->type)) { +@@ -10976,6 +10986,9 @@ build_neigh_learning_flows_for_lrouter( + copp_meter_get(COPP_ARP, od->nbr->copp, + meter_groups)); + ++ ovn_lflow_add(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 95, ++ "nd_ns && (ip6.src == 0 || nd.sll == 0)", "next;"); ++ + ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 95, + "nd_na && nd.tll == 0", + "put_nd(inport, nd.target, eth.src); next;", +@@ -12021,6 +12034,7 @@ build_gateway_redirect_flows_for_lrouter( + } + for (size_t i = 0; i < od->n_l3dgw_ports; i++) { + const struct ovsdb_idl_row *stage_hint = NULL; ++ bool add_def_flow = true; + + if (od->l3dgw_ports[i]->nbrp) { + stage_hint = &od->l3dgw_ports[i]->nbrp->header_; +@@ -12039,22 +12053,42 @@ build_gateway_redirect_flows_for_lrouter( + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, 50, + ds_cstr(match), ds_cstr(actions), + stage_hint); +- } ++ for (int j = 0; j < od->n_nat_entries; j++) { ++ const struct ovn_nat *nat = &od->nat_entries[j]; + +- for (int i = 0; i < od->n_nat_entries; i++) { +- const struct ovn_nat *nat = &od->nat_entries[i]; ++ if (!lrouter_nat_is_stateless(nat->nb) || ++ strcmp(nat->nb->type, "dnat_and_snat") || ++ (!nat->nb->allowed_ext_ips && !nat->nb->exempted_ext_ips)) { ++ continue; ++ } + +- if (!lrouter_nat_is_stateless(nat->nb) || +- strcmp(nat->nb->type, "dnat_and_snat")) { +- continue; +- } ++ struct ds match_ext = DS_EMPTY_INITIALIZER; ++ struct nbrec_address_set *as = nat->nb->allowed_ext_ips ++ ? nat->nb->allowed_ext_ips : nat->nb->exempted_ext_ips; ++ ds_put_format(&match_ext, "%s && ip%s.src == $%s", ++ ds_cstr(match), nat_entry_is_v6(nat) ? "6" : "4", ++ as->name); + +- ds_clear(match); +- ds_put_format(match, "ip && ip%s.dst == %s", +- nat_entry_is_v6(nat) ? "6" : "4", +- nat->nb->external_ip); +- ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 100, +- ds_cstr(match), "drop;"); ++ if (nat->nb->allowed_ext_ips) { ++ ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, ++ 75, ds_cstr(&match_ext), ++ ds_cstr(actions), stage_hint); ++ if (add_def_flow) { ++ ds_clear(&match_ext); ++ ds_put_format(&match_ext, "ip && ip%s.dst == %s", ++ nat_entry_is_v6(nat) ? "6" : "4", ++ nat->nb->external_ip); ++ ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 70, ++ ds_cstr(&match_ext), "drop;"); ++ add_def_flow = false; ++ } ++ } else if (nat->nb->exempted_ext_ips) { ++ ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, ++ 75, ds_cstr(&match_ext), "drop;", ++ stage_hint); ++ } ++ ds_destroy(&match_ext); ++ } + } + + /* Packets are allowed by default. */ +diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml +index 1f7022490..32858c0b4 100644 +--- a/northd/ovn-northd.8.xml ++++ b/northd/ovn-northd.8.xml +@@ -2323,6 +2323,12 @@ next; + to learn the neighbor. +
  • + ++
  • ++ A priority-95 flow with the match nd_ns && ++ (ip6.src == 0 || nd.sll == 0) and applies the action ++ next; ++
  • ++ +
  • + A priority-90 flow with the match arp and + applies the action +@@ -3018,8 +3024,7 @@ icmp6 { + ip && ip6.dst == B + with an action ct_snat; . If the NAT rule is of type + dnat_and_snat and has stateless=true in the +- options, then the action would be ip4/6.dst= +- (B). ++ options, then the action would be next;. +

    + +

    +@@ -3059,7 +3064,7 @@ icmp6 { + action ct_snat_in_czone; to unSNAT in the common + zone. If the NAT rule is of type dnat_and_snat and has + stateless=true in the options, then the action +- would be ip4/6.dst=(B). ++ would be next;. +

    + +

    +@@ -4217,6 +4222,26 @@ icmp6 { + external ip and D is NAT external mac. +

  • + ++
  • ++ For each dnat_and_snat NAT rule with ++ stateless=true and allowed_ext_ips ++ configured, a priority-75 flow is programmed with match ++ ip4.dst == B and action ++ outport = CR; next; where B ++ is the NAT rule external IP and CR is the ++ chassisredirect port representing the instance ++ of the logical router distributed gateway port on the ++ gateway chassis. Moreover a priority-70 flow is programmed ++ with same match and action drop;. ++ For each dnat_and_snat NAT rule with ++ stateless=true and exempted_ext_ips ++ configured, a priority-75 flow is programmed with match ++ ip4.dst == B and action ++ drop; where B is the NAT rule ++ external IP. ++ A similar flow is added for IPv6 traffic. ++
  • ++ +
  • + For each NAT rule in the OVN Northbound database that can + be handled in a distributed manner, a priority-80 logical flow +@@ -4415,8 +4440,7 @@ nd_ns { + is the logical router gateway port, with an action + ct_dnat_in_czone;. If the NAT rule is of type + dnat_and_snat and has stateless=true in the +- options, then the action would be ip4/6.src= +- (B). ++ options, then the action would be next;. +

    + +

    +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index e4e980720..ab28756af 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -107,7 +107,10 @@ static const char *rbac_port_binding_auth[] = + static const char *rbac_port_binding_update[] = + {"chassis", "additional_chassis", + "encap", "additional_encap", +- "up", "virtual_parent"}; ++ "up", "virtual_parent", ++ /* NOTE: we only need to update the additional-chassis-activated key, ++ * but RBAC_Role doesn't support mutate operation for subkeys. */ ++ "options"}; + + static const char *rbac_mac_binding_auth[] = + {""}; +diff --git a/ovn-nb.xml b/ovn-nb.xml +index c197f431f..e700b2e88 100644 +--- a/ovn-nb.xml ++++ b/ovn-nb.xml +@@ -1045,6 +1045,17 @@ +

    + + ++ ++ If used with multiple chassis set in ++ , specifies an activation strategy ++ for all additional chassis. By default, no activation strategy is ++ used, meaning additional port locations are immediately available for ++ use. When set to "rarp", the port is blocked for ingress and egress ++ communication until a RARP packet is sent from a new location. The ++ "rarp" strategy is useful in live migration scenarios for virtual ++ machines. ++ ++ + + If set, this port will be bound by ovn-controller + only if this same key and value is configured in the +diff --git a/ovn-sb.xml b/ovn-sb.xml +index 9f47a037e..49e851e2a 100644 +--- a/ovn-sb.xml ++++ b/ovn-sb.xml +@@ -3374,6 +3374,21 @@ tcp.flags = RST; +

    +
    + ++ ++ If used with multiple chassis set in , ++ specifies an activation strategy for all additional chassis. By ++ default, no activation strategy is used, meaning additional port ++ locations are immediately available for use. When set to "rarp", the ++ port is blocked for ingress and egress communication until a RARP ++ packet is sent from a new location. The "rarp" strategy is useful ++ in live migration scenarios for virtual machines. ++ ++ ++ ++ When is set, this option indicates ++ that the port was activated using the strategy specified. ++ ++ + + If set, this port will be bound by ovn-controller + only if this same key and value is configured in the +diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at +index a071b3689..76e5a5c2b 100644 +--- a/tests/ovn-northd.at ++++ b/tests/ovn-northd.at +@@ -6734,6 +6734,7 @@ AT_CHECK([cat lrflows | grep -e lr_in_lookup_neighbor -e lr_in_learn_neighbor | + table=2 (lr_in_learn_neighbor), priority=90 , match=(nd_na), action=(put_nd(inport, nd.target, nd.tll); next;) + table=2 (lr_in_learn_neighbor), priority=90 , match=(nd_ns), action=(put_nd(inport, ip6.src, nd.sll); next;) + table=2 (lr_in_learn_neighbor), priority=95 , match=(nd_na && nd.tll == 0), action=(put_nd(inport, nd.target, eth.src); next;) ++ table=2 (lr_in_learn_neighbor), priority=95 , match=(nd_ns && (ip6.src == 0 || nd.sll == 0)), action=(next;) + ]) + + AT_CLEANUP +diff --git a/tests/ovn.at b/tests/ovn.at +index 3c079e0fb..1aa562de5 100644 +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -7432,7 +7432,7 @@ ovs-vsctl -- add-port br-int vif2 -- \ + # Allow some time for ovn-northd and ovn-controller to catch up. + wait_for_ports_up + check ovn-nbctl --wait=hv sync +-ovn-nbctl dump-flows > sbflows ++ovn-sbctl dump-flows > sbflows + AT_CAPTURE_FILE([sbflows]) + + for i in 1 2; do +@@ -8037,7 +8037,7 @@ wait_for_ports_up + check ovn-nbctl --wait=hv sync + sleep 1 + +-ovn-nbctl dump-flows > sbflows ++ovn-sbctl dump-flows > sbflows + AT_CAPTURE_FILE([sbflows]) + + for i in 1 2; do +@@ -14015,6 +14015,7 @@ AT_CLEANUP + + OVN_FOR_EACH_NORTHD([ + AT_SETUP([options:multiple requested-chassis for logical port]) ++AT_KEYWORDS([multi-chassis]) + ovn_start + + net_add n1 +@@ -14104,6 +14105,7 @@ AT_CLEANUP + + OVN_FOR_EACH_NORTHD([ + AT_SETUP([options:multiple requested-chassis for logical port: change chassis role]) ++AT_KEYWORDS([multi-chassis]) + ovn_start + + net_add n1 +@@ -14153,6 +14155,7 @@ AT_CLEANUP + + OVN_FOR_EACH_NORTHD([ + AT_SETUP([options:multiple requested-chassis for logical port: unclaimed behavior]) ++AT_KEYWORDS([multi-chassis]) + ovn_start + + net_add n1 +@@ -14233,6 +14236,7 @@ AT_CLEANUP + + OVN_FOR_EACH_NORTHD([ + AT_SETUP([basic connectivity with multiple requested-chassis]) ++AT_KEYWORDS([multi-chassis]) + ovn_start + + net_add n1 +@@ -14567,6 +14571,7 @@ AT_CLEANUP + + OVN_FOR_EACH_NORTHD([ + AT_SETUP([localnet connectivity with multiple requested-chassis]) ++AT_KEYWORDS([multi-chassis]) + ovn_start + + net_add n1 +@@ -14924,6 +14929,391 @@ OVN_CLEANUP([hv1],[hv2],[hv3]) + AT_CLEANUP + ]) + ++OVN_FOR_EACH_NORTHD([ ++AT_SETUP([options:activation-strategy for logical port]) ++AT_KEYWORDS([multi-chassis]) ++ovn_start ++ ++net_add n1 ++ ++sim_add hv1 ++as hv1 ++check ovs-vsctl add-br br-phys ++ovn_attach n1 br-phys 192.168.0.11 ++ ++sim_add hv2 ++as hv2 ++check ovs-vsctl add-br br-phys ++ovn_attach n1 br-phys 192.168.0.12 ++ ++sim_add hv3 ++as hv3 ++check ovs-vsctl add-br br-phys ++ovn_attach n1 br-phys 192.168.0.13 ++ ++# Disable local ARP responder to pass ARP requests through tunnels ++check ovn-nbctl ls-add ls0 -- add Logical_Switch ls0 other_config vlan-passthru=true ++ ++check ovn-nbctl lsp-add ls0 migrator ++check ovn-nbctl lsp-set-options migrator requested-chassis=hv1,hv2 \ ++ activation-strategy=rarp ++ ++check ovn-nbctl lsp-add ls0 first ++check ovn-nbctl lsp-set-options first requested-chassis=hv1 ++check ovn-nbctl lsp-add ls0 second ++check ovn-nbctl lsp-set-options second requested-chassis=hv2 ++check ovn-nbctl lsp-add ls0 outside ++check ovn-nbctl lsp-set-options outside requested-chassis=hv3 ++ ++check ovn-nbctl lsp-set-addresses migrator "00:00:00:00:00:10 10.0.0.10" ++check ovn-nbctl lsp-set-addresses first "00:00:00:00:00:01 10.0.0.1" ++check ovn-nbctl lsp-set-addresses second "00:00:00:00:00:02 10.0.0.2" ++check ovn-nbctl lsp-set-addresses outside "00:00:00:00:00:03 10.0.0.3" ++ ++for hv in hv1 hv2; do ++ as $hv check ovs-vsctl -- add-port br-int migrator -- \ ++ set Interface migrator external-ids:iface-id=migrator \ ++ options:tx_pcap=$hv/migrator-tx.pcap \ ++ options:rxq_pcap=$hv/migrator-rx.pcap ++done ++ ++as hv1 check ovs-vsctl -- add-port br-int first -- \ ++ set Interface first external-ids:iface-id=first ++as hv2 check ovs-vsctl -- add-port br-int second -- \ ++ set Interface second external-ids:iface-id=second ++as hv3 check ovs-vsctl -- add-port br-int outside -- \ ++ set Interface outside external-ids:iface-id=outside ++ ++for hv in hv1 hv2 hv3; do ++ wait_row_count Chassis 1 name=$hv ++done ++hv1_uuid=$(fetch_column Chassis _uuid name=hv1) ++hv2_uuid=$(fetch_column Chassis _uuid name=hv2) ++hv3_uuid=$(fetch_column Chassis _uuid name=hv3) ++ ++wait_column "$hv1_uuid" Port_Binding chassis logical_port=migrator ++wait_column "$hv1_uuid" Port_Binding requested_chassis logical_port=migrator ++wait_column "$hv2_uuid" Port_Binding additional_chassis logical_port=migrator ++wait_column "$hv2_uuid" Port_Binding requested_additional_chassis logical_port=migrator ++ ++wait_column "$hv1_uuid" Port_Binding chassis logical_port=first ++wait_column "$hv2_uuid" Port_Binding chassis logical_port=second ++wait_column "$hv3_uuid" Port_Binding chassis logical_port=outside ++ ++OVN_POPULATE_ARP ++ ++send_arp() { ++ local hv=$1 inport=$2 eth_src=$3 eth_dst=$4 spa=$5 tpa=$6 ++ local request=${eth_dst}${eth_src}08060001080006040001${eth_src}${spa}${eth_dst}${tpa} ++ as ${hv} ovs-appctl netdev-dummy/receive $inport $request ++ echo "${request}" ++} ++ ++send_rarp() { ++ local hv=$1 inport=$2 eth_src=$3 eth_dst=$4 spa=$5 tpa=$6 ++ local request=${eth_dst}${eth_src}80350001080006040001${eth_src}${spa}${eth_dst}${tpa} ++ as ${hv} ovs-appctl netdev-dummy/receive $inport $request ++ echo "${request}" ++} ++ ++reset_pcap_file() { ++ local hv=$1 ++ local iface=$2 ++ local pcap_file=$3 ++ as $hv check ovs-vsctl -- set Interface $iface options:tx_pcap=dummy-tx.pcap \ ++ options:rxq_pcap=dummy-rx.pcap ++ check rm -f ${pcap_file}*.pcap ++ as $hv check ovs-vsctl -- set Interface $iface options:tx_pcap=${pcap_file}-tx.pcap \ ++ options:rxq_pcap=${pcap_file}-rx.pcap ++} ++ ++reset_env() { ++ reset_pcap_file hv1 migrator hv1/migrator ++ reset_pcap_file hv2 migrator hv2/migrator ++ reset_pcap_file hv1 first hv1/first ++ reset_pcap_file hv2 second hv2/second ++ reset_pcap_file hv3 outside hv3/outside ++ ++ for port in hv1/migrator hv2/migrator hv1/first hv2/second hv3/outside; do ++ : > $port.expected ++ done ++} ++ ++check_packets() { ++ OVN_CHECK_PACKETS([hv1/migrator-tx.pcap], [hv1/migrator.expected]) ++ OVN_CHECK_PACKETS([hv2/migrator-tx.pcap], [hv2/migrator.expected]) ++ OVN_CHECK_PACKETS([hv3/outside-tx.pcap], [hv3/outside.expected]) ++ OVN_CHECK_PACKETS([hv1/first-tx.pcap], [hv1/first.expected]) ++ OVN_CHECK_PACKETS([hv2/second-tx.pcap], [hv2/second.expected]) ++} ++ ++migrator_spa=$(ip_to_hex 10 0 0 10) ++first_spa=$(ip_to_hex 10 0 0 1) ++second_spa=$(ip_to_hex 10 0 0 2) ++outside_spa=$(ip_to_hex 10 0 0 3) ++ ++reset_env ++ ++# Packet from hv3:Outside arrives to hv1:Migrator ++# hv3:Outside cannot reach hv2:Migrator because it is blocked by RARP strategy ++request=$(send_arp hv3 outside 000000000003 000000000010 $outside_spa $migrator_spa) ++echo $request >> hv1/migrator.expected ++ ++# Packet from hv1:First arrives to hv1:Migrator ++# hv1:First cannot reach hv2:Migrator because it is blocked by RARP strategy ++request=$(send_arp hv1 first 000000000001 000000000010 $first_spa $migrator_spa) ++echo $request >> hv1/migrator.expected ++ ++# Packet from hv2:Second arrives to hv1:Migrator ++# hv2:Second cannot reach hv2:Migrator because it is blocked by RARP strategy ++request=$(send_arp hv2 second 000000000002 000000000010 $second_spa $migrator_spa) ++echo $request >> hv1/migrator.expected ++ ++check_packets ++reset_env ++ ++# Packet from hv1:Migrator arrives to hv3:Outside ++request=$(send_arp hv1 migrator 000000000010 000000000003 $migrator_spa $outside_spa) ++echo $request >> hv3/outside.expected ++ ++# Packet from hv1:Migrator arrives to hv1:First ++request=$(send_arp hv1 migrator 000000000010 000000000001 $migrator_spa $first_spa) ++echo $request >> hv1/first.expected ++ ++# Packet from hv1:Migrator arrives to hv2:Second ++request=$(send_arp hv1 migrator 000000000010 000000000002 $migrator_spa $second_spa) ++echo $request >> hv2/second.expected ++ ++check_packets ++reset_env ++ ++# hv2:Migrator cannot reach to hv3:Outside because it is blocked by RARP strategy ++request=$(send_arp hv2 migrator 000000000010 000000000003 $migrator_spa $outside_spa) ++ ++check_packets ++reset_env ++ ++AT_CHECK([ovn-sbctl find port_binding logical_port=migrator | grep -q additional-chassis-activated], [1]) ++ ++# Now activate hv2:Migrator location ++request=$(send_rarp hv2 migrator 000000000010 ffffffffffff $migrator_spa $migrator_spa) ++ ++# RARP was reinjected into the pipeline ++echo $request >> hv3/outside.expected ++echo $request >> hv1/first.expected ++echo $request >> hv2/second.expected ++ ++check_packets ++reset_env ++ ++pb_uuid=$(ovn-sbctl --bare --columns _uuid find Port_Binding logical_port=migrator) ++OVS_WAIT_UNTIL([test xhv2 = x$(ovn-sbctl get Port_Binding $pb_uuid options:additional-chassis-activated | tr -d '""')]) ++ ++# Now packet arrives to both locations ++request=$(send_arp hv3 outside 000000000003 000000000010 $outside_spa $migrator_spa) ++echo $request >> hv1/migrator.expected ++echo $request >> hv2/migrator.expected ++ ++check_packets ++reset_env ++ ++# Packet from hv1:Migrator still arrives to hv3:Outside ++request=$(send_arp hv1 migrator 000000000010 000000000003 $migrator_spa $outside_spa) ++echo $request >> hv3/outside.expected ++ ++check_packets ++reset_env ++ ++# hv2:Migrator can now reach to hv3:Outside because RARP strategy activated it ++request=$(send_arp hv2 migrator 000000000010 000000000003 $migrator_spa $outside_spa) ++echo $request >> hv3/outside.expected ++ ++check_packets ++ ++# complete port migration and check that -activated flag is reset ++check ovn-nbctl lsp-set-options migrator requested-chassis=hv2 ++OVS_WAIT_UNTIL([test x = x$(ovn-sbctl get Port_Binding $pb_uuid options:additional-chassis-activated)]) ++ ++OVN_CLEANUP([hv1],[hv2],[hv3]) ++ ++AT_CLEANUP ++]) ++ ++OVN_FOR_EACH_NORTHD([ ++AT_SETUP([options:activation-strategy=rarp is not waiting for southbound db]) ++AT_KEYWORDS([multi-chassis]) ++# unskip when ovn-controller is able to process incremental updates to flow ++# table without ovsdb transaction available ++AT_SKIP_IF([true]) ++ ++ovn_start ++ ++net_add n1 ++ ++sim_add hv1 ++as hv1 ++check ovs-vsctl add-br br-phys ++ovn_attach n1 br-phys 192.168.0.11 ++ ++sim_add hv2 ++as hv2 ++check ovs-vsctl add-br br-phys ++ovn_attach n1 br-phys 192.168.0.12 ++ ++# Disable local ARP responder to pass ARP requests through tunnels ++check ovn-nbctl ls-add ls0 -- add Logical_Switch ls0 other_config vlan-passthru=true ++ ++check ovn-nbctl lsp-add ls0 migrator ++check ovn-nbctl lsp-set-options migrator requested-chassis=hv1,hv2 \ ++ activation-strategy=rarp ++ ++check ovn-nbctl lsp-add ls0 first ++check ovn-nbctl lsp-set-options first requested-chassis=hv1 ++ ++check ovn-nbctl lsp-set-addresses migrator "00:00:00:00:00:10 10.0.0.10" ++check ovn-nbctl lsp-set-addresses first "00:00:00:00:00:01 10.0.0.1" ++ ++for hv in hv1 hv2; do ++ as $hv check ovs-vsctl -- add-port br-int migrator -- \ ++ set Interface migrator external-ids:iface-id=migrator \ ++ options:tx_pcap=$hv/migrator-tx.pcap \ ++ options:rxq_pcap=$hv/migrator-rx.pcap ++done ++ ++as hv1 check ovs-vsctl -- add-port br-int first -- \ ++ set Interface first external-ids:iface-id=first ++ ++for hv in hv1 hv2; do ++ wait_row_count Chassis 1 name=$hv ++done ++hv1_uuid=$(fetch_column Chassis _uuid name=hv1) ++hv2_uuid=$(fetch_column Chassis _uuid name=hv2) ++ ++wait_column "$hv1_uuid" Port_Binding chassis logical_port=migrator ++wait_column "$hv1_uuid" Port_Binding requested_chassis logical_port=migrator ++wait_column "$hv2_uuid" Port_Binding additional_chassis logical_port=migrator ++wait_column "$hv2_uuid" Port_Binding requested_additional_chassis logical_port=migrator ++ ++wait_column "$hv1_uuid" Port_Binding chassis logical_port=first ++ ++OVN_POPULATE_ARP ++ ++send_arp() { ++ local hv=$1 inport=$2 eth_src=$3 eth_dst=$4 spa=$5 tpa=$6 ++ local request=${eth_dst}${eth_src}08060001080006040001${eth_src}${spa}${eth_dst}${tpa} ++ as ${hv} ovs-appctl netdev-dummy/receive $inport $request ++ echo "${request}" ++} ++ ++send_rarp() { ++ local hv=$1 inport=$2 eth_src=$3 eth_dst=$4 spa=$5 tpa=$6 ++ local request=${eth_dst}${eth_src}80350001080006040001${eth_src}${spa}${eth_dst}${tpa} ++ as ${hv} ovs-appctl netdev-dummy/receive $inport $request ++ echo "${request}" ++} ++ ++reset_pcap_file() { ++ local hv=$1 ++ local iface=$2 ++ local pcap_file=$3 ++ as $hv check ovs-vsctl -- set Interface $iface options:tx_pcap=dummy-tx.pcap \ ++ options:rxq_pcap=dummy-rx.pcap ++ check rm -f ${pcap_file}*.pcap ++ as $hv check ovs-vsctl -- set Interface $iface options:tx_pcap=${pcap_file}-tx.pcap \ ++ options:rxq_pcap=${pcap_file}-rx.pcap ++} ++ ++reset_env() { ++ reset_pcap_file hv1 migrator hv1/migrator ++ reset_pcap_file hv2 migrator hv2/migrator ++ reset_pcap_file hv1 first hv1/first ++ ++ for port in hv1/migrator hv2/migrator hv1/first; do ++ : > $port.expected ++ done ++} ++ ++check_packets() { ++ OVN_CHECK_PACKETS([hv1/migrator-tx.pcap], [hv1/migrator.expected]) ++ OVN_CHECK_PACKETS([hv2/migrator-tx.pcap], [hv2/migrator.expected]) ++ OVN_CHECK_PACKETS([hv1/first-tx.pcap], [hv1/first.expected]) ++} ++ ++migrator_spa=$(ip_to_hex 10 0 0 10) ++first_spa=$(ip_to_hex 10 0 0 1) ++ ++reset_env ++ ++# Packet from hv1:First arrives to hv1:Migrator ++# hv1:First cannot reach hv2:Migrator because it is blocked by RARP strategy ++request=$(send_arp hv1 first 000000000001 000000000010 $first_spa $migrator_spa) ++echo $request >> hv1/migrator.expected ++ ++check_packets ++reset_env ++ ++# Packet from hv1:Migrator arrives to hv1:First ++request=$(send_arp hv1 migrator 000000000010 000000000001 $migrator_spa $first_spa) ++echo $request >> hv1/first.expected ++ ++check_packets ++reset_env ++ ++# hv2:Migrator cannot reach to hv1:First because it is blocked by RARP strategy ++request=$(send_arp hv2 migrator 000000000010 000000000001 $migrator_spa $first_spa) ++ ++check_packets ++reset_env ++ ++# Before proceeding, stop ovsdb-server to make sure we test in the environment ++# that can't remove flows triggered by updates to database ++as ovn-sb ++OVS_APP_EXIT_AND_WAIT([ovsdb-server]) ++ ++# Now activate hv2:Migrator location ++request=$(send_rarp hv2 migrator 000000000010 ffffffffffff $migrator_spa $migrator_spa) ++ ++# RARP was reinjected into the pipeline ++echo $request >> hv1/first.expected ++ ++# Now packet from hv1:First arrives to both locations ++request=$(send_arp hv1 first 000000000001 000000000010 $first_spa $migrator_spa) ++echo $request >> hv1/migrator.expected ++echo $request >> hv2/migrator.expected ++ ++# Packet from hv1:Migrator still arrives to hv1:First ++request=$(send_arp hv1 migrator 000000000010 000000000001 $migrator_spa $first_spa) ++echo $request >> hv1/first.expected ++ ++# hv2:Migrator can now reach to hv1:First because RARP strategy activated it ++request=$(send_arp hv2 migrator 000000000010 000000000001 $migrator_spa $first_spa) ++echo $request >> hv1/first.expected ++ ++check_packets ++ ++# restart ovsdb-server before cleaning up to give ovn-controller a chance to ++# exit gracefully ++mv $ovs_base/ovn-sb/ovsdb-server.log $ovs_base/ovn-sb/ovsdb-server.log.prev ++as ovn-sb start_daemon ovsdb-server \ ++ -vjsonrpc \ ++ --remote=punix:$ovs_base/ovn-sb/$1.sock \ ++ --remote=db:OVN_Southbound,SB_Global,connections \ ++ --private-key=$PKIDIR/testpki-test-privkey.pem \ ++ --certificate=$PKIDIR/testpki-test-cert.pem \ ++ --ca-cert=$PKIDIR/testpki-cacert.pem \ ++ $ovs_base/ovn-sb/ovn-sb.db ++ ++PARSE_LISTENING_PORT([$ovs_base/ovn-sb/ovsdb-server.log], [TCP_PORT]) ++for i in 1 2; do ++ as hv$i ++ ovs-vsctl \ ++ -- set Open_vSwitch . external-ids:ovn-remote=ssl:127.0.0.1:$TCP_PORT ++done ++OVN_CLEANUP([hv1],[hv2]) ++ ++AT_CLEANUP ++]) ++ + OVN_FOR_EACH_NORTHD([ + AT_SETUP([options:requested-chassis for logical port]) + ovn_start +diff --git a/tests/system-ovn.at b/tests/system-ovn.at +index 4bf22593a..df2da3408 100644 +--- a/tests/system-ovn.at ++++ b/tests/system-ovn.at +@@ -6741,6 +6741,21 @@ NS_CHECK_EXEC([vm1], [ping -q -c 3 -i 0.3 -w 2 172.18.2.10 | FORMAT_PING], \ + [0], [dnl + 3 packets transmitted, 3 received, 0% packet loss, time 0ms + ]) ++ ++dnat_and_snat_uuid=$(fetch_column nb:NAT _uuid external_ip=172.18.2.10) ++ovn-nbctl set NAT $dnat_and_snat_uuid options:stateless=true ++ ++# A ping from vm1 should hairpin in lr1 and successfully DNAT to vm2 ++NS_CHECK_EXEC([vm1], [ping -q -c 3 -i 0.3 -w 2 172.18.2.10 | FORMAT_PING], \ ++[0], [dnl ++3 packets transmitted, 3 received, 0% packet loss, time 0ms ++]) ++# A ping from vm2 should hairpin in lr1 and successfully DNAT to vm2 ++NS_CHECK_EXEC([vm2], [ping -q -c 3 -i 0.3 -w 2 172.18.2.10 | FORMAT_PING], \ ++[0], [dnl ++3 packets transmitted, 3 received, 0% packet loss, time 0ms ++]) ++ + kill $(pidof ovn-controller) + + as ovn-sb +diff --git a/utilities/ovn-ctl b/utilities/ovn-ctl +index d733aa42d..93be9b84b 100755 +--- a/utilities/ovn-ctl ++++ b/utilities/ovn-ctl +@@ -42,8 +42,21 @@ ovn_ic_db_conf_file="$ovn_etcdir/ovn-ic-db-params.conf" + + pidfile_is_running () { + pidfile=$1 +- test -e "$pidfile" && [ -s "$pidfile" ] && pid=`cat "$pidfile"` && pid_exists "$pid" +-} >/dev/null 2>&1 ++ cmd=$2 ++ if [ ! -s "$pidfile" ]; then ++ # file missing or empty ++ return 1 ++ fi ++ pid=`cat "$pidfile"` ++ if ! pid_exists $pid; then ++ # pid is dead ++ return 1 ++ fi ++ if [ -n "$cmd" ]; then ++ return $(pid_comm_check "$cmd" "$pid") ++ fi ++ return 0 ++} + + stop_nb_ovsdb() { + OVS_RUNDIR=${OVS_RUNDIR} stop_ovn_daemon ovnnb_db $DB_NB_PIDFILE $DB_NB_CTRL_SOCK +@@ -199,7 +212,7 @@ start_ovsdb__() { + ovn_install_dir "$ovn_etcdir" + + # Check and eventually start ovsdb-server for DB +- if pidfile_is_running $db_pid_file; then ++ if pidfile_is_running $db_pid_file ovsdb-server; then + return + fi + +@@ -298,6 +311,10 @@ $cluster_remote_port + set "$@" --sync-from=`cat $active_conf_file` + fi + ++ if test X"$extra_args" != X; then ++ set "$@" $extra_args ++ fi ++ + local run_ovsdb_in_bg="no" + local process_id= + if test X$detach = Xno && test $mode = cluster && test -z "$cluster_remote_addr" ; then +@@ -528,6 +545,10 @@ start_ic () { + + set "$@" $OVN_IC_LOG $ovn_ic_params + ++ if test X"$extra_args" != X; then ++ set "$@" $extra_args ++ fi ++ + OVS_RUNDIR=${OVS_RUNDIR} start_ovn_daemon "$OVN_IC_PRIORITY" "$OVN_IC_WRAPPER" "$@" + fi + } +@@ -550,6 +571,10 @@ start_controller () { + + [ "$OVN_USER" != "" ] && set "$@" --user "$OVN_USER" + ++ if test X"$extra_args" != X; then ++ set "$@" $extra_args ++ fi ++ + OVS_RUNDIR=${OVS_RUNDIR} start_ovn_daemon "$OVN_CONTROLLER_PRIORITY" "$OVN_CONTROLLER_WRAPPER" "$@" + } + +@@ -577,6 +602,10 @@ start_controller_vtep () { + + [ "$OVN_USER" != "" ] && set "$@" --user "$OVN_USER" + ++ if test X"$extra_args" != X; then ++ set "$@" $extra_args ++ fi ++ + OVS_RUNDIR=${OVS_RUNDIR} start_ovn_daemon "$OVN_CONTROLLER_PRIORITY" "$OVN_CONTROLLER_WRAPPER" "$@" + } + +@@ -1093,8 +1122,10 @@ EOF + + set_defaults + command= ++extra_args= + for arg + do ++ shift + case $arg in + -h | --help) + usage +@@ -1117,6 +1148,10 @@ do + type=bool + set_option + ;; ++ --) ++ extra_args=$@ ++ break ++ ;; + -*) + echo >&2 "$0: unknown option \"$arg\" (use --help for help)" + exit 1 +diff --git a/utilities/ovn-ctl.8.xml b/utilities/ovn-ctl.8.xml +index a1d39b22b..42d16fabc 100644 +--- a/utilities/ovn-ctl.8.xml ++++ b/utilities/ovn-ctl.8.xml +@@ -4,7 +4,10 @@ +

    ovn-ctl -- Open Virtual Network northbound daemon lifecycle utility

    + +

    Synopsis

    +-

    ovn-ctl [options] command

    ++

    ++ ovn-ctl [options] command ++ [--- extra_args] ++

    + +

    Description

    +

    This program is intended to be invoked internally by Open Virtual Network +@@ -156,6 +159,15 @@ +

    --db-nb-probe-interval-to-active=Time in milliseconds

    +

    --db-sb-probe-interval-to-active=Time in milliseconds

    + ++

    Extra Options

    ++

    ++ Any options after '--' will be passed on to the binary run by ++ command with the exception of start_northd, which can have ++ options specified in ovn-northd-db-params.conf. Any extra_args ++ passed to start_northd will be passed to the ovsdb-servers if ++ --ovn-manage-ovsdb=yes ++

    ++ +

    Configuration files

    +

    Following are the optional configuration files. If present, it should be located in the etc dir

    + +diff --git a/utilities/ovn-dbctl.c b/utilities/ovn-dbctl.c +index a292e589d..c4cc8c9b2 100644 +--- a/utilities/ovn-dbctl.c ++++ b/utilities/ovn-dbctl.c +@@ -202,6 +202,13 @@ ovn_dbctl_main(int argc, char *argv[], + error = ctl_parse_commands(argc - optind, argv_ + optind, + &local_options, &commands, &n_commands); + if (error) { ++ ovsdb_idl_destroy(idl); ++ idl = the_idl = NULL; ++ ++ for (int i = 0; i < argc; i++) { ++ free(argv_[i]); ++ } ++ free(argv_); + ctl_fatal("%s", error); + } + diff --git a/SPECS/ovn22.03.spec b/SPECS/ovn22.03.spec deleted file mode 100644 index 4da4fd4..0000000 --- a/SPECS/ovn22.03.spec +++ /dev/null @@ -1,625 +0,0 @@ -# Copyright (C) 2009, 2010, 2013, 2014 Nicira Networks, Inc. -# -# Copying and distribution of this file, with or without modification, -# are permitted in any medium without royalty provided the copyright -# notice and this notice are preserved. This file is offered as-is, -# without warranty of any kind. -# -# If tests have to be skipped while building, specify the '--without check' -# option. For example: -# rpmbuild -bb --without check rhel/openvswitch-fedora.spec - -# This defines the base package name's version. - -%define pkgver 2.13 -%define pkgname ovn22.03 - -# If libcap-ng isn't available and there is no need for running OVS -# as regular user, specify the '--without libcapng' -%bcond_without libcapng - -# Enable PIE, bz#955181 -%global _hardened_build 1 - -# RHEL-7 doesn't define _rundir macro yet -# Fedora 15 onwards uses /run as _rundir -%if 0%{!?_rundir:1} -%define _rundir /run -%endif - -# Build python2 (that provides python) and python3 subpackages on Fedora -# Build only python3 (that provides python) subpackage on RHEL8 -# Build only python subpackage on RHEL7 -%if 0%{?rhel} > 7 || 0%{?fedora} -# On RHEL8 Sphinx is included in buildroot -%global external_sphinx 1 -%else -# Don't use external sphinx (RHV doesn't have optional repositories enabled) -%global external_sphinx 0 -%endif - -# We would see rpmlinit error - E: hardcoded-library-path in '% {_prefix}/lib'. -# But there is no solution to fix this. Using {_lib} macro will solve the -# rpmlink error, but will install the files in /usr/lib64/. -# OVN pacemaker ocf script file is copied in /usr/lib/ocf/resource.d/ovn/ -# and we are not sure if pacemaker looks into this path to find the -# OVN resource agent script. -%global ovnlibdir %{_prefix}/lib - -Name: %{pkgname} -Summary: Open Virtual Network support -Group: System Environment/Daemons -URL: http://www.ovn.org/ -Version: 22.03.0 -Release: 22%{?commit0:.%{date}git%{shortcommit0}}%{?dist} -Provides: openvswitch%{pkgver}-ovn-common = %{?epoch:%{epoch}:}%{version}-%{release} -Obsoletes: openvswitch%{pkgver}-ovn-common < 2.11.0-1 - -# Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the -# lib/sflow*.[ch] files are SISSL -License: ASL 2.0 and LGPLv2+ and SISSL - -# Always pull an upstream release, since this is what we rebase to. -Source: https://github.com/ovn-org/ovn/archive/v%{version}.tar.gz#/ovn-%{version}.tar.gz - -%define ovscommit ba159ee0f97ed770c244cd6710d34fe20595541d -%define ovsshortcommit ba159ee - -Source10: https://github.com/openvswitch/ovs/archive/%{ovscommit}.tar.gz#/openvswitch-%{ovsshortcommit}.tar.gz -%define ovsdir ovs-%{ovscommit} - -%define docutilsver 0.12 -%define pygmentsver 1.4 -%define sphinxver 1.1.3 -Source100: https://pypi.io/packages/source/d/docutils/docutils-%{docutilsver}.tar.gz -Source101: https://pypi.io/packages/source/P/Pygments/Pygments-%{pygmentsver}.tar.gz -Source102: https://pypi.io/packages/source/S/Sphinx/Sphinx-%{sphinxver}.tar.gz - -Source500: configlib.sh -Source501: gen_config_group.sh -Source502: set_config.sh - -# Important: source503 is used as the actual copy file -# @TODO: this causes a warning - fix it? -Source504: arm64-armv8a-linuxapp-gcc-config -Source505: ppc_64-power8-linuxapp-gcc-config -Source506: x86_64-native-linuxapp-gcc-config - -Patch: %{pkgname}.patch - -# FIXME Sphinx is used to generate some manpages, unfortunately, on RHEL, it's -# in the -optional repository and so we can't require it directly since RHV -# doesn't have the -optional repository enabled and so TPS fails -%if %{external_sphinx} -BuildRequires: python3-sphinx -%else -# Sphinx dependencies -BuildRequires: python-devel -BuildRequires: python-setuptools -#BuildRequires: python2-docutils -BuildRequires: python-jinja2 -BuildRequires: python-nose -#BuildRequires: python2-pygments -# docutils dependencies -BuildRequires: python-imaging -# pygments dependencies -BuildRequires: python-nose -%endif - -BuildRequires: gcc gcc-c++ make -BuildRequires: autoconf automake libtool -BuildRequires: systemd-units openssl openssl-devel -BuildRequires: python3-devel python3-setuptools -BuildRequires: desktop-file-utils -BuildRequires: groff-base graphviz -BuildRequires: unbound-devel - -# make check dependencies -BuildRequires: procps-ng -%if 0%{?rhel} == 8 || 0%{?fedora} -BuildRequires: python3-pyOpenSSL -%endif -BuildRequires: tcpdump - -%if %{with libcapng} -BuildRequires: libcap-ng libcap-ng-devel -%endif - -Requires: hostname openssl iproute module-init-tools - -Requires(post): systemd-units -Requires(preun): systemd-units -Requires(postun): systemd-units - -# to skip running checks, pass --without check -%bcond_without check - -%description -OVN, the Open Virtual Network, is a system to support virtual network -abstraction. OVN complements the existing capabilities of OVS to add -native support for virtual network abstractions, such as virtual L2 and L3 -overlays and security groups. - -%package central -Summary: Open Virtual Network support -License: ASL 2.0 -Requires: %{pkgname} -Requires: firewalld-filesystem -Provides: openvswitch%{pkgver}-ovn-central = %{?epoch:%{epoch}:}%{version}-%{release} -Obsoletes: openvswitch%{pkgver}-ovn-central < 2.11.0-1 - -%description central -OVN DB servers and ovn-northd running on a central node. - -%package host -Summary: Open Virtual Network support -License: ASL 2.0 -Requires: %{pkgname} -Requires: firewalld-filesystem -Provides: openvswitch%{pkgver}-ovn-host = %{?epoch:%{epoch}:}%{version}-%{release} -Obsoletes: openvswitch%{pkgver}-ovn-host < 2.11.0-1 - -%description host -OVN controller running on each host. - -%package vtep -Summary: Open Virtual Network support -License: ASL 2.0 -Requires: %{pkgname} -Provides: openvswitch%{pkgver}-ovn-vtep = %{?epoch:%{epoch}:}%{version}-%{release} -Obsoletes: openvswitch%{pkgver}-ovn-vtep < 2.11.0-1 - -%description vtep -OVN vtep controller - -%prep -%if 0%{?commit0:1} -%autosetup -n ovn-%{commit0} -a 10 -p 1 -%else -%autosetup -n ovn-%{version} -a 10 -p 1 -%endif - -%build -%if 0%{?commit0:1} -# fix the snapshot unreleased version to be the released one. -sed -i.old -e "s/^AC_INIT(openvswitch,.*,/AC_INIT(openvswitch, %{version},/" configure.ac -%endif -./boot.sh - -# OVN source code is now separate. -# Build openvswitch first. -# XXX Current openvswitch2.13 doesn't -# use "2.13.0" for version. It's a commit hash -pushd %{ovsdir} -./boot.sh -%configure \ -%if %{with libcapng} - --enable-libcapng \ -%else - --disable-libcapng \ -%endif - --enable-ssl \ - --with-pkidir=%{_sharedstatedir}/openvswitch/pki - -make %{?_smp_mflags} -popd - -# Build OVN. -# XXX OVS version needs to be updated when ovs2.13 is updated. -%configure \ - --with-ovs-source=$PWD/%{ovsdir} \ -%if %{with libcapng} - --enable-libcapng \ -%else - --disable-libcapng \ -%endif - --enable-ssl \ - --with-pkidir=%{_sharedstatedir}/openvswitch/pki - -make %{?_smp_mflags} - -%install -%make_install -install -p -D -m 0644 \ - rhel/usr_share_ovn_scripts_systemd_sysconfig.template \ - $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/ovn - -for service in ovn-controller ovn-controller-vtep ovn-northd; do - install -p -D -m 0644 \ - rhel/usr_lib_systemd_system_${service}.service \ - $RPM_BUILD_ROOT%{_unitdir}/${service}.service -done - -install -d -m 0755 $RPM_BUILD_ROOT/%{_sharedstatedir}/ovn - -install -d $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/ -install -p -m 0644 rhel/usr_lib_firewalld_services_ovn-central-firewall-service.xml \ - $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/ovn-central-firewall-service.xml -install -p -m 0644 rhel/usr_lib_firewalld_services_ovn-host-firewall-service.xml \ - $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/ovn-host-firewall-service.xml - -install -d -m 0755 $RPM_BUILD_ROOT%{ovnlibdir}/ocf/resource.d/ovn -ln -s %{_datadir}/ovn/scripts/ovndb-servers.ocf \ - $RPM_BUILD_ROOT%{ovnlibdir}/ocf/resource.d/ovn/ovndb-servers - -install -p -D -m 0644 rhel/etc_logrotate.d_ovn \ - $RPM_BUILD_ROOT/%{_sysconfdir}/logrotate.d/ovn - -# remove unneeded files. -rm -f $RPM_BUILD_ROOT%{_bindir}/ovs* -rm -f $RPM_BUILD_ROOT%{_bindir}/vtep-ctl -rm -f $RPM_BUILD_ROOT%{_sbindir}/ovs* -rm -f $RPM_BUILD_ROOT%{_mandir}/man1/ovs* -rm -f $RPM_BUILD_ROOT%{_mandir}/man5/ovs* -rm -f $RPM_BUILD_ROOT%{_mandir}/man5/vtep* -rm -f $RPM_BUILD_ROOT%{_mandir}/man7/ovs* -rm -f $RPM_BUILD_ROOT%{_mandir}/man8/ovs* -rm -f $RPM_BUILD_ROOT%{_mandir}/man8/vtep* -rm -rf $RPM_BUILD_ROOT%{_datadir}/ovn/python -rm -f $RPM_BUILD_ROOT%{_datadir}/ovn/scripts/ovs* -rm -rf $RPM_BUILD_ROOT%{_datadir}/ovn/bugtool-plugins -rm -f $RPM_BUILD_ROOT%{_libdir}/*.a -rm -f $RPM_BUILD_ROOT%{_libdir}/*.la -rm -f $RPM_BUILD_ROOT%{_libdir}/pkgconfig/*.pc -rm -f $RPM_BUILD_ROOT%{_includedir}/ovn/* -rm -f $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/ovs-appctl-bashcomp.bash -rm -f $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/ovs-vsctl-bashcomp.bash -rm -rf $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/openvswitch -rm -f $RPM_BUILD_ROOT%{_datadir}/ovn/scripts/ovn-bugtool* -rm -f $RPM_BUILD_ROOT/%{_bindir}/ovn-docker-overlay-driver \ - $RPM_BUILD_ROOT/%{_bindir}/ovn-docker-underlay-driver - -%check -%if %{with check} - touch resolv.conf - export OVS_RESOLV_CONF=$(pwd)/resolv.conf - if ! make check TESTSUITEFLAGS='%{_smp_mflags}'; then - cat tests/testsuite.log - if ! make check TESTSUITEFLAGS='--recheck'; then - cat tests/testsuite.log - # Presently a test case - "2796: ovn -- ovn-controller incremental processing" - # is failing on aarch64 arch. Let's not exit for this arch - # until we figure out why it is failing. - # Test case 93: ovn.at:12105 ovn -- ACLs on Port Groups is failing - # repeatedly on s390x. This needs to be investigated. - %ifnarch aarch64 - %ifnarch ppc64le - %ifnarch s390x - exit 1 - %endif - %endif - %endif - fi - fi -%endif - -%clean -rm -rf $RPM_BUILD_ROOT - -%pre central -if [ $1 -eq 1 ] ; then - # Package install. - /bin/systemctl status ovn-northd.service >/dev/null - ovn_status=$? - rpm -ql openvswitch-ovn-central > /dev/null - if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then - # ovn-northd service is running which means old openvswitch-ovn-central - # is already installed and it will be cleaned up. So start ovn-northd - # service when posttrans central is called. - touch %{_localstatedir}/lib/rpm-state/ovn-northd - fi -fi - -%pre host -if [ $1 -eq 1 ] ; then - # Package install. - /bin/systemctl status ovn-controller.service >/dev/null - ovn_status=$? - rpm -ql openvswitch-ovn-host > /dev/null - if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then - # ovn-controller service is running which means old - # openvswitch-ovn-host is installed and it will be cleaned up. So - # start ovn-controller service when posttrans host is called. - touch %{_localstatedir}/lib/rpm-state/ovn-controller - fi -fi - -%pre vtep -if [ $1 -eq 1 ] ; then - # Package install. - /bin/systemctl status ovn-controller-vtep.service >/dev/null - ovn_status=$? - rpm -ql openvswitch-ovn-vtep > /dev/null - if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then - # ovn-controller-vtep service is running which means old - # openvswitch-ovn-vtep is installed and it will be cleaned up. So - # start ovn-controller-vtep service when posttrans host is called. - touch %{_localstatedir}/lib/rpm-state/ovn-controller-vtep - fi -fi - -%preun central -%if 0%{?systemd_preun:1} - %systemd_preun ovn-northd.service -%else - if [ $1 -eq 0 ] ; then - # Package removal, not upgrade - /bin/systemctl --no-reload disable ovn-northd.service >/dev/null 2>&1 || : - /bin/systemctl stop ovn-northd.service >/dev/null 2>&1 || : - fi -%endif - -%preun host -%if 0%{?systemd_preun:1} - %systemd_preun ovn-controller.service -%else - if [ $1 -eq 0 ] ; then - # Package removal, not upgrade - /bin/systemctl --no-reload disable ovn-controller.service >/dev/null 2>&1 || : - /bin/systemctl stop ovn-controller.service >/dev/null 2>&1 || : - fi -%endif - -%preun vtep -%if 0%{?systemd_preun:1} - %systemd_preun ovn-controller-vtep.service -%else - if [ $1 -eq 0 ] ; then - # Package removal, not upgrade - /bin/systemctl --no-reload disable ovn-controller-vtep.service >/dev/null 2>&1 || : - /bin/systemctl stop ovn-controller-vtep.service >/dev/null 2>&1 || : - fi -%endif - -%post -%if %{with libcapng} -if [ $1 -eq 1 ]; then - sed -i 's:^#OVN_USER_ID=:OVN_USER_ID=:' %{_sysconfdir}/sysconfig/ovn - sed -i 's:\(.*su\).*:\1 openvswitch openvswitch:' %{_sysconfdir}/logrotate.d/ovn -fi -%endif - -%post central -%if 0%{?systemd_post:1} - %systemd_post ovn-northd.service -%else - # Package install, not upgrade - if [ $1 -eq 1 ]; then - /bin/systemctl daemon-reload >dev/null || : - fi -%endif - -%post host -%if 0%{?systemd_post:1} - %systemd_post ovn-controller.service -%else - # Package install, not upgrade - if [ $1 -eq 1 ]; then - /bin/systemctl daemon-reload >dev/null || : - fi -%endif - -%post vtep -%if 0%{?systemd_post:1} - %systemd_post ovn-controller-vtep.service -%else - # Package install, not upgrade - if [ $1 -eq 1 ]; then - /bin/systemctl daemon-reload >dev/null || : - fi -%endif - -%postun - -%postun central -%if 0%{?systemd_postun_with_restart:1} - %systemd_postun_with_restart ovn-northd.service -%else - /bin/systemctl daemon-reload >/dev/null 2>&1 || : - if [ "$1" -ge "1" ] ; then - # Package upgrade, not uninstall - /bin/systemctl try-restart ovn-northd.service >/dev/null 2>&1 || : - fi -%endif - -%postun host -%if 0%{?systemd_postun_with_restart:1} - %systemd_postun_with_restart ovn-controller.service -%else - /bin/systemctl daemon-reload >/dev/null 2>&1 || : - if [ "$1" -ge "1" ] ; then - # Package upgrade, not uninstall - /bin/systemctl try-restart ovn-controller.service >/dev/null 2>&1 || : - fi -%endif - -%postun vtep -%if 0%{?systemd_postun_with_restart:1} - %systemd_postun_with_restart ovn-controller-vtep.service -%else - /bin/systemctl daemon-reload >/dev/null 2>&1 || : - if [ "$1" -ge "1" ] ; then - # Package upgrade, not uninstall - /bin/systemctl try-restart ovn-controller-vtep.service >/dev/null 2>&1 || : - fi -%endif - -%posttrans central -if [ $1 -eq 1 ]; then - # Package install, not upgrade - if [ -e %{_localstatedir}/lib/rpm-state/ovn-northd ]; then - rm %{_localstatedir}/lib/rpm-state/ovn-northd - /bin/systemctl start ovn-northd.service >/dev/null 2>&1 || : - fi -fi - - -%posttrans host -if [ $1 -eq 1 ]; then - # Package install, not upgrade - if [ -e %{_localstatedir}/lib/rpm-state/ovn-controller ]; then - rm %{_localstatedir}/lib/rpm-state/ovn-controller - /bin/systemctl start ovn-controller.service >/dev/null 2>&1 || : - fi -fi - -%posttrans vtep -if [ $1 -eq 1 ]; then - # Package install, not upgrade - if [ -e %{_localstatedir}/lib/rpm-state/ovn-controller-vtep ]; then - rm %{_localstatedir}/lib/rpm-state/ovn-controller-vtep - /bin/systemctl start ovn-controller-vtep.service >/dev/null 2>&1 || : - fi -fi - -%files -%{_bindir}/ovn-nbctl -%{_bindir}/ovn-sbctl -%{_bindir}/ovn-trace -%{_bindir}/ovn-detrace -%{_bindir}/ovn_detrace.py -%{_bindir}/ovn-appctl -%{_bindir}/ovn-ic-nbctl -%{_bindir}/ovn-ic-sbctl -%dir %{_datadir}/ovn/ -%dir %{_datadir}/ovn/scripts/ -%{_datadir}/ovn/scripts/ovn-ctl -%{_datadir}/ovn/scripts/ovn-lib -%{_datadir}/ovn/scripts/ovndb-servers.ocf -%{_mandir}/man8/ovn-ctl.8* -%{_mandir}/man8/ovn-appctl.8* -%{_mandir}/man8/ovn-nbctl.8* -%{_mandir}/man8/ovn-ic-nbctl.8* -%{_mandir}/man8/ovn-trace.8* -%{_mandir}/man1/ovn-detrace.1* -%{_mandir}/man7/ovn-architecture.7* -%{_mandir}/man8/ovn-sbctl.8* -%{_mandir}/man8/ovn-ic-sbctl.8* -%{_mandir}/man5/ovn-nb.5* -%{_mandir}/man5/ovn-ic-nb.5* -%{_mandir}/man5/ovn-sb.5* -%{_mandir}/man5/ovn-ic-sb.5* -%dir %{ovnlibdir}/ocf/resource.d/ovn/ -%{ovnlibdir}/ocf/resource.d/ovn/ovndb-servers -%config(noreplace) %verify(not md5 size mtime) %{_sysconfdir}/logrotate.d/ovn -%config(noreplace) %verify(not md5 size mtime) %{_sysconfdir}/sysconfig/ovn - -%files central -%{_bindir}/ovn-northd -%{_bindir}/ovn-ic -%{_mandir}/man8/ovn-northd.8* -%{_mandir}/man8/ovn-ic.8* -%{_datadir}/ovn/ovn-nb.ovsschema -%{_datadir}/ovn/ovn-ic-nb.ovsschema -%{_datadir}/ovn/ovn-sb.ovsschema -%{_datadir}/ovn/ovn-ic-sb.ovsschema -%{_unitdir}/ovn-northd.service -%{ovnlibdir}/firewalld/services/ovn-central-firewall-service.xml - -%files host -%{_bindir}/ovn-controller -%{_mandir}/man8/ovn-controller.8* -%{_unitdir}/ovn-controller.service -%{ovnlibdir}/firewalld/services/ovn-host-firewall-service.xml - -%files vtep -%{_bindir}/ovn-controller-vtep -%{_mandir}/man8/ovn-controller-vtep.8* -%{_unitdir}/ovn-controller-vtep.service - -%changelog -* Tue Apr 26 2022 Adrian Moreno - 22.03.0-22 -- parallel-hmap: rewrite iterator using multivar helpers -[Gerrit: 3da85a6660776548ddafaa9759b260b0dac38b4b] -[Upstream: 3da85a6660776548ddafaa9759b260b0dac38b4b] - -* Tue Apr 26 2022 Adrian Moreno - 22.03.0-21 -- treewide: bump ovs and fix problematic loops -[Gerrit: 985ef4580ac6558859e104bad6fd5e2a68af79f7] -[Upstream: 985ef4580ac6558859e104bad6fd5e2a68af79f7] - -* Tue Apr 26 2022 Mark Michelson - 22.03.0-20 -- Get OVS branch updated to proper base version for upcoming changes. -[Gerrit: 367051dacab28dbe875aba9e1920b5693cf284c3] -[Upstream: 367051dacab28dbe875aba9e1920b5693cf284c3] - -* Mon Apr 25 2022 Numan Siddique - 22.03.0-19 -- ovn-northd: Add flow to use eth.src if nd.tll is 0 in put_nd() action. (#2078026) -[Gerrit: bd0ee4c1103ca5eaf834e48093205cacddaadf31] -[Upstream: 80187a8031b6abe01fb23657a9bed2372ae23af5] - -* Thu Apr 21 2022 Ihar Hrachyshka - 22.03.0-18 -- Stop sending garps when binding not bound to chassis -[Gerrit: 65088824dbca07dfdf3402d1775d3af76a304ef4] -[Upstream: 65088824dbca07dfdf3402d1775d3af76a304ef4] - -* Thu Apr 21 2022 Ales Musil - 22.03.0-17 -- pinctrl.c: Send GARP only on chassis atached to l3gw (#2062580) -[Gerrit: 77ec310dda51c78c1897011ba851612787fcc6c6] -[Upstream: 77ec310dda51c78c1897011ba851612787fcc6c6] - -* Sun Apr 17 2022 Lorenzo Bianconi - 22.03.0-16 -- system-ovn: fix CoPP test failures (#2073060) -[Gerrit: 388446ff27650773716ebcbc332424b1bf82bad1] -[Upstream: e922c05dbb0c0ca70c98bd0b24833248ff5d458b] - -* Wed Apr 13 2022 Han Zhou - 22.03.0-15 -- ofctrl.c: Check installed flow when merging tracked flow changes. (#2071272) -[Gerrit: 92cdada0e150e937e19f52c98a0c6a6dba7a84e0] -[Upstream: 9c6d285ef2a65aef032cd60f9a9fe16cad7c4222] - -* Mon Apr 11 2022 Xavier Simonart - 22.03.0-14 -- northd: avoid writing to IDL in parallel when using northd parallelization -[Gerrit: 6410cb7906121bf2ebec3698d53bcfcb580ca4f6] -[Upstream: 741a135fa1db9e10b725d4b69c6da455f732b89b] - -* Thu Apr 07 2022 Mohammad Heib - 22.03.0-13 -- controller/pinctrl: avoid accessing invalid memory (#2052945) -[Gerrit: 55a0ab5d2971daaf22e3d935f623bf7548a3df98] -[Upstream: 6bc6002601ea161a287bcf53524e9282ab97c31b] - -* Thu Apr 07 2022 Xavier Simonart - 22.03.0-12 -- northd: avoid snat on reply packets (#2061593) -[Gerrit: be49d5145e10b1e4a525eed3b12d7ffb7818f2d1] -[Upstream: 8b3e1afc30f3cf0ef9857fdc68f619b6fbed10dc] - -* Wed Apr 06 2022 Vladislav Odintsov - 22.03.0-11 -- vtep: correctly bring vtep lport up in SBDB -[Gerrit: 655c3aa74d45791b0de5548c787ee24a147f2456] -[Upstream: b35c98c923f4972198f741ff1d2b28671d6ff50d] - -* Wed Apr 06 2022 Lorenzo Bianconi - 22.03.0-10 -- controller: properly remove qos policy meters -[Gerrit: a814b865fbec460c91f9b5037d936b9d518c7a2f] -[Upstream: 1e1d75c725a3445a853dd792b28ff02bb3ab1218] - -* Wed Mar 30 2022 Mark Michelson - 22.03.0-9 -- tests: Make "check CoPP config" more reliable. -[Gerrit: 93e21802ac27ed29f2a4daf58a10912ebd581db5] -[Upstream: 93e21802ac27ed29f2a4daf58a10912ebd581db5] - -* Tue Mar 29 2022 Dumitru Ceara - 22.03.0-8 -- inc-proc-eng: Properly log recompute reason. -[Gerrit: 3b07a5db4abd921a87b6fdfb851cf27e6975b079] -[Upstream: 3b07a5db4abd921a87b6fdfb851cf27e6975b079] - -* Thu Mar 24 2022 Mark Michelson - 22.03.0-7 -- NEWS: Update the 22.03.0 release date. -[Gerrit: e62886efda51adadd6c01c4e7ee0bbd97994216c] -[Upstream: e62886efda51adadd6c01c4e7ee0bbd97994216c] - -* Thu Mar 24 2022 Vladislav Odintsov - 22.03.0-6 -- rhel: fix logrotate user config option -[Gerrit: 135310cae98e84a637f13e99439566846debcb29] -[Upstream: e8800ddd9e919e2ffc9d8c5c9ab27f0a5a6ec2e5] - -* Thu Mar 17 2022 Dumitru Ceara - 22.03.0-5 -- northd: Properly warn for NAT on LR with multiple gw ports. -[Gerrit: 622d15d078178e854027358d5130690edbe75a4c] -[Upstream: b8194738c99ee09ad6d4762a3c999e04d58d1a0f] - -* Fri Mar 11 2022 Mark Michelson - 22.03.0-4 -- Prepare for 22.03.1. -[Gerrit: b3d273f73c4aa8d246e652f1fb505779d3828c5b] -[Upstream: b3d273f73c4aa8d246e652f1fb505779d3828c5b] - diff --git a/SPECS/ovn22.06.spec b/SPECS/ovn22.06.spec new file mode 100644 index 0000000..23798b6 --- /dev/null +++ b/SPECS/ovn22.06.spec @@ -0,0 +1,591 @@ +# Copyright (C) 2009, 2010, 2013, 2014 Nicira Networks, Inc. +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. This file is offered as-is, +# without warranty of any kind. +# +# If tests have to be skipped while building, specify the '--without check' +# option. For example: +# rpmbuild -bb --without check rhel/openvswitch-fedora.spec + +# This defines the base package name's version. + +%define pkgver 2.13 +%define pkgname ovn22.06 + +# If libcap-ng isn't available and there is no need for running OVS +# as regular user, specify the '--without libcapng' +%bcond_without libcapng + +# Enable PIE, bz#955181 +%global _hardened_build 1 + +# RHEL-7 doesn't define _rundir macro yet +# Fedora 15 onwards uses /run as _rundir +%if 0%{!?_rundir:1} +%define _rundir /run +%endif + +# Build python2 (that provides python) and python3 subpackages on Fedora +# Build only python3 (that provides python) subpackage on RHEL8 +# Build only python subpackage on RHEL7 +%if 0%{?rhel} > 7 || 0%{?fedora} +# On RHEL8 Sphinx is included in buildroot +%global external_sphinx 1 +%else +# Don't use external sphinx (RHV doesn't have optional repositories enabled) +%global external_sphinx 0 +%endif + +# We would see rpmlinit error - E: hardcoded-library-path in '% {_prefix}/lib'. +# But there is no solution to fix this. Using {_lib} macro will solve the +# rpmlink error, but will install the files in /usr/lib64/. +# OVN pacemaker ocf script file is copied in /usr/lib/ocf/resource.d/ovn/ +# and we are not sure if pacemaker looks into this path to find the +# OVN resource agent script. +%global ovnlibdir %{_prefix}/lib + +Name: %{pkgname} +Summary: Open Virtual Network support +Group: System Environment/Daemons +URL: http://www.ovn.org/ +Version: 22.06.0 +Release: 16%{?commit0:.%{date}git%{shortcommit0}}%{?dist} +Provides: openvswitch%{pkgver}-ovn-common = %{?epoch:%{epoch}:}%{version}-%{release} +Obsoletes: openvswitch%{pkgver}-ovn-common < 2.11.0-1 + +# Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the +# lib/sflow*.[ch] files are SISSL +License: ASL 2.0 and LGPLv2+ and SISSL + +# Always pull an upstream release, since this is what we rebase to. +Source: https://github.com/ovn-org/ovn/archive/v%{version}.tar.gz#/ovn-%{version}.tar.gz + +%define ovscommit 6f24c2bc769afde0a390ce344de1a7d9c592e5a6 +%define ovsshortcommit 6f24c2b + +Source10: https://github.com/openvswitch/ovs/archive/%{ovscommit}.tar.gz#/openvswitch-%{ovsshortcommit}.tar.gz +%define ovsdir ovs-%{ovscommit} + +%define docutilsver 0.12 +%define pygmentsver 1.4 +%define sphinxver 1.1.3 +Source100: https://pypi.io/packages/source/d/docutils/docutils-%{docutilsver}.tar.gz +Source101: https://pypi.io/packages/source/P/Pygments/Pygments-%{pygmentsver}.tar.gz +Source102: https://pypi.io/packages/source/S/Sphinx/Sphinx-%{sphinxver}.tar.gz + +Source500: configlib.sh +Source501: gen_config_group.sh +Source502: set_config.sh + +# Important: source503 is used as the actual copy file +# @TODO: this causes a warning - fix it? +Source504: arm64-armv8a-linuxapp-gcc-config +Source505: ppc_64-power8-linuxapp-gcc-config +Source506: x86_64-native-linuxapp-gcc-config + +Patch: %{pkgname}.patch + +# FIXME Sphinx is used to generate some manpages, unfortunately, on RHEL, it's +# in the -optional repository and so we can't require it directly since RHV +# doesn't have the -optional repository enabled and so TPS fails +%if %{external_sphinx} +BuildRequires: python3-sphinx +%else +# Sphinx dependencies +BuildRequires: python-devel +BuildRequires: python-setuptools +#BuildRequires: python2-docutils +BuildRequires: python-jinja2 +BuildRequires: python-nose +#BuildRequires: python2-pygments +# docutils dependencies +BuildRequires: python-imaging +# pygments dependencies +BuildRequires: python-nose +%endif + +BuildRequires: gcc gcc-c++ make +BuildRequires: autoconf automake libtool +BuildRequires: systemd-units openssl openssl-devel +BuildRequires: python3-devel python3-setuptools +BuildRequires: desktop-file-utils +BuildRequires: groff-base graphviz +BuildRequires: unbound-devel + +# make check dependencies +BuildRequires: procps-ng +%if 0%{?rhel} == 8 || 0%{?fedora} +BuildRequires: python3-pyOpenSSL +%endif +BuildRequires: tcpdump + +%if %{with libcapng} +BuildRequires: libcap-ng libcap-ng-devel +%endif + +Requires: hostname openssl iproute module-init-tools + +Requires(post): systemd-units +Requires(preun): systemd-units +Requires(postun): systemd-units + +# to skip running checks, pass --without check +%bcond_without check + +%description +OVN, the Open Virtual Network, is a system to support virtual network +abstraction. OVN complements the existing capabilities of OVS to add +native support for virtual network abstractions, such as virtual L2 and L3 +overlays and security groups. + +%package central +Summary: Open Virtual Network support +License: ASL 2.0 +Requires: %{pkgname} +Requires: firewalld-filesystem +Provides: openvswitch%{pkgver}-ovn-central = %{?epoch:%{epoch}:}%{version}-%{release} +Obsoletes: openvswitch%{pkgver}-ovn-central < 2.11.0-1 + +%description central +OVN DB servers and ovn-northd running on a central node. + +%package host +Summary: Open Virtual Network support +License: ASL 2.0 +Requires: %{pkgname} +Requires: firewalld-filesystem +Provides: openvswitch%{pkgver}-ovn-host = %{?epoch:%{epoch}:}%{version}-%{release} +Obsoletes: openvswitch%{pkgver}-ovn-host < 2.11.0-1 + +%description host +OVN controller running on each host. + +%package vtep +Summary: Open Virtual Network support +License: ASL 2.0 +Requires: %{pkgname} +Provides: openvswitch%{pkgver}-ovn-vtep = %{?epoch:%{epoch}:}%{version}-%{release} +Obsoletes: openvswitch%{pkgver}-ovn-vtep < 2.11.0-1 + +%description vtep +OVN vtep controller + +%prep +%autosetup -n ovn-%{version} -a 10 -p 1 + +%build +%if 0%{?commit0:1} +# fix the snapshot unreleased version to be the released one. +sed -i.old -e "s/^AC_INIT(openvswitch,.*,/AC_INIT(openvswitch, %{version},/" configure.ac +%endif +./boot.sh + +# OVN source code is now separate. +# Build openvswitch first. +# XXX Current openvswitch2.13 doesn't +# use "2.13.0" for version. It's a commit hash +pushd %{ovsdir} +./boot.sh +%configure \ +%if %{with libcapng} + --enable-libcapng \ +%else + --disable-libcapng \ +%endif + --enable-ssl \ + --with-pkidir=%{_sharedstatedir}/openvswitch/pki + +make %{?_smp_mflags} +popd + +# Build OVN. +# XXX OVS version needs to be updated when ovs2.13 is updated. +%configure \ + --with-ovs-source=$PWD/%{ovsdir} \ +%if %{with libcapng} + --enable-libcapng \ +%else + --disable-libcapng \ +%endif + --enable-ssl \ + --with-pkidir=%{_sharedstatedir}/openvswitch/pki + +make %{?_smp_mflags} + +%install +%make_install +install -p -D -m 0644 \ + rhel/usr_share_ovn_scripts_systemd_sysconfig.template \ + $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/ovn + +for service in ovn-controller ovn-controller-vtep ovn-northd; do + install -p -D -m 0644 \ + rhel/usr_lib_systemd_system_${service}.service \ + $RPM_BUILD_ROOT%{_unitdir}/${service}.service +done + +install -d -m 0755 $RPM_BUILD_ROOT/%{_sharedstatedir}/ovn + +install -d $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/ +install -p -m 0644 rhel/usr_lib_firewalld_services_ovn-central-firewall-service.xml \ + $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/ovn-central-firewall-service.xml +install -p -m 0644 rhel/usr_lib_firewalld_services_ovn-host-firewall-service.xml \ + $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/ovn-host-firewall-service.xml + +install -d -m 0755 $RPM_BUILD_ROOT%{ovnlibdir}/ocf/resource.d/ovn +ln -s %{_datadir}/ovn/scripts/ovndb-servers.ocf \ + $RPM_BUILD_ROOT%{ovnlibdir}/ocf/resource.d/ovn/ovndb-servers + +install -p -D -m 0644 rhel/etc_logrotate.d_ovn \ + $RPM_BUILD_ROOT/%{_sysconfdir}/logrotate.d/ovn + +# remove unneeded files. +rm -f $RPM_BUILD_ROOT%{_bindir}/ovs* +rm -f $RPM_BUILD_ROOT%{_bindir}/vtep-ctl +rm -f $RPM_BUILD_ROOT%{_sbindir}/ovs* +rm -f $RPM_BUILD_ROOT%{_mandir}/man1/ovs* +rm -f $RPM_BUILD_ROOT%{_mandir}/man5/ovs* +rm -f $RPM_BUILD_ROOT%{_mandir}/man5/vtep* +rm -f $RPM_BUILD_ROOT%{_mandir}/man7/ovs* +rm -f $RPM_BUILD_ROOT%{_mandir}/man8/ovs* +rm -f $RPM_BUILD_ROOT%{_mandir}/man8/vtep* +rm -rf $RPM_BUILD_ROOT%{_datadir}/ovn/python +rm -f $RPM_BUILD_ROOT%{_datadir}/ovn/scripts/ovs* +rm -rf $RPM_BUILD_ROOT%{_datadir}/ovn/bugtool-plugins +rm -f $RPM_BUILD_ROOT%{_libdir}/*.a +rm -f $RPM_BUILD_ROOT%{_libdir}/*.la +rm -f $RPM_BUILD_ROOT%{_libdir}/pkgconfig/*.pc +rm -f $RPM_BUILD_ROOT%{_includedir}/ovn/* +rm -f $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/ovs-appctl-bashcomp.bash +rm -f $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/ovs-vsctl-bashcomp.bash +rm -rf $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/openvswitch +rm -f $RPM_BUILD_ROOT%{_datadir}/ovn/scripts/ovn-bugtool* +rm -f $RPM_BUILD_ROOT/%{_bindir}/ovn-docker-overlay-driver \ + $RPM_BUILD_ROOT/%{_bindir}/ovn-docker-underlay-driver + +%check +%if %{with check} + touch resolv.conf + export OVS_RESOLV_CONF=$(pwd)/resolv.conf + if ! make check TESTSUITEFLAGS='%{_smp_mflags}'; then + cat tests/testsuite.log + if ! make check TESTSUITEFLAGS='--recheck'; then + cat tests/testsuite.log + # Presently a test case - "2796: ovn -- ovn-controller incremental processing" + # is failing on aarch64 arch. Let's not exit for this arch + # until we figure out why it is failing. + # Test case 93: ovn.at:12105 ovn -- ACLs on Port Groups is failing + # repeatedly on s390x. This needs to be investigated. + %ifnarch aarch64 + %ifnarch ppc64le + %ifnarch s390x + exit 1 + %endif + %endif + %endif + fi + fi +%endif + +%clean +rm -rf $RPM_BUILD_ROOT + +%pre central +if [ $1 -eq 1 ] ; then + # Package install. + /bin/systemctl status ovn-northd.service >/dev/null + ovn_status=$? + rpm -ql openvswitch-ovn-central > /dev/null + if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then + # ovn-northd service is running which means old openvswitch-ovn-central + # is already installed and it will be cleaned up. So start ovn-northd + # service when posttrans central is called. + touch %{_localstatedir}/lib/rpm-state/ovn-northd + fi +fi + +%pre host +if [ $1 -eq 1 ] ; then + # Package install. + /bin/systemctl status ovn-controller.service >/dev/null + ovn_status=$? + rpm -ql openvswitch-ovn-host > /dev/null + if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then + # ovn-controller service is running which means old + # openvswitch-ovn-host is installed and it will be cleaned up. So + # start ovn-controller service when posttrans host is called. + touch %{_localstatedir}/lib/rpm-state/ovn-controller + fi +fi + +%pre vtep +if [ $1 -eq 1 ] ; then + # Package install. + /bin/systemctl status ovn-controller-vtep.service >/dev/null + ovn_status=$? + rpm -ql openvswitch-ovn-vtep > /dev/null + if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then + # ovn-controller-vtep service is running which means old + # openvswitch-ovn-vtep is installed and it will be cleaned up. So + # start ovn-controller-vtep service when posttrans host is called. + touch %{_localstatedir}/lib/rpm-state/ovn-controller-vtep + fi +fi + +%preun central +%if 0%{?systemd_preun:1} + %systemd_preun ovn-northd.service +%else + if [ $1 -eq 0 ] ; then + # Package removal, not upgrade + /bin/systemctl --no-reload disable ovn-northd.service >/dev/null 2>&1 || : + /bin/systemctl stop ovn-northd.service >/dev/null 2>&1 || : + fi +%endif + +%preun host +%if 0%{?systemd_preun:1} + %systemd_preun ovn-controller.service +%else + if [ $1 -eq 0 ] ; then + # Package removal, not upgrade + /bin/systemctl --no-reload disable ovn-controller.service >/dev/null 2>&1 || : + /bin/systemctl stop ovn-controller.service >/dev/null 2>&1 || : + fi +%endif + +%preun vtep +%if 0%{?systemd_preun:1} + %systemd_preun ovn-controller-vtep.service +%else + if [ $1 -eq 0 ] ; then + # Package removal, not upgrade + /bin/systemctl --no-reload disable ovn-controller-vtep.service >/dev/null 2>&1 || : + /bin/systemctl stop ovn-controller-vtep.service >/dev/null 2>&1 || : + fi +%endif + +%post +%if %{with libcapng} +if [ $1 -eq 1 ]; then + sed -i 's:^#OVN_USER_ID=:OVN_USER_ID=:' %{_sysconfdir}/sysconfig/ovn + sed -i 's:\(.*su\).*:\1 openvswitch openvswitch:' %{_sysconfdir}/logrotate.d/ovn +fi +%endif + +%post central +%if 0%{?systemd_post:1} + %systemd_post ovn-northd.service +%else + # Package install, not upgrade + if [ $1 -eq 1 ]; then + /bin/systemctl daemon-reload >dev/null || : + fi +%endif + +%post host +%if 0%{?systemd_post:1} + %systemd_post ovn-controller.service +%else + # Package install, not upgrade + if [ $1 -eq 1 ]; then + /bin/systemctl daemon-reload >dev/null || : + fi +%endif + +%post vtep +%if 0%{?systemd_post:1} + %systemd_post ovn-controller-vtep.service +%else + # Package install, not upgrade + if [ $1 -eq 1 ]; then + /bin/systemctl daemon-reload >dev/null || : + fi +%endif + +%postun + +%postun central +%if 0%{?systemd_postun_with_restart:1} + %systemd_postun_with_restart ovn-northd.service +%else + /bin/systemctl daemon-reload >/dev/null 2>&1 || : + if [ "$1" -ge "1" ] ; then + # Package upgrade, not uninstall + /bin/systemctl try-restart ovn-northd.service >/dev/null 2>&1 || : + fi +%endif + +%postun host +%if 0%{?systemd_postun_with_restart:1} + %systemd_postun_with_restart ovn-controller.service +%else + /bin/systemctl daemon-reload >/dev/null 2>&1 || : + if [ "$1" -ge "1" ] ; then + # Package upgrade, not uninstall + /bin/systemctl try-restart ovn-controller.service >/dev/null 2>&1 || : + fi +%endif + +%postun vtep +%if 0%{?systemd_postun_with_restart:1} + %systemd_postun_with_restart ovn-controller-vtep.service +%else + /bin/systemctl daemon-reload >/dev/null 2>&1 || : + if [ "$1" -ge "1" ] ; then + # Package upgrade, not uninstall + /bin/systemctl try-restart ovn-controller-vtep.service >/dev/null 2>&1 || : + fi +%endif + +%posttrans central +if [ $1 -eq 1 ]; then + # Package install, not upgrade + if [ -e %{_localstatedir}/lib/rpm-state/ovn-northd ]; then + rm %{_localstatedir}/lib/rpm-state/ovn-northd + /bin/systemctl start ovn-northd.service >/dev/null 2>&1 || : + fi +fi + + +%posttrans host +if [ $1 -eq 1 ]; then + # Package install, not upgrade + if [ -e %{_localstatedir}/lib/rpm-state/ovn-controller ]; then + rm %{_localstatedir}/lib/rpm-state/ovn-controller + /bin/systemctl start ovn-controller.service >/dev/null 2>&1 || : + fi +fi + +%posttrans vtep +if [ $1 -eq 1 ]; then + # Package install, not upgrade + if [ -e %{_localstatedir}/lib/rpm-state/ovn-controller-vtep ]; then + rm %{_localstatedir}/lib/rpm-state/ovn-controller-vtep + /bin/systemctl start ovn-controller-vtep.service >/dev/null 2>&1 || : + fi +fi + +%files +%{_bindir}/ovn-nbctl +%{_bindir}/ovn-sbctl +%{_bindir}/ovn-trace +%{_bindir}/ovn-detrace +%{_bindir}/ovn_detrace.py +%{_bindir}/ovn-appctl +%{_bindir}/ovn-ic-nbctl +%{_bindir}/ovn-ic-sbctl +%dir %{_datadir}/ovn/ +%dir %{_datadir}/ovn/scripts/ +%{_datadir}/ovn/scripts/ovn-ctl +%{_datadir}/ovn/scripts/ovn-lib +%{_datadir}/ovn/scripts/ovndb-servers.ocf +%{_mandir}/man8/ovn-ctl.8* +%{_mandir}/man8/ovn-appctl.8* +%{_mandir}/man8/ovn-nbctl.8* +%{_mandir}/man8/ovn-ic-nbctl.8* +%{_mandir}/man8/ovn-trace.8* +%{_mandir}/man1/ovn-detrace.1* +%{_mandir}/man7/ovn-architecture.7* +%{_mandir}/man8/ovn-sbctl.8* +%{_mandir}/man8/ovn-ic-sbctl.8* +%{_mandir}/man5/ovn-nb.5* +%{_mandir}/man5/ovn-ic-nb.5* +%{_mandir}/man5/ovn-sb.5* +%{_mandir}/man5/ovn-ic-sb.5* +%dir %{ovnlibdir}/ocf/resource.d/ovn/ +%{ovnlibdir}/ocf/resource.d/ovn/ovndb-servers +%config(noreplace) %verify(not md5 size mtime) %{_sysconfdir}/logrotate.d/ovn +%config(noreplace) %verify(not md5 size mtime) %{_sysconfdir}/sysconfig/ovn + +%files central +%{_bindir}/ovn-northd +%{_bindir}/ovn-ic +%{_mandir}/man8/ovn-northd.8* +%{_mandir}/man8/ovn-ic.8* +%{_datadir}/ovn/ovn-nb.ovsschema +%{_datadir}/ovn/ovn-ic-nb.ovsschema +%{_datadir}/ovn/ovn-sb.ovsschema +%{_datadir}/ovn/ovn-ic-sb.ovsschema +%{_unitdir}/ovn-northd.service +%{ovnlibdir}/firewalld/services/ovn-central-firewall-service.xml + +%files host +%{_bindir}/ovn-controller +%{_mandir}/man8/ovn-controller.8* +%{_unitdir}/ovn-controller.service +%{ovnlibdir}/firewalld/services/ovn-host-firewall-service.xml + +%files vtep +%{_bindir}/ovn-controller-vtep +%{_mandir}/man8/ovn-controller-vtep.8* +%{_unitdir}/ovn-controller-vtep.service + +%changelog +* Fri Jul 01 2022 Mark Michelson - 22.06.0-16 +- ovs: Bump submodule to newer version (#2102618) +[Gerrit: 5593044a8be0d2ce730e4890cf213ee760916889] +[Upstream: 5593044a8be0d2ce730e4890cf213ee760916889] + +* Wed Jun 29 2022 Ihar Hrachyshka - 22.06.0-15 +- tests: add multi-chassis keyword to relevant test cases +[Gerrit: 4bdade3593ae3c6604822716d22ab04b0af962da] +[Upstream: 4bdade3593ae3c6604822716d22ab04b0af962da] + +* Wed Jun 29 2022 Lorenzo Bianconi - 22.06.0-14 +- northd: add condition for stateless nat drop flow in S_ROUTER_IN_GW_REDIRECT pipeline (#2094980) +[Gerrit: 9885154fc41005dbb8fbbdca9e3a38d892870f53] +[Upstream: 9885154fc41005dbb8fbbdca9e3a38d892870f53] + +* Wed Jun 29 2022 Ales Musil - 22.06.0-13 +- northd.c: Add flow to skip put_nd action if ip6.src or nd.sll is 0 +[Gerrit: c5596102cb84e22086d7807b31cbe5c9e893ac38] +[Upstream: 0a4bc2075f7df1bb38338cde1973c931aa5e1942] + +* Wed Jun 29 2022 Terry Wilson - 22.06.0-12 +- Allow arbitrary args to be passed to called binary +[Gerrit: 849106f6ee75d7b1ff990763325d41d45c843a64] +[Upstream: 849106f6ee75d7b1ff990763325d41d45c843a64] + +* Mon Jun 27 2022 Ihar Hrachyshka - 22.06.0-11 +- tests: ovn-nbctl dump-flows -> ovn-sbctl dump-flows +[Gerrit: 656a91b6b5cd9d9e48b8e938fcffb81ead2d9fda] +[Upstream: 656a91b6b5cd9d9e48b8e938fcffb81ead2d9fda] + +* Mon Jun 27 2022 Ihar Hrachyshka - 22.06.0-10 +- Fix memleak in ovn-nbctl when args can't be parsed +[Gerrit: 70b360325c13f399835b1f5c7ac0c0acd4832773] +[Upstream: 70b360325c13f399835b1f5c7ac0c0acd4832773] + +* Mon Jun 20 2022 Ihar Hrachyshka - 22.06.0-9 +- Implement RARP activation strategy for ports +[Gerrit: c75ddaf804cc8ea8499706430b438ae53f2f1224] +[Upstream: ee20c48c2f5ce9d512adfcbea3ee300f8bb09625] + +* Tue Jun 14 2022 Ihar Hrachyshka - 22.06.0-8 +- Fix pidfile_is_running when $cmd is not passed +[Gerrit: 44e047d6f1be5ae4f564e82a928cf1f08f1908ef] +[Upstream: 6e57adfe5a35fc36ef290c6e9ae7e616f73cd3d2] + +* Thu Jun 09 2022 Ihar Hrachyshka - 22.06.0-7 +- Lock pinctrl_mutex for pinctrl_wait +[Gerrit: 6e36ad7a52ec4e6443ccb3185bda6421cdf6747e] +[Upstream: 6e36ad7a52ec4e6443ccb3185bda6421cdf6747e] + +* Thu Jun 09 2022 Terry Wilson - 22.06.0-6 +- Ensure pid belongs to ovsdb-server in ovn-ctl +[Gerrit: d0847f56913245c19a33e087f730c084ca674c83] +[Upstream: d0847f56913245c19a33e087f730c084ca674c83] + +* Thu Jun 09 2022 Terry Wilson - 22.06.0-5 +- Handle re-used pids in pidfile_is_running +[Gerrit: 98e7d4b3675b237c770763377382075ac08c64ba] +[Upstream: 98e7d4b3675b237c770763377382075ac08c64ba] + +* Fri Jun 03 2022 Mark Michelson - 22.06.0-4 +- Prepare for 22.06.1. +[Gerrit: 437dc3a01266d7f128bba532c674c5827af1bd6f] +[Upstream: 437dc3a01266d7f128bba532c674c5827af1bd6f] +