diff --git a/.ci/ovn-kubernetes/Dockerfile b/.ci/ovn-kubernetes/Dockerfile
index eda8b6d02..554b5551b 100644
--- a/.ci/ovn-kubernetes/Dockerfile
+++ b/.ci/ovn-kubernetes/Dockerfile
@@ -1,4 +1,4 @@
-ARG OVNKUBE_COMMIT=master
+ARG OVNKUBE_COMMIT
ARG GO_VERSION
FROM fedora:37 AS ovnbuilder
diff --git a/.github/workflows/ovn-kubernetes.yml b/.github/workflows/ovn-kubernetes.yml
index 0f2b30497..f7dfd1c39 100644
--- a/.github/workflows/ovn-kubernetes.yml
+++ b/.github/workflows/ovn-kubernetes.yml
@@ -13,7 +13,7 @@ concurrency:
cancel-in-progress: true
env:
- OVNKUBE_COMMIT: "master"
+ OVNKUBE_COMMIT: "release-1.0"
KIND_CLUSTER_NAME: ovn
KIND_INSTALL_INGRESS: true
KIND_ALLOW_SYSTEM_WRITES: true
@@ -41,6 +41,7 @@ jobs:
with:
path: src/github.com/ovn-org/ovn-kubernetes
repository: ovn-org/ovn-kubernetes
+ ref: ${{ env.OVNKUBE_COMMIT }}
- name: Prepare
run: |
@@ -108,6 +109,7 @@ jobs:
with:
path: src/github.com/ovn-org/ovn-kubernetes
repository: ovn-org/ovn-kubernetes
+ ref: ${{ env.OVNKUBE_COMMIT }}
- name: Prepare
run: |
diff --git a/AUTHORS.rst b/AUTHORS.rst
index 65c8761f4..351523fd1 100644
--- a/AUTHORS.rst
+++ b/AUTHORS.rst
@@ -448,6 +448,7 @@ xushengping shengping.xu@huawei.com
yinpeijun yinpeijun@huawei.com
zangchuanqiang zangchuanqiang@huawei.com
zhang yanxian zhangyanxian@pmlabs.com.cn
+zhangqiang45 zhangqiang45@lenovo.com
zhaojingjing zhao.jingjing1@zte.com.cn
zhongbaisong zhongbaisong@huawei.com
zhaozhanxu zhaozhanxu@163.com
diff --git a/NEWS b/NEWS
index 5c80fa482..9265e0836 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,10 @@
+OVN v23.09.6 - xx xxx xxxx
+--------------------------
+
+OVN v23.09.5 - 16 Aug 2024
+--------------------------
+ - Bug fixes
+
OVN v23.09.4 - 09 May 2024
--------------------------
- Bug fixes
diff --git a/configure.ac b/configure.ac
index c71ade236..055d339e3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -13,7 +13,7 @@
# limitations under the License.
AC_PREREQ(2.63)
-AC_INIT(ovn, 23.09.4, bugs@openvswitch.org)
+AC_INIT(ovn, 23.09.6, bugs@openvswitch.org)
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])
diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
index e8e7ac6bd..66b656044 100644
--- a/controller/ovn-controller.c
+++ b/controller/ovn-controller.c
@@ -750,7 +750,7 @@ update_ct_zones(const struct sset *local_lports,
const char *user;
struct sset all_users = SSET_INITIALIZER(&all_users);
struct simap req_snat_zones = SIMAP_INITIALIZER(&req_snat_zones);
- unsigned long unreq_snat_zones_map[BITMAP_N_LONGS(MAX_CT_ZONES)];
+ unsigned long *unreq_snat_zones_map = bitmap_allocate(MAX_CT_ZONES);
struct simap unreq_snat_zones = SIMAP_INITIALIZER(&unreq_snat_zones);
const char *local_lport;
@@ -861,6 +861,7 @@ update_ct_zones(const struct sset *local_lports,
simap_destroy(&req_snat_zones);
simap_destroy(&unreq_snat_zones);
sset_destroy(&all_users);
+ bitmap_free(unreq_snat_zones_map);
}
static void
@@ -1146,6 +1147,7 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl)
ovsdb_idl_add_table(ovs_idl, &ovsrec_table_queue);
ovsdb_idl_add_column(ovs_idl, &ovsrec_queue_col_other_config);
ovsdb_idl_add_column(ovs_idl, &ovsrec_queue_col_external_ids);
+ ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_link_state);
chassis_register_ovs_idl(ovs_idl);
encaps_register_ovs_idl(ovs_idl);
@@ -2990,7 +2992,7 @@ lb_data_local_lb_add(struct ed_type_lb_data *lb_data,
static void
lb_data_local_lb_remove(struct ed_type_lb_data *lb_data,
- struct ovn_controller_lb *lb, bool tracked)
+ struct ovn_controller_lb *lb)
{
const struct uuid *uuid = &lb->slb->header_.uuid;
@@ -2999,12 +3001,8 @@ lb_data_local_lb_remove(struct ed_type_lb_data *lb_data,
lb_data_removed_five_tuples_add(lb_data, lb);
- if (tracked) {
- hmap_insert(&lb_data->old_lbs, &lb->hmap_node, uuid_hash(uuid));
- uuidset_insert(&lb_data->deleted, uuid);
- } else {
- ovn_controller_lb_destroy(lb);
- }
+ hmap_insert(&lb_data->old_lbs, &lb->hmap_node, uuid_hash(uuid));
+ uuidset_insert(&lb_data->deleted, uuid);
}
static bool
@@ -3029,7 +3027,7 @@ lb_data_handle_changed_ref(enum objdep_type type, const char *res_name,
continue;
}
- lb_data_local_lb_remove(lb_data, lb, true);
+ lb_data_local_lb_remove(lb_data, lb);
const struct sbrec_load_balancer *sbrec_lb =
sbrec_load_balancer_table_get_for_uuid(ctx_in->lb_table, uuid);
@@ -3075,9 +3073,13 @@ en_lb_data_run(struct engine_node *node, void *data)
const struct sbrec_load_balancer_table *lb_table =
EN_OVSDB_GET(engine_get_input("SB_load_balancer", node));
+ objdep_mgr_clear(&lb_data->deps_mgr);
+
struct ovn_controller_lb *lb;
HMAP_FOR_EACH_SAFE (lb, hmap_node, &lb_data->local_lbs) {
- lb_data_local_lb_remove(lb_data, lb, false);
+ hmap_remove(&lb_data->local_lbs, &lb->hmap_node);
+ lb_data_removed_five_tuples_add(lb_data, lb);
+ ovn_controller_lb_destroy(lb);
}
const struct sbrec_load_balancer *sbrec_lb;
@@ -3115,7 +3117,7 @@ lb_data_sb_load_balancer_handler(struct engine_node *node, void *data)
continue;
}
- lb_data_local_lb_remove(lb_data, lb, true);
+ lb_data_local_lb_remove(lb_data, lb);
}
if (sbrec_load_balancer_is_deleted(sbrec_lb) ||
@@ -4054,6 +4056,8 @@ en_lflow_output_run(struct engine_node *node, void *data)
EN_OVSDB_GET(engine_get_input("OVS_bridge", node));
const struct ovsrec_bridge *br_int = get_br_int(bridge_table, ovs_table);
const char *chassis_id = get_ovs_chassis_id(ovs_table);
+ const struct ovsrec_flow_sample_collector_set_table *flow_collector_table =
+ EN_OVSDB_GET(engine_get_input("OVS_flow_sample_collector_set", node));
struct ovsdb_idl_index *sbrec_chassis_by_name =
engine_ovsdb_node_get_index(
@@ -4067,6 +4071,17 @@ en_lflow_output_run(struct engine_node *node, void *data)
ovs_assert(br_int && chassis);
+ const struct ovsrec_flow_sample_collector_set *set;
+ OVSREC_FLOW_SAMPLE_COLLECTOR_SET_TABLE_FOR_EACH (set,
+ flow_collector_table) {
+ if (set->bridge == br_int) {
+ struct ed_type_lflow_output *lfo = data;
+ flow_collector_ids_clear(&lfo->collector_ids);
+ flow_collector_ids_init_from_table(&lfo->collector_ids,
+ flow_collector_table);
+ }
+ }
+
struct ed_type_lflow_output *fo = data;
struct ovn_desired_flow_table *lflow_table = &fo->flow_table;
struct ovn_extend_table *group_table = &fo->group_table;
@@ -5719,17 +5734,14 @@ main(int argc, char *argv[])
br_int ? br_int->name : NULL)) {
VLOG_INFO("OVS feature set changed, force recompute.");
engine_set_force_recompute(true);
- if (ovs_feature_set_discovered()) {
- uint32_t max_groups = ovs_feature_max_select_groups_get();
- uint32_t max_meters = ovs_feature_max_meters_get();
- struct ed_type_lflow_output *lflow_out_data =
- engine_get_internal_data(&en_lflow_output);
-
- ovn_extend_table_reinit(&lflow_out_data->group_table,
- max_groups);
- ovn_extend_table_reinit(&lflow_out_data->meter_table,
- max_meters);
- }
+
+ struct ed_type_lflow_output *lflow_out_data =
+ engine_get_internal_data(&en_lflow_output);
+
+ ovn_extend_table_reinit(&lflow_out_data->group_table,
+ ovs_feature_max_select_groups_get());
+ ovn_extend_table_reinit(&lflow_out_data->meter_table,
+ ovs_feature_max_meters_get());
}
if (br_int) {
diff --git a/controller/pinctrl.c b/controller/pinctrl.c
index 98821d275..9e80556ef 100644
--- a/controller/pinctrl.c
+++ b/controller/pinctrl.c
@@ -655,8 +655,6 @@ pinctrl_forward_pkt(struct rconn *swconn, int64_t dp_key,
put_load(dp_key, MFF_LOG_DATAPATH, 0, 64, &ofpacts);
put_load(in_port_key, MFF_LOG_INPORT, 0, 32, &ofpacts);
put_load(out_port_key, MFF_LOG_OUTPORT, 0, 32, &ofpacts);
- /* Avoid re-injecting packet already consumed. */
- put_load(1, MFF_LOG_FLAGS, MLF_IGMP_IGMP_SNOOP_INJECT_BIT, 1, &ofpacts);
struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts);
resubmit->in_port = OFPP_CONTROLLER;
@@ -5756,6 +5754,10 @@ get_localnet_vifs_l3gwports(
if (!pb || pb->chassis != chassis) {
continue;
}
+ if (!iface_rec->link_state ||
+ strcmp(iface_rec->link_state, "up")) {
+ continue;
+ }
struct local_datapath *ld
= get_local_datapath(local_datapaths,
pb->datapath->tunnel_key);
@@ -6687,6 +6689,9 @@ struct svc_monitor {
long long int timestamp;
bool is_ip6;
+ struct eth_addr src_mac;
+ struct in6_addr src_ip;
+
long long int wait_time;
long long int next_send_time;
@@ -6881,6 +6886,9 @@ sync_svc_monitors(struct ovsdb_idl_txn *ovnsb_idl_txn,
svc_mon->n_success = 0;
svc_mon->n_failures = 0;
+ eth_addr_from_string(sb_svc_mon->src_mac, &svc_mon->src_mac);
+ ip46_parse(sb_svc_mon->src_ip, &svc_mon->src_ip);
+
hmap_insert(&svc_monitors_map, &svc_mon->hmap_node, hash);
ovs_list_push_back(&svc_monitors, &svc_mon->list_node);
changed = true;
@@ -7639,19 +7647,14 @@ svc_monitor_send_tcp_health_check__(struct rconn *swconn,
struct dp_packet packet;
dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
- struct eth_addr eth_src;
- eth_addr_from_string(svc_mon->sb_svc_mon->src_mac, ð_src);
if (svc_mon->is_ip6) {
- struct in6_addr ip6_src;
- ipv6_parse(svc_mon->sb_svc_mon->src_ip, &ip6_src);
- pinctrl_compose_ipv6(&packet, eth_src, svc_mon->ea,
- &ip6_src, &svc_mon->ip, IPPROTO_TCP,
+ pinctrl_compose_ipv6(&packet, svc_mon->src_mac, svc_mon->ea,
+ &svc_mon->src_ip, &svc_mon->ip, IPPROTO_TCP,
63, TCP_HEADER_LEN);
} else {
- ovs_be32 ip4_src;
- ip_parse(svc_mon->sb_svc_mon->src_ip, &ip4_src);
- pinctrl_compose_ipv4(&packet, eth_src, svc_mon->ea,
- ip4_src, in6_addr_get_mapped_ipv4(&svc_mon->ip),
+ pinctrl_compose_ipv4(&packet, svc_mon->src_mac, svc_mon->ea,
+ in6_addr_get_mapped_ipv4(&svc_mon->src_ip),
+ in6_addr_get_mapped_ipv4(&svc_mon->ip),
IPPROTO_TCP, 63, TCP_HEADER_LEN);
}
@@ -7707,24 +7710,18 @@ svc_monitor_send_udp_health_check(struct rconn *swconn,
struct svc_monitor *svc_mon,
ovs_be16 udp_src)
{
- struct eth_addr eth_src;
- eth_addr_from_string(svc_mon->sb_svc_mon->src_mac, ð_src);
-
uint64_t packet_stub[128 / 8];
struct dp_packet packet;
dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
if (svc_mon->is_ip6) {
- struct in6_addr ip6_src;
- ipv6_parse(svc_mon->sb_svc_mon->src_ip, &ip6_src);
- pinctrl_compose_ipv6(&packet, eth_src, svc_mon->ea,
- &ip6_src, &svc_mon->ip, IPPROTO_UDP,
+ pinctrl_compose_ipv6(&packet, svc_mon->src_mac, svc_mon->ea,
+ &svc_mon->src_ip, &svc_mon->ip, IPPROTO_UDP,
63, UDP_HEADER_LEN + 8);
} else {
- ovs_be32 ip4_src;
- ip_parse(svc_mon->sb_svc_mon->src_ip, &ip4_src);
- pinctrl_compose_ipv4(&packet, eth_src, svc_mon->ea,
- ip4_src, in6_addr_get_mapped_ipv4(&svc_mon->ip),
+ pinctrl_compose_ipv4(&packet, svc_mon->src_mac, svc_mon->ea,
+ in6_addr_get_mapped_ipv4(&svc_mon->src_ip),
+ in6_addr_get_mapped_ipv4(&svc_mon->ip),
IPPROTO_UDP, 63, UDP_HEADER_LEN + 8);
}
diff --git a/debian/changelog b/debian/changelog
index e06f13536..244bb95ce 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,15 @@
+ovn (23.09.6-1) unstable; urgency=low
+ [ OVN team ]
+ * New upstream version
+
+ -- OVN team <dev@openvswitch.org> Fri, 16 Aug 2024 13:51:01 -0400
+
+OVN (23.09.5-1) unstable; urgency=low
+ [ OVN team ]
+ * New upstream version
+
+ -- OVN team <dev@openvswitch.org> Fri, 16 Aug 2024 13:51:01 -0400
+
OVN (23.09.4-1) unstable; urgency=low
[ OVN team ]
* New upstream version
diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
index 7446accad..cf0558c0e 100644
--- a/ic/ovn-ic.c
+++ b/ic/ovn-ic.c
@@ -2324,7 +2324,7 @@ ovn_ic_resume(struct unixctl_conn *conn, int argc OVS_UNUSED,
{
struct ic_state *state = state_;
state->paused = false;
-
+ poll_immediate_wake();
unixctl_command_reply(conn, NULL);
}
diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h
index e3236fa24..f07c4c42e 100644
--- a/include/ovn/logical-fields.h
+++ b/include/ovn/logical-fields.h
@@ -80,7 +80,6 @@ enum mff_log_flags_bits {
MLF_LOCALNET_BIT = 15,
MLF_RX_FROM_TUNNEL_BIT = 16,
MLF_ICMP_SNAT_BIT = 17,
- MLF_IGMP_IGMP_SNOOP_INJECT_BIT = 18,
};
/* MFF_LOG_FLAGS_REG flag assignments */
@@ -136,8 +135,6 @@ enum mff_log_flags {
MLF_RX_FROM_TUNNEL = (1 << MLF_RX_FROM_TUNNEL_BIT),
MLF_ICMP_SNAT = (1 << MLF_ICMP_SNAT_BIT),
-
- MLF_IGMP_IGMP_SNOOP = (1 << MLF_IGMP_IGMP_SNOOP_INJECT_BIT),
};
/* OVN logical fields
diff --git a/lib/actions.c b/lib/actions.c
index 2b3fc915c..5c10edf53 100644
--- a/lib/actions.c
+++ b/lib/actions.c
@@ -875,6 +875,9 @@ encode_CT_COMMIT_V2(const struct ovnact_nest *on,
const struct ovnact_encode_params *ep OVS_UNUSED,
struct ofpbuf *ofpacts)
{
+ size_t ct_offset = ofpacts->size;
+ ofpbuf_pull(ofpacts, ct_offset);
+
struct ofpact_conntrack *ct = ofpact_put_CT(ofpacts);
ct->flags = NX_CT_F_COMMIT;
ct->recirc_table = NX_CT_RECIRC_NONE;
@@ -906,6 +909,7 @@ encode_CT_COMMIT_V2(const struct ovnact_nest *on,
ofpacts->header = ofpbuf_push_uninit(ofpacts, set_field_offset);
ct = ofpacts->header;
ofpact_finish(ofpacts, &ct->ofpact);
+ ofpbuf_push_uninit(ofpacts, ct_offset);
}
static void
diff --git a/lib/logical-fields.c b/lib/logical-fields.c
index 68892dba5..d84528ef5 100644
--- a/lib/logical-fields.c
+++ b/lib/logical-fields.c
@@ -139,10 +139,6 @@ ovn_init_symtab(struct shash *symtab)
flags_str);
snprintf(flags_str, sizeof flags_str, "flags[%d]", MLF_RX_FROM_TUNNEL_BIT);
expr_symtab_add_subfield(symtab, "flags.tunnel_rx", NULL, flags_str);
- snprintf(flags_str, sizeof flags_str, "flags[%d]",
- MLF_IGMP_IGMP_SNOOP_INJECT_BIT);
- expr_symtab_add_subfield(symtab, "flags.igmp_loopback", NULL,
- flags_str);
/* Connection tracking state. */
expr_symtab_add_field_scoped(symtab, "ct_mark", MFF_CT_MARK, NULL, false,
@@ -247,7 +243,7 @@ ovn_init_symtab(struct shash *symtab)
expr_symtab_add_field(symtab, "icmp4.code", MFF_ICMPV4_CODE, "icmp4",
false);
- expr_symtab_add_predicate(symtab, "igmp", "ip4 && ip.proto == 2");
+ expr_symtab_add_predicate(symtab, "igmp", "ip4.mcast && ip.proto == 2");
expr_symtab_add_field(symtab, "ip6.src", MFF_IPV6_SRC, "ip6", false);
expr_symtab_add_field(symtab, "ip6.dst", MFF_IPV6_DST, "ip6", false);
@@ -307,6 +303,9 @@ ovn_init_symtab(struct shash *symtab)
"icmp6.type == {135, 136} && icmp6.code == 0 && ip.ttl == 255");
expr_symtab_add_predicate(symtab, "nd_ns",
"icmp6.type == 135 && icmp6.code == 0 && ip.ttl == 255");
+ expr_symtab_add_predicate(symtab, "nd_ns_mcast",
+ "ip6.mcast && icmp6.type == 135 && icmp6.code == 0 && "
+ "ip.ttl == 255");
expr_symtab_add_predicate(symtab, "nd_na",
"icmp6.type == 136 && icmp6.code == 0 && ip.ttl == 255");
expr_symtab_add_predicate(symtab, "nd_rs",
@@ -321,11 +320,12 @@ ovn_init_symtab(struct shash *symtab)
* (RFC 2710 and RFC 3810).
*/
expr_symtab_add_predicate(symtab, "mldv1",
- "ip6.src == fe80::/10 && "
+ "eth.mcastv6 && ip6.src == fe80::/10 && "
"icmp6.type == {130, 131, 132}");
/* MLDv2 packets are sent to ff02::16 (RFC 3810, 5.2.14) */
expr_symtab_add_predicate(symtab, "mldv2",
- "ip6.dst == ff02::16 && icmp6.type == 143");
+ "eth.mcastv6 && ip6.dst == ff02::16 && "
+ "icmp6.type == 143");
expr_symtab_add_predicate(symtab, "tcp", "ip.proto == 6");
expr_symtab_add_field(symtab, "tcp.src", MFF_TCP_SRC, "tcp", false);
diff --git a/northd/northd.c b/northd/northd.c
index 32240b856..d3ff7629d 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -119,6 +119,7 @@ static bool default_acl_drop;
#define REGBIT_PORT_SEC_DROP "reg0[15]"
#define REGBIT_ACL_STATELESS "reg0[16]"
#define REGBIT_ACL_HINT_ALLOW_REL "reg0[17]"
+#define REGBIT_FROM_ROUTER_PORT "reg0[18]"
#define REG_ORIG_DIP_IPV4 "reg1"
#define REG_ORIG_DIP_IPV6 "xxreg1"
@@ -805,12 +806,6 @@ ovn_datapath_is_stale(const struct ovn_datapath *od)
return !od->nbr && !od->nbs;
}
-static inline bool
-ovn_datapath_is_transit_switch(const struct ovn_datapath *od)
-{
- return od->tunnel_key >= OVN_MIN_DP_KEY_GLOBAL;
-}
-
static struct ovn_datapath *
ovn_datapath_from_sbrec(const struct hmap *ls_datapaths,
const struct hmap *lr_datapaths,
@@ -6126,13 +6121,11 @@ ovn_igmp_group_get_ports(const struct sbrec_igmp_group *sb_igmp_group,
continue;
}
- /* If this is already a port of a router on which relay is enabled
- * and it's not a transit switch to router port, skip it for the
- * group. Traffic is flooded there anyway.
+ /* If this is already a port of a router on which relay is enabled,
+ * skip it for the group. Traffic is flooded there anyway.
*/
if (port->peer && port->peer->od &&
- port->peer->od->mcast_info.rtr.relay &&
- !ovn_datapath_is_transit_switch(port->od)) {
+ port->peer->od->mcast_info.rtr.relay) {
continue;
}
@@ -6956,6 +6949,12 @@ build_lswitch_port_sec_op(struct ovn_port *op, struct hmap *lflows,
op->od->localnet_ports[0]->key,
&op->od->localnet_ports[0]->nbsp->header_);
}
+ } else if (lsp_is_router(op->nbsp)) {
+ ds_put_format(actions, REGBIT_FROM_ROUTER_PORT" = 1; next;");
+ ovn_lflow_add_with_lport_and_hint(lflows, op->od,
+ S_SWITCH_IN_CHECK_PORT_SEC, 70,
+ ds_cstr(match), ds_cstr(actions),
+ op->key, &op->nbsp->header_);
}
}
@@ -7252,8 +7251,7 @@ build_interconn_mcast_snoop_flows(struct ovn_datapath *od,
continue;
}
/* Punt IGMP traffic to controller. */
- char *match = xasprintf("inport == %s && igmp && "
- "flags.igmp_loopback == 0", op->json_key);
+ char *match = xasprintf("inport == %s && igmp", op->json_key);
ovn_lflow_metered(lflows, od, S_SWITCH_OUT_PRE_LB, 120, match,
"clone { igmp; }; next;",
copp_meter_get(COPP_IGMP, od->nbs->copp,
@@ -7261,8 +7259,7 @@ build_interconn_mcast_snoop_flows(struct ovn_datapath *od,
free(match);
/* Punt MLD traffic to controller. */
- match = xasprintf("inport == %s && (mldv1 || mldv2) && "
- "flags.igmp_loopback == 0", op->json_key);
+ match = xasprintf("inport == %s && (mldv1 || mldv2)", op->json_key);
ovn_lflow_metered(lflows, od, S_SWITCH_OUT_PRE_LB, 120, match,
"clone { igmp; }; next;",
copp_meter_get(COPP_IGMP, od->nbs->copp,
@@ -8933,13 +8930,16 @@ build_fwd_group_lflows(struct ovn_datapath *od, struct hmap *lflows)
struct ds actions = DS_EMPTY_INITIALIZER;
struct ds group_ports = DS_EMPTY_INITIALIZER;
- for (int i = 0; i < od->nbs->n_forwarding_groups; ++i) {
+ for (size_t i = 0; i < od->nbs->n_forwarding_groups; ++i) {
const struct nbrec_forwarding_group *fwd_group = NULL;
fwd_group = od->nbs->forwarding_groups[i];
if (!fwd_group->n_child_port) {
continue;
}
+ ds_clear(&match);
+ ds_clear(&actions);
+
/* ARP responder for the forwarding group's virtual IP */
ds_put_format(&match, "arp.tpa == %s && arp.op == 1",
fwd_group->vip);
@@ -8970,9 +8970,9 @@ build_fwd_group_lflows(struct ovn_datapath *od, struct hmap *lflows)
ds_put_cstr(&group_ports, "liveness=\"true\",");
}
ds_put_cstr(&group_ports, "childports=");
- for (i = 0; i < (fwd_group->n_child_port - 1); ++i) {
+ for (size_t j = 0; j < (fwd_group->n_child_port - 1); ++j) {
ds_put_format(&group_ports, "\"%s\",",
- fwd_group->child_port[i]);
+ fwd_group->child_port[j]);
}
ds_put_format(&group_ports, "\"%s\"",
fwd_group->child_port[fwd_group->n_child_port - 1]);
@@ -9912,16 +9912,21 @@ build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op,
&op->nbsp->header_);
}
- /* For ND solicitations, we need to listen for both the
- * unicast IPv6 address and its all-nodes multicast address,
- * but always respond with the unicast IPv6 address. */
+ /* For ND solicitations:
+ * - Reply only for the all-nodes multicast address(es) of the
+ * logical port IPv6 address(es).
+ *
+ * - Do not reply for unicast ND solicitations. Let the target
+ * reply to it, so that the sender has the ability to monitor
+ * the target liveness via the unicast ND solicitations.
+ */
for (size_t j = 0; j < op->lsp_addrs[i].n_ipv6_addrs; j++) {
ds_clear(match);
- ds_put_format(match,
- "nd_ns && ip6.dst == {%s, %s} && nd.target == %s",
- op->lsp_addrs[i].ipv6_addrs[j].addr_s,
- op->lsp_addrs[i].ipv6_addrs[j].sn_addr_s,
- op->lsp_addrs[i].ipv6_addrs[j].addr_s);
+ ds_put_format(
+ match,
+ "nd_ns_mcast && ip6.dst == %s && nd.target == %s",
+ op->lsp_addrs[i].ipv6_addrs[j].sn_addr_s,
+ op->lsp_addrs[i].ipv6_addrs[j].addr_s);
ds_clear(actions);
ds_put_format(actions,
@@ -9977,7 +9982,9 @@ build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op,
if (op->proxy_arp_addrs.n_ipv4_addrs) {
/* Match rule on all proxy ARP IPs. */
ds_clear(match);
- ds_put_cstr(match, "arp.op == 1 && arp.tpa == {");
+ ds_put_cstr(match,
+ REGBIT_FROM_ROUTER_PORT" == 0 "
+ "&& arp.op == 1 && arp.tpa == {");
for (i = 0; i < op->proxy_arp_addrs.n_ipv4_addrs; i++) {
ds_put_format(match, "%s/%u,",
@@ -10027,7 +10034,8 @@ build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op,
ds_truncate(&nd_target_match, nd_target_match.length - 2);
ds_clear(match);
ds_put_format(match,
- "nd_ns "
+ REGBIT_FROM_ROUTER_PORT" == 0 "
+ "&& nd_ns "
"&& ip6.dst == { %s } "
"&& nd.target == { %s }",
ds_cstr(&ip6_dst_match),
@@ -10288,14 +10296,13 @@ build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od,
ds_put_cstr(actions, "igmp;");
/* Punt IGMP traffic to controller. */
ovn_lflow_metered(lflows, od, S_SWITCH_IN_L2_LKUP, 100,
- "flags.igmp_loopback == 0 && igmp", ds_cstr(actions),
+ "igmp", ds_cstr(actions),
copp_meter_get(COPP_IGMP, od->nbs->copp,
meter_groups));
/* Punt MLD traffic to controller. */
ovn_lflow_metered(lflows, od, S_SWITCH_IN_L2_LKUP, 100,
- "flags.igmp_loopback == 0 && (mldv1 || mldv2)",
- ds_cstr(actions),
+ "mldv1 || mldv2", ds_cstr(actions),
copp_meter_get(COPP_IGMP, od->nbs->copp,
meter_groups));
@@ -10359,16 +10366,8 @@ build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od,
}
-/* Ingress table 27: Add IP multicast flows learnt from IGMP/MLD
- * (priority 90).
- *
- * OR, for transit switches:
- *
- * Add IP multicast flows learnt from IGMP/MLD to forward traffic
- * explicitly to the ports that are part of the IGMP/MLD group,
- * and ignore MROUTER Ports.
- * (priority 90).
- */
+/* Ingress table 25: Add IP multicast flows learnt from IGMP/MLD
+ * (priority 90). */
static void
build_lswitch_ip_mcast_igmp_mld(struct ovn_igmp_group *igmp_group,
struct hmap *lflows,
@@ -10382,9 +10381,6 @@ build_lswitch_ip_mcast_igmp_mld(struct ovn_igmp_group *igmp_group,
ds_clear(match);
ds_clear(actions);
- bool transit_switch =
- ovn_datapath_is_transit_switch(igmp_group->datapath);
-
struct mcast_switch_info *mcast_sw_info =
&igmp_group->datapath->mcast_info.sw;
uint64_t table_size = mcast_sw_info->table_size;
@@ -10430,7 +10426,7 @@ build_lswitch_ip_mcast_igmp_mld(struct ovn_igmp_group *igmp_group,
}
/* Also flood traffic to all multicast routers with relay enabled. */
- if (mcast_sw_info->flood_relay && !transit_switch) {
+ if (mcast_sw_info->flood_relay) {
ds_put_cstr(actions,
"clone { "
"outport = \""MC_MROUTER_FLOOD "\"; "
@@ -17618,7 +17614,8 @@ build_static_mac_binding_table(
struct hmap *lr_ports)
{
/* Cleanup SB Static_MAC_Binding entries which do not have corresponding
- * NB Static_MAC_Binding entries. */
+ * NB Static_MAC_Binding entries, and SB Static_MAC_Binding entries for
+ * which there is not a NB Logical_Router_Port of the same name. */
const struct nbrec_static_mac_binding *nb_smb;
const struct sbrec_static_mac_binding *sb_smb;
SBREC_STATIC_MAC_BINDING_TABLE_FOR_EACH_SAFE (sb_smb,
@@ -17628,6 +17625,12 @@ build_static_mac_binding_table(
sb_smb->ip);
if (!nb_smb) {
sbrec_static_mac_binding_delete(sb_smb);
+ continue;
+ }
+
+ struct ovn_port *op = ovn_port_find(lr_ports, nb_smb->logical_port);
+ if (!op || !op->nbrp || !op->od || !op->od->sb) {
+ sbrec_static_mac_binding_delete(sb_smb);
}
}
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index 897e626b4..f36afd999 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -1983,13 +1983,13 @@ output;
</li>
<li>
- Priority-90 flows for non-transit switches that forward registered
- IP multicast traffic to their corresponding multicast group, which
- <code>ovn-northd</code> creates based on learnt
- <ref table="IGMP_Group" db="OVN_Southbound"/> entries. The flows
- also forward packets to the <code>MC_MROUTER_FLOOD</code> multicast
- group, which <code>ovn-nortdh</code> populates with all the logical
- ports that are connected to logical routers with
+ Priority-90 flows that forward registered IP multicast traffic to
+ their corresponding multicast group, which <code>ovn-northd</code>
+ creates based on learnt <ref table="IGMP_Group" db="OVN_Southbound"/>
+ entries. The flows also forward packets to the
+ <code>MC_MROUTER_FLOOD</code> multicast group, which
+ <code>ovn-nortdh</code> populates with all the logical ports that
+ are connected to logical routers with
<ref column="options" table="Logical_Router"/>:mcast_relay='true'.
</li>
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index 00ff6ea4f..22c392b67 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -1098,6 +1098,7 @@ ovn_northd_resume(struct unixctl_conn *conn, int argc OVS_UNUSED,
{
struct northd_state *state = state_;
state->paused = false;
+ poll_immediate_wake();
unixctl_command_reply(conn, NULL);
}
diff --git a/ovn-sb.xml b/ovn-sb.xml
index 94e722512..01d1a3f4d 100644
--- a/ovn-sb.xml
+++ b/ovn-sb.xml
@@ -1155,6 +1155,7 @@
<ul>
<li><code>eth.bcast</code> expands to <code>eth.dst == ff:ff:ff:ff:ff:ff</code></li>
<li><code>eth.mcast</code> expands to <code>eth.dst[40]</code></li>
+ <li><code>eth.mcastv6</code> expands to <code>eth.dst[32..47] == 0x3333</code></li>
<li><code>vlan.present</code> expands to <code>vlan.tci[12]</code></li>
<li><code>ip4</code> expands to <code>eth.type == 0x800</code></li>
<li><code>ip4.src_mcast</code> expands to
@@ -1170,8 +1171,10 @@
<li><code>ip.first_frag</code> expands to <code>ip.is_frag && !ip.later_frag</code></li>
<li><code>arp</code> expands to <code>eth.type == 0x806</code></li>
<li><code>rarp</code> expands to <code>eth.type == 0x8035</code></li>
+ <li><code>ip6.mcast</code> expands to <code>eth.mcastv6 && ip6.dst[120..127] == 0xff</code></li>
<li><code>nd</code> expands to <code>icmp6.type == {135, 136} && icmp6.code == 0 && ip.ttl == 255</code></li>
<li><code>nd_ns</code> expands to <code>icmp6.type == 135 && icmp6.code == 0 && ip.ttl == 255</code></li>
+ <li><code>nd_ns_mcast</code> expands to <code>ip6.mcast && icmp6.type == 135 && icmp6.code == 0 && ip.ttl == 255</code></li>
<li><code>nd_na</code> expands to <code>icmp6.type == 136 && icmp6.code == 0 && ip.ttl == 255</code></li>
<li><code>nd_rs</code> expands to <code>icmp6.type == 133 &&
icmp6.code == 0 && ip.ttl == 255</code></li>
diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at
index 83d13213f..678afe462 100644
--- a/tests/ovn-controller.at
+++ b/tests/ovn-controller.at
@@ -2772,3 +2772,41 @@ priority=1100,ip,reg15=0x1,metadata=0x1,nw_src=10.0.0.4 actions=load:0x1->OXM_OF
OVN_CLEANUP([hv1])
AT_CLEANUP
+
+AT_SETUP([ovn-controller - LB remove after disconnect])
+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
+check ovs-vsctl -- add-port br-int vif1 -- \
+ set interface vif1 external-ids:iface-id=lsp
+
+check ovs-vsctl set Open_vSwitch . external-ids:ovn-remote-probe-interval="5000"
+
+check ovn-nbctl ls-add ls
+check ovn-nbctl lsp-add ls lsp \
+-- lsp-set-addresses lsp "f0:00:00:00:00:01 172.16.0.10"
+
+check ovn-nbctl lb-add lb 192.168.100.100 172.16.0.10
+check ovn-nbctl ls-lb-add ls lb
+
+wait_for_ports_up
+check ovn-nbctl --wait=hv sync
+
+sleep_sb
+OVS_WAIT_UNTIL([grep -q 'OVNSB commit failed' hv1/ovn-controller.log])
+
+sleep_controller hv1
+wake_up_sb
+
+ovn-nbctl lb-del lb
+
+wake_up_controller hv1
+check ovn-nbctl --wait=hv sync
+
+OVN_CLEANUP([hv1
+/no response to inactivity probe after .* seconds, disconnecting/d])
+AT_CLEANUP
diff --git a/tests/ovn-macros.at b/tests/ovn-macros.at
index f5de46a0b..fc89b5bab 100644
--- a/tests/ovn-macros.at
+++ b/tests/ovn-macros.at
@@ -957,16 +957,18 @@ stop_ovsdb_controller_updates() {
TCP_PORT=$1
echo Stopping updates from ovn-controller to ovsdb using port $TCP_PORT
on_exit 'nft list tables | grep ovn-test && nft delete table ip ovn-test'
- nft add table ip ovn-test
- nft 'add chain ip ovn-test INPUT { type filter hook input priority 0; policy accept; }'
- nft add rule ip ovn-test INPUT tcp dport $TCP_PORT counter drop
+ # Report the test as skipped if proper nft related packages are not installed.
+ AT_SKIP_IF([! which nft])
+ AT_CHECK([nft add table ip ovn-test])
+ AT_CHECK([nft 'add chain ip ovn-test INPUT { type filter hook input priority 0; policy accept; }'])
+ AT_CHECK([nft add rule ip ovn-test INPUT tcp dport $TCP_PORT counter drop])
}
restart_ovsdb_controller_updates() {
TCP_PORT=$1
echo Restarting updates from ovn-controller to ovsdb
- nft list ruleset | grep $TCP_PORT
- nft delete table ip ovn-test
+ AT_CHECK([nft list ruleset | grep $TCP_PORT], [0], [ignore])
+ AT_CHECK([nft delete table ip ovn-test])
}
trim_zeros() {
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index 4bebb2673..22c881d6a 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -7619,6 +7619,19 @@ wait_row_count Static_MAC_Binding 1 logical_port=lr0-p0 ip=192.168.10.100 mac="0
AT_CLEANUP
])
+OVN_FOR_EACH_NORTHD_NO_HV([
+AT_SETUP([LR NB Static_MAC_Binding garbage collection])
+ovn_start
+
+check ovn-nbctl lr-add lr -- lrp-add lr lr-lrp 00:00:00:00:00:01 1.1.1.1/24
+check ovn-nbctl static-mac-binding-add lr-lrp 1.1.1.2 00:00:00:00:00:02
+wait_row_count sb:Static_MAC_Binding 1 logical_port=lr-lrp ip=1.1.1.2 mac="00\:00\:00\:00\:00\:02"
+check ovn-nbctl lr-del lr
+wait_row_count sb:Static_MAC_Binding 0
+
+AT_CLEANUP
+])
+
OVN_FOR_EACH_NORTHD_NO_HV([
AT_SETUP([LR neighbor lookup and learning flows])
ovn_start
diff --git a/tests/ovn.at b/tests/ovn.at
index ffd9f653e..a5b8f91b8 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -1304,6 +1304,9 @@ ct_commit { ct_label=0x181716151413121110090807060504030201; };
141-bit constant is not compatible with 128-bit field ct_label.
ct_commit { ip4.dst = 192.168.0.1; };
Field ip4.dst is not modifiable.
+reg8[17] = 1; ct_commit { ct_mark.blocked = 1; };
+ encodes as set_field:0x2000000000000/0x2000000000000->xreg4,ct(commit,zone=NXM_NX_REG13[0..15],exec(set_field:0x1/0x1->ct_mark))
+ has prereqs ip
# Legact ct_commit_v1 action.
ct_commit();
@@ -5767,13 +5770,24 @@ for i in 1 2 3; do
# Test ICMPv6 MLD reports (v1 and v2) and NS for DAD
sip=00000000000000000000000000000000
- test_icmpv6 ${i}3 f00000000${i}${i}3 f00000000021 $sip ff020000000000000000000000160000 83 21
- test_icmpv6 ${i}3 f00000000${i}${i}3 f00000000021 $sip ff020000000000000000000000160000 8f 21
- test_icmpv6 ${i}3 f00000000${i}${i}3 f00000000021 $sip ff0200000000000000ea2aeafffe2800 87 21
+ # Multicast traffic is delivered to all ports, except for the source.
+ out_ports=
+ for j in 1 2 3; do
+ for k in 1 2 3; do
+ if test "${j}${k}" -eq "${i}3"; then
+ continue
+ else
+ out_ports="$out_ports ${j}${k}"
+ fi
+ done
+ done
+ test_icmpv6 ${i}3 f00000000${i}${i}3 333300160000 $sip ff020000000000000000000000160000 83 ${out_ports}
+ test_icmpv6 ${i}3 f00000000${i}${i}3 333300160000 $sip ff020000000000000000000000160000 8f ${out_ports}
+ test_icmpv6 ${i}3 f00000000${i}${i}3 3333fffe2800 $sip ff0200000000000000ea2aeafffe2800 87 ${out_ports}
# Traffic to non-multicast traffic should be dropped
test_icmpv6 ${i}3 f00000000${i}${i}3 f00000000021 $sip $tip 83
# Traffic of other ICMPv6 types should be dropped
- test_icmpv6 ${i}3 f00000000${i}${i}3 f00000000021 $sip ff020000000000000000000000160000 80
+ test_icmpv6 ${i}3 f00000000${i}${i}3 333300160000 $sip ff020000000000000000000000160000 80
# should be dropped
sip=ae80000000000000ea2aeafffe2800aa
@@ -8428,7 +8442,7 @@ done
# Complete Neighbor Solicitation packet and Neighbor Advertisement packet
# vif1 -> NS -> vif2. vif1 <- NA <- ovn-controller.
# vif2 will not receive NS packet, since ovn-controller will reply for it.
-ns_packet=3333ffa1f9aefa163e94059886dd6000000000203afffd81ce49a9480000f8163efffe940598fd81ce49a9480000f8163efffea1f9ae8700e01160000000fd81ce49a9480000f8163efffea1f9ae0101fa163e940598
+ns_packet=3333ffa1f9aefa163e94059886dd6000000000203afffd81ce49a9480000f8163efffe940598ff0200000000000000000001ffa1f9ae8700e01160000000fd81ce49a9480000f8163efffea1f9ae0101fa163e940598
na_packet=fa163e940598fa163ea1f9ae86dd6000000000203afffd81ce49a9480000f8163efffea1f9aefd81ce49a9480000f8163efffe9405988800e9ed60000000fd81ce49a9480000f8163efffea1f9ae0201fa163ea1f9ae
as hv1 ovs-appctl netdev-dummy/receive vif1 $ns_packet
@@ -14131,7 +14145,7 @@ test_ns_na() {
local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5
packet=$(fmt_pkt "
- Ether(dst='ff:ff:ff:ff:ff:ff', src='${src_mac}') /
+ Ether(dst='33:33:ff:ff:ff:ff', src='${src_mac}') /
IPv6(src='${src_ip}', dst='ff02::1:ff00:2') /
ICMPv6ND_NS(tgt='${dst_ip}')
")
@@ -14171,8 +14185,8 @@ test_mldv2() {
local inport=$1 outport=$2 src_mac=$3 src_ip=$4
packet=$(fmt_pkt "
- Ether(dst='ff:ff:ff:ff:ff:ff', src='${src_mac}') /
- IPv6(src='${src_ip}', dst='ff02::2') /
+ Ether(dst='33:33:00:00:00:01', src='${src_mac}') /
+ IPv6(src='${src_ip}', dst='ff02::1') /
ICMPv6MLQuery2()
")
as hv1 ovs-appctl netdev-dummy/receive vif${inport} $packet
@@ -26674,20 +26688,10 @@ wait_row_count IGMP_Group 2 address=239.0.1.68
wait_row_count IGMP_Group 2 address='"ff0a:dead:beef::1"'
check ovn-nbctl --wait=hv sync
-#Validate that Multicast Group contains all registered ports for
-# specific igmp group.
-ts_dp=$(fetch_column datapath_binding _uuid external_ids:name=ts)
-ports=$(fetch_column multicast_group ports name="239.0.1.68" datapath=$ts_dp)
-check test X2 = X$(echo $ports | wc -w)
-
-
ovn_as az2
wait_row_count IGMP_Group 2 address=239.0.1.68
wait_row_count IGMP_Group 2 address='"ff0a:dead:beef::1"'
check ovn-nbctl --wait=hv sync
-ts_dp=$(fetch_column datapath_binding _uuid external_ids:name=ts)
-ports=$(fetch_column multicast_group ports name="239.0.1.68" datapath=$ts_dp)
-check test X2 = X$(echo $ports | wc -w)
# Send an IP multicast packet from LSP2, it should be forwarded
# to lsp1 and lsp3.
@@ -27428,7 +27432,14 @@ check ovs-vsctl add-port br-int vif3 -- set Interface vif3 external-ids:iface-id
# Add a forwarding group on ls2 with lsp21 and lsp22 as child ports
# virtual IP - 172.16.1.11, virtual MAC - 00:11:de:ad:be:ef
check ovn-nbctl --wait=hv fwd-group-add fwd_grp1 ls2 172.16.1.11 00:11:de:ad:be:ef lsp21 lsp22
+check ovn-nbctl --wait=hv fwd-group-add fwd_grp2 ls2 172.16.2.11 00:22:de:ad:be:ef lsp21 lsp22
+# Check logical flow
+AT_CAPTURE_FILE([sbflows])
+ovn-sbctl dump-flows > sbflows
+AT_CHECK([grep ls_in_l2_lkup sbflows | grep fwd_group | wc -l], [0], [2
+])
+check ovn-nbctl --wait=hv fwd-group-del fwd_grp2
# Check logical flow
AT_CAPTURE_FILE([sbflows])
ovn-sbctl dump-flows > sbflows
@@ -32805,7 +32816,7 @@ AT_CHECK([ovn-sbctl dump-flows |
grep ls_in_arp_rsp |
grep "${arp_proxy_ls1[[1]]}" |
sed 's/table=../table=??/'], [0], [dnl
- table=??(ls_in_arp_rsp ), priority=30 , match=(arp.op == 1 && dnl
+ table=??(ls_in_arp_rsp ), priority=30 , match=(reg0[[18]] == 0 && arp.op == 1 && dnl
arp.tpa == {169.254.238.0/24,169.254.239.2/32}), dnl
action=(eth.dst = eth.src; eth.src = 00:00:00:01:02:f1; arp.op = 2; dnl
/* ARP reply */ arp.tha = arp.sha; arp.sha = 00:00:00:01:02:f1; dnl
@@ -32818,7 +32829,7 @@ AT_CHECK([ovn-sbctl dump-flows |
grep "${arp_proxy_ls1[[3]]}" |
sed 's/table=../table=??/'], [0], [dnl
table=??(ls_in_arp_rsp ), priority=30 , dnl
-match=(nd_ns && ip6.dst == { fd7b:6b4d:7b25:d22d::/64, ff02::1:ff00:0/64, dnl
+match=(reg0[[18]] == 0 && nd_ns && ip6.dst == { fd7b:6b4d:7b25:d22d::/64, ff02::1:ff00:0/64, dnl
fd7b:6b4d:7b25:d22f::1/128, ff02::1:ff00:1/128 } && dnl
nd.target == { fd7b:6b4d:7b25:d22d::/64, fd7b:6b4d:7b25:d22f::1/128 }), dnl
action=(nd_na_router { eth.src = 00:00:00:01:02:f1; ip6.src = nd.target; dnl
@@ -32832,7 +32843,7 @@ AT_CHECK([ovn-sbctl dump-flows |
grep "${arp_proxy_ls2[[2]]}" |
sed 's/table=../table=??/'], [0], [dnl
table=??(ls_in_arp_rsp ), priority=30 , dnl
-match=(arp.op == 1 && arp.tpa == {169.254.236.0/24,169.254.237.2/32}), dnl
+match=(reg0[[18]] == 0 && arp.op == 1 && arp.tpa == {169.254.236.0/24,169.254.237.2/32}), dnl
action=(eth.dst = eth.src; eth.src = 00:00:00:02:02:f1; arp.op = 2; dnl
/* ARP reply */ arp.tha = arp.sha; arp.sha = 00:00:00:02:02:f1; dnl
arp.tpa <-> arp.spa; outport = inport; flags.loopback = 1; output;)
@@ -32844,7 +32855,7 @@ AT_CHECK([ovn-sbctl dump-flows |
grep "${arp_proxy_ls2[[4]]}" |
sed 's/table=../table=??/'], [0], [dnl
table=??(ls_in_arp_rsp ), priority=30 , dnl
-match=(nd_ns && ip6.dst == { fd7b:6b4d:7b25:d22b::/64, ff02::1:ff00:0/64, dnl
+match=(reg0[[18]] == 0 && nd_ns && ip6.dst == { fd7b:6b4d:7b25:d22b::/64, ff02::1:ff00:0/64, dnl
fd7b:6b4d:7b25:d22c::1/128, ff02::1:ff00:1/128 } && dnl
nd.target == { fd7b:6b4d:7b25:d22b::/64, fd7b:6b4d:7b25:d22c::1/128 }), dnl
action=(nd_na_router { eth.src = 00:00:00:02:02:f1; ip6.src = nd.target; dnl
@@ -35202,7 +35213,10 @@ check_default_flows() {
# Check that every drop flow gets sampled.
check_sample_drops() {
-
+ hv=hv$1
+ remote_hv=hv$((${1}%2 + 1))
+ race_condition=$2
+ ovs-vsctl destroy Flow_Sample_Collector_Set 123
check ovn-nbctl -- remove NB_Global . options debug_drop_collector_set \
-- remove NB_Global . options debug_drop_domain_id
check ovn-nbctl --wait=hv sync
@@ -35212,14 +35226,52 @@ check_sample_drops() {
# Take match part of flows that contain "drop".
drop_matches="$(grep 'drop' oflows_nosample | grep -oP 'table=\d*, priority=.* ')"
+ if [[ x$race_condition = x"true" ]]; then
+ sleep_controller $hv
+ # Get ofport used by the geneve interface
+ OVS_WAIT_UNTIL([
+ ofport=$(as $hv ovs-vsctl --bare --columns ofport find Interface name=ovn-${remote_hv}-0)
+ test 1 -le $ofport
+ ])
+
+ # Add a vif while ovn-controller sleeps, and make it request the ofport used by the geneve interface.
+ # This is used to cause the geneve interface to change ofport.
+ ovs-vsctl -- add-port br-int vif3 -- set interface vif3\
+ options:tx_pcap=${hv}/vif3-tx.pcap \
+ options:rxq_pcap=${hv}/vif3-rx.pcap \
+ ofport-request=$ofport
+ OVS_WAIT_UNTIL([
+ vif_ofport=$(as $hv ovs-vsctl --bare --columns ofport find Interface name=vif3)
+ test 1 -le $vif_ofport
+ ])
+ # For the geneve interface ofport change to happen...
+ ovs-vsctl -- add-port br-int vif4 -- set interface vif4\
+ options:tx_pcap=${hv}/vif4-tx.pcap \
+ options:rxq_pcap=${hv}/vif4-rx.pcap
+ OVS_WAIT_UNTIL([
+ new_ofport=$(as $hv ovs-vsctl --bare --columns ofport find Interface name=ovn-${remote_hv}-0)
+ test $ofport -ne $new_ofport
+ ])
+ fi
+
ovs-vsctl --id=@br get Bridge br-int -- \
--id=@i create IPFIX targets=\"192.168.1.1\" -- \
create Flow_Sample_Collector_Set bridge=@br id=123 ipfix=@i
check ovn-nbctl -- set NB_Global . options:debug_drop_collector_set="123" \
-- set NB_Global . options:debug_drop_domain_id="1"
- check ovn-nbctl --wait=hv sync
+ if [[ x$race_condition = x"true" ]]; then
+ # Wait sb as ovn-controller sleeps.
+ check ovn-nbctl --wait=sb sync
+ # Wake up ovn-controller. It should most of the times receive non-vif ofport change and sb changes at the same time.
+ wake_up_controller $hv
+ # Check twice ovn-controller is running to guarantee if run a full loop.
+ OVS_WAIT_UNTIL([test x$(as $hv ovn-appctl -t ovn-controller debug/status) = "xrunning"])
+ OVS_WAIT_UNTIL([test x$(as $hv ovn-appctl -t ovn-controller debug/status) = "xrunning"])
+ else
+ check ovn-nbctl --wait=hv sync
+ fi
ovs-ofctl dump-flows --no-stats br-int > oflows_sample
AT_CAPTURE_FILE([oflows_sample])
@@ -35227,6 +35279,8 @@ check_sample_drops() {
save_IFS=$IFS
IFS=$'\n'
for flow in $drop_matches; do
+ # Restore IFS to avoid "printf %s\n: command not found" errors.
+ IFS=$save_IFS
AT_CHECK([grep "${flow}actions=.*sample.*" oflows_sample], [0], [ignore], [ignore], [echo "Flow $flow has a drop and did not get sampled"])
done
IFS=$save_IFS
@@ -35239,9 +35293,9 @@ check_drops() {
check_default_flows
as hv1
- check_sample_drops
+ check_sample_drops 1 $1
as hv2
- check_sample_drops
+ check_sample_drops 2 $1
}
# Logical network:
@@ -35309,7 +35363,8 @@ ovs-vsctl -- add-port br-int hv2-vif1 -- \
wait_for_ports_up
check ovn-nbctl --wait=hv sync
-check_debug
+check_drops
+check_drops true
# Add stateless ACL
check ovn-nbctl --wait=sb \
@@ -35317,7 +35372,7 @@ check ovn-nbctl --wait=sb \
check ovn-nbctl --wait=sb \
-- acl-add ls2 from-lport 100 'ip4' allow-stateless
-check_debug
+check_drops
check ovn-nbctl --wait=sb acl-del ls1
check ovn-nbctl --wait=sb acl-del ls2
@@ -35328,7 +35383,7 @@ check ovn-nbctl --wait=sb \
check ovn-nbctl --wait=sb \
-- acl-add ls2 from-lport 100 "udp" allow-related
-check_debug
+check_drops
check ovn-nbctl --wait=sb acl-del ls1
check ovn-nbctl --wait=sb acl-del ls2
@@ -37663,9 +37718,9 @@ AT_CHECK([ovn-sbctl --db=ssl:127.0.0.1:$TCP_PORT \
--ca-cert=$PKIDIR/testpki-cacert.pem \
--ssl-ciphers='HIGH:!aNULL:!MD5:@SECLEVEL=1' \
--ssl-protocols='TLSv1,TLSv1.1,TLSv1.2' \
- chassis-add ch vxlan 1.2.4.8], [1], [ignore],
-[ovn-sbctl: transaction error: {"details":"insert operation not allowed when database server is in read only mode","error":"not allowed"}
-])
+ chassis-add ch vxlan 1.2.4.8 2>&1 | grep 'transaction error]', [0], [dnl
+ovn-sbctl: transaction error: {"details":"insert operation not allowed when database server is in read only mode","error":"not allowed"}
+], [ignore])
OVS_APP_EXIT_AND_WAIT([ovsdb-server])
AT_CLEANUP
@@ -37840,3 +37895,170 @@ OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=0 |grep priority=1
OVN_CLEANUP([hv1])
AT_CLEANUP
])
+
+dnl This test checks that the megaflows translated by ovs-vswitchd
+dnl don't match on IPv6 source and destination addresses for
+dnl simple switching.
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([IPv6 switching - megaflow check for IPv6 src/dst matches])
+ovn_start
+
+check ovn-nbctl ls-add sw0
+
+check ovn-nbctl lsp-add sw0 vm0
+check ovn-nbctl lsp-set-addresses vm0 "f0:00:0f:01:02:03 10.0.0.3 1000::3"
+
+check ovn-nbctl lsp-add sw0 vm1
+check ovn-nbctl lsp-set-addresses vm1 "f0:00:0f:01:02:04 10.0.0.4 1000::4"
+
+check ovn-nbctl lr-add lr0
+check ovn-nbctl lrp-add lr0 lr0-sw0 fa:16:3e:00:00:01 10.0.0.1 1000::1/64
+check ovn-nbctl lsp-add sw0 sw0-lr0
+check ovn-nbctl lsp-set-type sw0-lr0 router
+check ovn-nbctl lsp-set-addresses sw0-lr0 router
+check ovn-nbctl --wait=hv lsp-set-options sw0-lr0 router-port=lr0-sw0
+
+net_add n1
+sim_add hv
+as hv
+check ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+check ovs-vsctl add-port br-int vif1 -- \
+ set Interface vif1 external-ids:iface-id=vm0 \
+ options:tx_pcap=hv/vif1-tx.pcap \
+ options:rxq_pcap=hv/vif1-rx.pcap \
+ ofport-request=1
+check ovs-vsctl add-port br-int vif2 -- \
+ set Interface vif2 external-ids:iface-id=vm1 \
+ options:tx_pcap=hv/vif2-tx.pcap \
+ options:rxq_pcap=hv/vif2-rx.pcap \
+ ofport-request=2
+
+check ovn-nbctl --wait=sb sync
+wait_for_ports_up
+
+AS_BOX([No port security, to vm1])
+packet=$(fmt_pkt "Ether(dst='f0:00:0f:01:02:04', src='f0:00:0f:01:02:03')/ \
+ IPv6(dst='1000::4', src='1000::3')/ \
+ UDP(sport=53, dport=4369)")
+
+as hv
+ovs-appctl ofproto/trace br-int in_port=1 $packet > vm0_ip6_ofproto_trace.txt
+ovs-appctl netdev-dummy/receive vif1 $packet
+
+AT_CAPTURE_FILE([vm0_ip6_ofproto_trace.txt])
+
+AT_CHECK([grep Megaflow vm0_ip6_ofproto_trace.txt | grep -e ipv6_src -e ipv6_dst -c], [1], [dnl
+0
+])
+
+dnl Make sure that the packet was received by vm1. This ensures that the
+dnl packet was delivered as expected and the megaflow didn't have any matches
+dnl on IPv6 src or dst.
+
+echo $packet >> expected-vif2
+OVN_CHECK_PACKETS([hv/vif2-tx.pcap], [expected-vif2])
+
+AS_BOX([No port security, to vm0])
+packet=$(fmt_pkt "Ether(dst='f0:00:0f:01:02:03', src='f0:00:0f:01:02:04')/ \
+ IPv6(dst='1000::3', src='1000::4')/ \
+ UDP(sport=53, dport=4369)")
+
+as hv
+ovs-appctl ofproto/trace br-int in_port=2 $packet > vm1_ip6_ofproto_trace.txt
+ovs-appctl netdev-dummy/receive vif2 $packet
+
+AT_CAPTURE_FILE([vm1_ip6_ofproto_trace.txt])
+
+AT_CHECK([grep Megaflow vm0_ip6_ofproto_trace.txt | grep -e ipv6_src -e ipv6_dst -c], [1], [dnl
+0
+])
+
+dnl Make sure that the packet was received by vm0. This ensures that the
+dnl packet was delivered as expected and the megaflow didn't have any matches
+dnl on IPv6 src or dst.
+echo $packet >> expected-vif1
+OVN_CHECK_PACKETS([hv/vif1-tx.pcap], [expected-vif1])
+
+AS_BOX([With port security, to vm1])
+dnl Add port security to vm0. The megaflow should now match on ipv6 src/dst.
+check ovn-nbctl lsp-set-port-security vm0 "f0:00:0f:01:02:03 10.0.0.3 1000::3"
+check ovn-nbctl --wait=hv sync
+
+packet=$(fmt_pkt "Ether(dst='f0:00:0f:01:02:04', src='f0:00:0f:01:02:03')/ \
+ IPv6(dst='1000::4', src='1000::3')/ \
+ UDP(sport=53, dport=4369)")
+
+as hv
+ovs-appctl ofproto/trace br-int in_port=1 $packet > vm0_ip6_ofproto_trace.txt
+ovs-appctl netdev-dummy/receive vif1 $packet
+
+AT_CAPTURE_FILE([vm0_ip6_ofproto_trace.txt])
+
+AT_CHECK([grep Megaflow vm0_ip6_ofproto_trace.txt | grep -e ipv6_src -e ipv6_dst -c], [0], [dnl
+1
+])
+
+dnl Make sure that the packet was received by vm1.
+echo $packet >> expected-vif2
+OVN_CHECK_PACKETS([hv/vif2-tx.pcap], [expected-vif2])
+
+AS_BOX([Clear port security, to vm1])
+dnl Clear port security.
+check ovn-nbctl lsp-set-port-security vm0 ""
+check ovn-nbctl --wait=hv sync
+
+as hv
+ovs-appctl ofproto/trace br-int in_port=1 $packet > vm0_ip6_ofproto_trace.txt
+ovs-appctl netdev-dummy/receive vif1 $packet
+
+AT_CAPTURE_FILE([vm0_ip6_ofproto_trace.txt])
+
+AT_CHECK([grep Megaflow vm0_ip6_ofproto_trace.txt | grep -e ipv6_src -e ipv6_dst -c], [1], [dnl
+0
+])
+
+dnl Make sure that the packet was received by vm1.
+echo $packet >> expected-vif2
+OVN_CHECK_PACKETS([hv/vif2-tx.pcap], [expected-vif2])
+
+AS_BOX([With proxy arp/nd, to vm1])
+dnl Configure proxy arp/nd on the router port. The megaflow should now match
+dnl on ipv6 src/dst.
+check ovn-nbctl --wait=hv lsp-set-options sw0-lr0 router-port=lr0-sw0 arp_proxy="2000::1/64"
+
+as hv
+ovs-appctl ofproto/trace br-int in_port=1 $packet > vm0_ip6_ofproto_trace.txt
+ovs-appctl netdev-dummy/receive vif1 $packet
+
+AT_CAPTURE_FILE([vm0_ip6_ofproto_trace.txt])
+
+AT_CHECK([grep Megaflow vm0_ip6_ofproto_trace.txt | grep -e ipv6_src -e ipv6_dst -c], [0], [dnl
+1
+])
+
+dnl Make sure that the packet was received by vm1.
+echo $packet >> expected-vif2
+OVN_CHECK_PACKETS([hv/vif2-tx.pcap], [expected-vif2])
+
+AS_BOX([With proxy arp/nd, to vm0])
+packet=$(fmt_pkt "Ether(dst='f0:00:0f:01:02:03', src='f0:00:0f:01:02:04')/ \
+ IPv6(dst='1000::3', src='1000::4')/ \
+ UDP(sport=53, dport=4369)")
+
+as hv
+ovs-appctl ofproto/trace br-int in_port=2 $packet > vm1_ip6_ofproto_trace.txt
+ovs-appctl netdev-dummy/receive vif2 $packet
+
+AT_CAPTURE_FILE([vm1_ip6_ofproto_trace.txt])
+
+AT_CHECK([grep Megaflow vm0_ip6_ofproto_trace.txt | grep -e ipv6_src -e ipv6_dst -c], [0], [dnl
+1
+])
+
+dnl Make sure that the packet was received by vm0.
+echo $packet >> expected-vif1
+OVN_CHECK_PACKETS([hv/vif1-tx.pcap], [expected-vif1])
+
+AT_CLEANUP
+])
diff --git a/tests/system-ovn.at b/tests/system-ovn.at
index 463075ac0..45e9ac94f 100644
--- a/tests/system-ovn.at
+++ b/tests/system-ovn.at
@@ -10628,7 +10628,7 @@ check ovn-nbctl ls-add bar
# Connect foo to R1
check ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 192.168.1.1/24
check ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
- type=router options:arp_proxy="0a:58:a9:fe:01:01 169.254.239.254 169.254.239.2 169.254.238.0/24 192.168.1.100" options:router-port=foo addresses='"router"'
+ type=router options:arp_proxy="0a:58:a9:fe:01:01 169.254.239.254 169.254.239.2 169.254.238.0/24 192.168.1.100 192.168.1.200" options:router-port=foo addresses='"router"'
# Connect bar to R1
check ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 192.168.2.1/24
@@ -10657,6 +10657,12 @@ ADD_VETH(foo3, foo3, br-int, "192.168.1.4/24", "f0:00:00:01:02:05", \
check ovn-nbctl lsp-add foo foo3 \
-- lsp-set-addresses foo3 "f0:00:00:01:02:05 192.168.1.4"
+ADD_NAMESPACES(foo4)
+ADD_VETH(foo4, foo4, br-int, "192.168.1.6/24", "f0:00:00:01:02:11", \
+ "192.168.1.1")
+check ovn-nbctl lsp-add foo foo4 \
+-- lsp-set-addresses foo4 "f0:00:00:01:02:11 192.168.1.6"
+
# Logical port 'ext1' in switch 'foo'
ADD_NAMESPACES(ext1)
ADD_VETH(ext1, ext1, br-ext, "192.168.1.5/24", "f0:00:00:01:02:06", \
@@ -10672,6 +10678,12 @@ ADD_VETH(bar1, bar1, br-int, "192.168.2.2/24", "f0:00:00:01:02:07", \
check ovn-nbctl lsp-add bar bar1 \
-- lsp-set-addresses bar1 "f0:00:00:01:02:07 192.168.2.2"
+ADD_NAMESPACES(bar2)
+ADD_VETH(bar2, bar2, br-int, "192.168.2.3/24", "f0:00:00:01:02:10", \
+"192.168.2.1")
+check ovn-nbctl lsp-add bar bar2 \
+-- lsp-set-addresses bar2 "f0:00:00:01:10:10 192.168.2.3"
+
# wait for ovn-controller to catch up.
check ovn-nbctl --wait=hv sync
@@ -10723,6 +10735,14 @@ OVS_WAIT_UNTIL([
test "${total_pkts}" = "3"
])
+check ovn-nbctl lr-route-add R1 169.254.240.0/24 192.168.1.200
+NETNS_START_TCPDUMP([foo4], [-nn -c 4 -e -i foo4 arp[[24:4]]=0xc0a801c8], [foo4-arp])
+
+NS_CHECK_EXEC([bar2], [ping -q -c 5 -i 0.3 -w 2 169.254.240.10],[ignore],[ignore])
+OVS_WAIT_UNTIL([
+ total_pkts=$(cat foo4-arp.tcpdump| wc -l)
+ test "${total_pkts}" = "4"
+])
OVS_APP_EXIT_AND_WAIT([ovn-controller])
diff --git a/utilities/automake.mk b/utilities/automake.mk
index 6a2b96e66..b7d2ebeef 100644
--- a/utilities/automake.mk
+++ b/utilities/automake.mk
@@ -41,6 +41,7 @@ EXTRA_DIST += \
utilities/checkpatch.py \
utilities/containers/Makefile \
utilities/containers/py-requirements.txt \
+ utilities/containers/prepare.sh \
utilities/containers/fedora/Dockerfile \
utilities/containers/ubuntu/Dockerfile \
utilities/docker/Makefile \
diff --git a/utilities/containers/fedora/Dockerfile b/utilities/containers/fedora/Dockerfile
index c11ea37b7..f5852378c 100755
--- a/utilities/containers/fedora/Dockerfile
+++ b/utilities/containers/fedora/Dockerfile
@@ -27,6 +27,7 @@ RUN dnf -y update \
libcap-ng-devel \
libtool \
net-tools \
+ nftables \
nmap-ncat \
openssl \
openssl-devel \
@@ -44,23 +45,12 @@ RUN dnf -y update \
&& \
dnf clean all
-# Compile sparse from source
-WORKDIR /workspace/sparse
-
-RUN git clone git://git.kernel.org/pub/scm/devel/sparse/sparse.git \
- /workspace/sparse \
- && \
- make -j4 PREFIX=/usr HAVE_LLVM= HAVE_SQLITE= install
-
WORKDIR /workspace
COPY $CONTAINERS_PATH/py-requirements.txt /tmp/py-requirements.txt
-# Update and install pip dependencies
-RUN python3 -m pip install --upgrade pip \
- && \
- python3 -m pip install wheel \
- && \
- python3 -m pip install -r /tmp/py-requirements.txt
+COPY $CONTAINERS_PATH/prepare.sh /tmp/prepare.sh
+
+RUN /tmp/prepare.sh
CMD ["/usr/sbin/init"]
diff --git a/utilities/containers/prepare.sh b/utilities/containers/prepare.sh
new file mode 100755
index 000000000..d3e8c4253
--- /dev/null
+++ b/utilities/containers/prepare.sh
@@ -0,0 +1,22 @@
+#!/bin/bash -xe
+
+function compile_sparse()
+{
+ git clone git://git.kernel.org/pub/scm/devel/sparse/sparse.git \
+ /workspace/sparse
+
+ pushd sparse
+ make -j4 PREFIX=/usr HAVE_LLVM= HAVE_SQLITE= install
+ popd
+}
+
+function install_python_dep()
+{
+ # The --user should be removed once pip can be upgraded on Ubuntu.
+ python3 -m pip install --user --upgrade pip
+ python3 -m pip install wheel
+ python3 -m pip install -r /tmp/py-requirements.txt
+}
+
+compile_sparse
+install_python_dep
diff --git a/utilities/containers/ubuntu/Dockerfile b/utilities/containers/ubuntu/Dockerfile
index 3c7fe7775..4e9599004 100755
--- a/utilities/containers/ubuntu/Dockerfile
+++ b/utilities/containers/ubuntu/Dockerfile
@@ -32,6 +32,7 @@ RUN apt update -y \
llvm-dev \
ncat \
net-tools \
+ nftables \
python3-dev \
python3-pip \
selinux-policy-dev \
@@ -43,23 +44,12 @@ RUN apt update -y \
&& \
apt clean
-# Compile sparse from source
-WORKDIR /workspace/sparse
-
-RUN git clone git://git.kernel.org/pub/scm/devel/sparse/sparse.git \
- /workspace/sparse \
- && \
- make -j4 PREFIX=/usr HAVE_LLVM= HAVE_SQLITE= install
-
WORKDIR /workspace
COPY $CONTAINERS_PATH/py-requirements.txt /tmp/py-requirements.txt
-# Update and install pip dependencies
-RUN python3 -m pip install --upgrade pip \
- && \
- python3 -m pip install wheel \
- && \
- python3 -m pip install -r /tmp/py-requirements.txt
+COPY $CONTAINERS_PATH/prepare.sh /tmp/prepare.sh
+
+RUN /tmp/prepare.sh
CMD ["/sbin/init"]