Add LSP/LRP option `requested-encap-ip` so the CMS can request a specific `Port_Binding.encap` IP (e.g., transit switch ports in ovn-k8s interconnect mode).
When the same encap IP exists for both Geneve and VXLAN, prefer Geneve. If `requested-chassis` is set, consider only encaps on that chassis; otherwise (router-LSP cases), use IP-only lookup. NB-requested encap overrides the VIF `external_ids:encap-ip`. Track NB ownership with Port_Binding option `is-encap-nb-bound` to avoid ovn-northd vs ovn-controller races. CC: Han Zhou <[email protected]> Signed-off-by: Lei Huang <[email protected]> --- NEWS | 3 + controller/binding.c | 18 ++++- northd/en-northd.c | 4 ++ northd/inc-proc-northd.c | 11 +++ northd/northd.c | 118 +++++++++++++++++++++++++++++-- northd/northd.h | 1 + ovn-nb.xml | 18 +++++ ovn-sb.xml | 8 +++ tests/ovn-inc-proc-graph-dump.at | 2 + tests/ovn-northd.at | 94 ++++++++++++++++++++++++ tests/ovn.at | 51 +++++++++++++ 11 files changed, 319 insertions(+), 9 deletions(-) diff --git a/NEWS b/NEWS index ef7b4210b..888946b54 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,9 @@ Post v26.03.0 OVN v26.03.0 - xxx xx xxxx -------------------------- + - Added LSP/LRP option "requested-encap-ip" to let CMS request a specific + SB Port_Binding encap IP (e.g., for transit switch ports in ovn-k8s + interconnect mode). - Added DNS query statistics tracking in ovn-controller using OVS coverage counters. Statistics can be queried using "ovn-appctl -t ovn-controller coverage/read-counter <counter_name>" or "coverage/show". Tracked metrics diff --git a/controller/binding.c b/controller/binding.c index eb9524142..fa1984ee7 100644 --- a/controller/binding.c +++ b/controller/binding.c @@ -1300,12 +1300,24 @@ claimed_lport_set_up(const struct sbrec_port_binding *pb, typedef void (*set_func)(const struct sbrec_port_binding *pb, const struct sbrec_encap *); +static bool +pb_encap_managed_by_northd(const struct sbrec_port_binding *pb) +{ + const char *requested_encap_ip = smap_get(&pb->options, + "requested-encap-ip"); + return requested_encap_ip && requested_encap_ip[0]; +} + static bool update_port_encap_if_needed(const struct sbrec_port_binding *pb, const struct sbrec_chassis *chassis_rec, const struct ovsrec_interface *iface_rec, bool sb_readonly) { + if (pb_encap_managed_by_northd(pb)) { + return true; + } + const struct sbrec_encap *encap_rec = sbrec_get_port_encap(chassis_rec, iface_rec); if ((encap_rec && pb->encap != encap_rec) || @@ -1508,7 +1520,8 @@ release_lport_main_chassis(const struct sbrec_port_binding *pb, bool sb_readonly, struct if_status_mgr *if_mgr) { - if (pb->encap) { + if (pb->encap && + !pb_encap_managed_by_northd(pb)) { if (sb_readonly) { return false; } @@ -2406,7 +2419,8 @@ binding_cleanup(struct ovsdb_idl_txn *ovnsb_idl_txn, bool any_changes = false; SBREC_PORT_BINDING_TABLE_FOR_EACH (binding_rec, port_binding_table) { if (binding_rec->chassis == chassis_rec) { - if (binding_rec->encap) { + if (binding_rec->encap && + !pb_encap_managed_by_northd(binding_rec)) { sbrec_port_binding_set_encap(binding_rec, NULL); } sbrec_port_binding_set_chassis(binding_rec, NULL); diff --git a/northd/en-northd.c b/northd/en-northd.c index a828f9a5f..c34818dba 100644 --- a/northd/en-northd.c +++ b/northd/en-northd.c @@ -51,6 +51,10 @@ northd_get_input_data(struct engine_node *node, engine_ovsdb_node_get_index( engine_get_input("SB_chassis", node), "sbrec_chassis_by_hostname"); + input_data->sbrec_encap_by_ip = + engine_ovsdb_node_get_index( + engine_get_input("SB_encap", node), + "sbrec_encap_by_ip"); input_data->sbrec_ha_chassis_grp_by_name = engine_ovsdb_node_get_index( engine_get_input("SB_ha_chassis_group", node), diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c index b79272324..9c7de172e 100644 --- a/northd/inc-proc-northd.c +++ b/northd/inc-proc-northd.c @@ -97,6 +97,7 @@ static unixctl_cb_func chassis_features_list; #define SB_NODES \ SB_NODE(sb_global) \ SB_NODE(chassis) \ + SB_NODE(encap) \ SB_NODE(address_set) \ SB_NODE(port_group) \ SB_NODE(logical_flow) \ @@ -261,6 +262,11 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, NULL); engine_add_input(&en_northd, &en_sb_chassis, NULL); + /* northd uses SB Encap mainly to get the index for requested-encap-ip + * lookups. Chassis owns Encap membership, so encap create/delete are + * covered by the SB chassis input. Hence a noop handler is sufficient + * here. */ + engine_add_input(&en_northd, &en_sb_encap, engine_noop_handler); engine_add_input(&en_northd, &en_sb_mirror, NULL); engine_add_input(&en_northd, &en_sb_meter, NULL); engine_add_input(&en_northd, &en_sb_dns, NULL); @@ -514,6 +520,8 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, ip_mcast_index_create(sb->idl); struct ovsdb_idl_index *sbrec_chassis_by_hostname = chassis_hostname_index_create(sb->idl); + struct ovsdb_idl_index *sbrec_encap_by_ip = + ovsdb_idl_index_create1(sb->idl, &sbrec_encap_col_ip); struct ovsdb_idl_index *sbrec_mac_binding_by_datapath = mac_binding_by_datapath_index_create(sb->idl); struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip @@ -529,6 +537,9 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, engine_ovsdb_node_add_index(&en_sb_chassis, "sbrec_chassis_by_hostname", sbrec_chassis_by_hostname); + engine_ovsdb_node_add_index(&en_sb_encap, + "sbrec_encap_by_ip", + sbrec_encap_by_ip); engine_ovsdb_node_add_index(&en_sb_ha_chassis_group, "sbrec_ha_chassis_grp_by_name", sbrec_ha_chassis_grp_by_name); diff --git a/northd/northd.c b/northd/northd.c index 983975dac..411f44d59 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -2546,6 +2546,90 @@ ovn_port_update_sbrec_chassis( free(requested_chassis_sb); } +static const struct sbrec_encap * +encap_lookup_by_ip(struct ovsdb_idl_index *sbrec_encap_by_ip, + const char *ip, const char *requested_chassis) +{ + struct sbrec_encap *key = + sbrec_encap_index_init_row(sbrec_encap_by_ip); + sbrec_encap_index_set_ip(key, ip); + + const struct sbrec_encap *best = NULL; + const struct sbrec_encap *encap; + SBREC_ENCAP_FOR_EACH_EQUAL (encap, key, sbrec_encap_by_ip) { + if (requested_chassis && + strcmp(encap->chassis_name, requested_chassis)) { + continue; + } + + enum chassis_tunnel_type tun_type = get_tunnel_type(encap->type); + if (tun_type == TUNNEL_TYPE_INVALID) { + continue; + } + /* Pick the highest-preference tunnel type (geneve > vxlan) + * when multiple encap types share the same IP. */ + if (!best || get_tunnel_type(best->type) < tun_type) { + best = encap; + } + } + sbrec_encap_index_destroy_row(key); + + return best; +} + +static void +ovn_port_update_requested_encap( + struct ovsdb_idl_index *sbrec_encap_by_ip, + const struct ovn_port *op, + bool was_requested_encap_ip) +{ + if (is_cr_port(op)) { + return; + } + + const struct smap *options = op->nbsp ? &op->nbsp->options + : &op->nbrp->options; + const char *requested_ip = smap_get(options, "requested-encap-ip"); + if (!requested_ip || !requested_ip[0]) { + if (was_requested_encap_ip) { + if (op->sb->encap) { + sbrec_port_binding_set_encap(op->sb, NULL); + } + sbrec_port_binding_update_options_delkey(op->sb, + "requested-encap-ip"); + } + return; + } + + const char *requested_chassis = op->sb->requested_chassis + ? op->sb->requested_chassis->name + : NULL; + const struct sbrec_encap *encap = encap_lookup_by_ip(sbrec_encap_by_ip, + requested_ip, + requested_chassis); + if (!encap) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + if (requested_chassis) { + VLOG_WARN_RL(&rl, + "No Encap matches options requested-encap-ip=\"%s\" " + "and requested-chassis=\"%s\" for logical port %s; " + "clearing Port_Binding.encap.", + requested_ip, requested_chassis, op->key); + } else { + VLOG_WARN_RL(&rl, + "No Encap matches option requested-encap-ip=\"%s\" " + "for logical port %s; clearing Port_Binding.encap.", + requested_ip, op->key); + } + } + + if (op->sb->encap != encap) { + sbrec_port_binding_set_encap(op->sb, encap); + } + sbrec_port_binding_update_options_setkey(op->sb, "requested-encap-ip", + requested_ip); +} + static void check_and_do_sb_mirror_deletion(const struct ovn_port *op) { @@ -2616,11 +2700,16 @@ ovn_port_update_sbrec(struct ovsdb_idl_txn *ovnsb_txn, struct ovsdb_idl_index *sbrec_chassis_by_hostname, struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name, const struct sbrec_mirror_table *sbrec_mirror_table, + struct ovsdb_idl_index *sbrec_encap_by_ip, const struct ovn_port *op, unsigned long *queue_id_bitmap, struct sset *active_ha_chassis_grps) { sbrec_port_binding_set_datapath(op->sb, op->od->sdp->sb_dp); + const char *sb_requested_encap_ip = smap_get(&op->sb->options, + "requested-encap-ip"); + bool was_requested_encap_ip = sb_requested_encap_ip && + sb_requested_encap_ip[0]; if (op->nbrp) { /* Note: SB port binding options for router ports are set in * sync_pbs(). */ @@ -2952,6 +3041,9 @@ common: sbrec_port_binding_set_tunnel_key(op->sb, op->tunnel_key); } + ovn_port_update_requested_encap(sbrec_encap_by_ip, op, + was_requested_encap_ip); + /* ovn-controller will update 'Port_Binding.up' only if it was explicitly * set to 'false'. */ @@ -4232,6 +4324,7 @@ build_ports(struct ovsdb_idl_txn *ovnsb_txn, const struct sbrec_ha_chassis_group_table *sbrec_ha_chassis_group_table, struct ovsdb_idl_index *sbrec_chassis_by_name, struct ovsdb_idl_index *sbrec_chassis_by_hostname, + struct ovsdb_idl_index *sbrec_encap_by_ip, struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name, struct hmap *ls_datapaths, struct hmap *lr_datapaths, struct hmap *ls_ports, struct hmap *lr_ports, @@ -4307,6 +4400,7 @@ build_ports(struct ovsdb_idl_txn *ovnsb_txn, sbrec_chassis_by_hostname, sbrec_ha_chassis_grp_by_name, sbrec_mirror_table, + sbrec_encap_by_ip, op, queue_id_bitmap, &active_ha_chassis_grps); op->od->is_transit_router |= is_transit_router_port(op); @@ -4321,6 +4415,7 @@ build_ports(struct ovsdb_idl_txn *ovnsb_txn, sbrec_chassis_by_hostname, sbrec_ha_chassis_grp_by_name, sbrec_mirror_table, + sbrec_encap_by_ip, op, queue_id_bitmap, &active_ha_chassis_grps); sbrec_port_binding_set_logical_port(op->sb, op->key); @@ -4543,7 +4638,8 @@ ls_port_init(struct ovn_port *op, struct ovsdb_idl_txn *ovnsb_txn, const struct sbrec_port_binding *sb, const struct sbrec_mirror_table *sbrec_mirror_table, struct ovsdb_idl_index *sbrec_chassis_by_name, - struct ovsdb_idl_index *sbrec_chassis_by_hostname) + struct ovsdb_idl_index *sbrec_chassis_by_hostname, + struct ovsdb_idl_index *sbrec_encap_by_ip) { op->od = od; parse_lsp_addrs(op); @@ -4573,6 +4669,7 @@ ls_port_init(struct ovn_port *op, struct ovsdb_idl_txn *ovnsb_txn, } ovn_port_update_sbrec(ovnsb_txn, sbrec_chassis_by_name, sbrec_chassis_by_hostname, NULL, sbrec_mirror_table, + sbrec_encap_by_ip, op, NULL, NULL); return true; } @@ -4583,13 +4680,15 @@ ls_port_create(struct ovsdb_idl_txn *ovnsb_txn, struct hmap *ls_ports, struct ovn_datapath *od, const struct sbrec_mirror_table *sbrec_mirror_table, struct ovsdb_idl_index *sbrec_chassis_by_name, - struct ovsdb_idl_index *sbrec_chassis_by_hostname) + struct ovsdb_idl_index *sbrec_chassis_by_hostname, + struct ovsdb_idl_index *sbrec_encap_by_ip) { struct ovn_port *op = ovn_port_create(ls_ports, key, nbsp, NULL, NULL); hmap_insert(&od->ports, &op->dp_node, hmap_node_hash(&op->key_node)); if (!ls_port_init(op, ovnsb_txn, od, NULL, sbrec_mirror_table, - sbrec_chassis_by_name, sbrec_chassis_by_hostname)) { + sbrec_chassis_by_name, sbrec_chassis_by_hostname, + sbrec_encap_by_ip)) { ovn_port_destroy(ls_ports, op); return NULL; } @@ -4604,14 +4703,16 @@ ls_port_reinit(struct ovn_port *op, struct ovsdb_idl_txn *ovnsb_txn, const struct sbrec_port_binding *sb, const struct sbrec_mirror_table *sbrec_mirror_table, struct ovsdb_idl_index *sbrec_chassis_by_name, - struct ovsdb_idl_index *sbrec_chassis_by_hostname) + struct ovsdb_idl_index *sbrec_chassis_by_hostname, + struct ovsdb_idl_index *sbrec_encap_by_ip) { ovn_port_cleanup(op); op->sb = sb; ovn_port_set_nb(op, nbsp, NULL); op->primary_port = op->cr_port = NULL; return ls_port_init(op, ovnsb_txn, od, sb, sbrec_mirror_table, - sbrec_chassis_by_name, sbrec_chassis_by_hostname); + sbrec_chassis_by_name, sbrec_chassis_by_hostname, + sbrec_encap_by_ip); } /* Returns true if the logical switch has changes which can be @@ -4810,7 +4911,8 @@ ls_handle_lsp_changes(struct ovsdb_idl_txn *ovnsb_idl_txn, new_nbsp->name, new_nbsp, od, ni->sbrec_mirror_table, ni->sbrec_chassis_by_name, - ni->sbrec_chassis_by_hostname); + ni->sbrec_chassis_by_hostname, + ni->sbrec_encap_by_ip); if (!op) { goto fail; } @@ -4853,7 +4955,8 @@ ls_handle_lsp_changes(struct ovsdb_idl_txn *ovnsb_idl_txn, new_nbsp, od, sb, ni->sbrec_mirror_table, ni->sbrec_chassis_by_name, - ni->sbrec_chassis_by_hostname)) { + ni->sbrec_chassis_by_hostname, + ni->sbrec_encap_by_ip)) { if (sb) { sbrec_port_binding_delete(sb); } @@ -20959,6 +21062,7 @@ ovnnb_db_run(struct northd_input *input_data, input_data->sbrec_ha_chassis_group_table, input_data->sbrec_chassis_by_name, input_data->sbrec_chassis_by_hostname, + input_data->sbrec_encap_by_ip, input_data->sbrec_ha_chassis_grp_by_name, &data->ls_datapaths.datapaths, &data->lr_datapaths.datapaths, &data->ls_ports, &data->lr_ports, diff --git a/northd/northd.h b/northd/northd.h index 4dcd128cc..a876e0a56 100644 --- a/northd/northd.h +++ b/northd/northd.h @@ -86,6 +86,7 @@ struct northd_input { struct ovsdb_idl_index *nbrec_mirror_by_type_and_sink; struct ovsdb_idl_index *sbrec_chassis_by_name; struct ovsdb_idl_index *sbrec_chassis_by_hostname; + struct ovsdb_idl_index *sbrec_encap_by_ip; struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name; struct ovsdb_idl_index *sbrec_ip_mcast_by_dp; struct ovsdb_idl_index *sbrec_fdb_by_dp_and_port; diff --git a/ovn-nb.xml b/ovn-nb.xml index 954ed1166..f1cd89509 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -1567,6 +1567,15 @@ </p> </column> + <column name="options" key="requested-encap-ip"> + Requests the encapsulation IP address for the port binding. If set, + <code>ovn-northd</code> uses this IP to select the + <ref table="Encap" db="OVN_Southbound"/> entry written to + <ref table="Port_Binding" column="encap" db="OVN_Southbound"/>. + This is intended for ports without a local OVS interface, e.g. remote + transit switch ports in ovn-kubernetes interconnect mode. + </column> + <column name="options" key="activation-strategy"> If used with multiple chassis set in <ref column="requested-chassis"/>, specifies an activation strategy @@ -4543,6 +4552,15 @@ or </p> </column> + <column name="options" key="requested-encap-ip"> + Requests the encapsulation IP address for the port binding. If set, + <code>ovn-northd</code> uses this IP to select the + <ref table="Encap" db="OVN_Southbound"/> entry written to + <ref table="Port_Binding" column="encap" db="OVN_Southbound"/>. + This is intended for ports without a local OVS interface, e.g. remote + transit router ports in ovn-kubernetes interconnect mode. + </column> + <column name="options" key="dynamic-routing-redistribute" type='{"type": "string"}'> <p> diff --git a/ovn-sb.xml b/ovn-sb.xml index 92496b911..46568da62 100644 --- a/ovn-sb.xml +++ b/ovn-sb.xml @@ -3829,6 +3829,14 @@ tcp.flags = RST; </p> </column> + <column name="options" key="requested-encap-ip"> + If set, <code>ovn-northd</code> resolves and sets + <ref column="encap"/> for this port based on the requested tunnel + endpoint IP. If absent, <code>ovn-controller</code> may manage + <ref column="encap"/> from local interface + <code>external_ids:encap-ip</code>. + </column> + <column name="options" key="activation-strategy"> If used with multiple chassis set in <ref column="requested-chassis"/>, specifies an activation strategy diff --git a/tests/ovn-inc-proc-graph-dump.at b/tests/ovn-inc-proc-graph-dump.at index a31aad6e7..c72d90b12 100644 --- a/tests/ovn-inc-proc-graph-dump.at +++ b/tests/ovn-inc-proc-graph-dump.at @@ -20,6 +20,7 @@ digraph "Incremental-Processing-Engine" { NB_network_function_group [[style=filled, shape=box, fillcolor=white, label="NB_network_function_group"]]; NB_logical_switch_port_health_check [[style=filled, shape=box, fillcolor=white, label="NB_logical_switch_port_health_check"]]; SB_chassis [[style=filled, shape=box, fillcolor=white, label="SB_chassis"]]; + SB_encap [[style=filled, shape=box, fillcolor=white, label="SB_encap"]]; SB_mirror [[style=filled, shape=box, fillcolor=white, label="SB_mirror"]]; SB_meter [[style=filled, shape=box, fillcolor=white, label="SB_meter"]]; SB_dns [[style=filled, shape=box, fillcolor=white, label="SB_dns"]]; @@ -78,6 +79,7 @@ digraph "Incremental-Processing-Engine" { NB_network_function_group -> northd [[label=""]]; NB_logical_switch_port_health_check -> northd [[label=""]]; SB_chassis -> northd [[label=""]]; + SB_encap -> northd [[label="engine_noop_handler"]]; SB_mirror -> northd [[label=""]]; SB_meter -> northd [[label=""]]; SB_dns -> northd [[label=""]]; diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index e29f6d7b5..4c1440b22 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -2896,6 +2896,100 @@ OVN_CLEANUP_NORTHD AT_CLEANUP ]) +OVN_FOR_EACH_NORTHD_NO_HV([ +AT_SETUP([check options:requested-encap-ip fills port binding encap col]) +AT_KEYWORDS([requested encap ip]) +ovn_start + +check_uuid ovn-sbctl \ + -- --id=@e11 create encap chassis_name=ch1 ip="192.168.1.1" type="vxlan" \ + -- --id=@e12 create encap chassis_name=ch1 ip="192.168.1.2" type="geneve" \ + -- --id=@c1 create chassis name=ch1 encaps=@e11,@e12 +check_uuid ovn-sbctl \ + -- --id=@e21 create encap chassis_name=ch2 ip="192.168.2.1" type="geneve" \ + -- --id=@e22 create encap chassis_name=ch2 ip="192.168.2.2" type="geneve" \ + -- --id=@c2 create chassis name=ch2 encaps=@e21,@e22 + +wait_row_count Chassis 2 +wait_row_count Encap 4 +en11_uuid=$(fetch_column Encap _uuid ip="192.168.1.1") +en12_uuid=$(fetch_column Encap _uuid ip="192.168.1.2") +en21_uuid=$(fetch_column Encap _uuid ip="192.168.2.1") +en22_uuid=$(fetch_column Encap _uuid ip="192.168.2.2") +ovn-sbctl show + +echo "__file__:__line__: encap uuid: $en11_uuid, ip: 192.168.1.1" +echo "__file__:__line__: encap uuid: $en12_uuid, ip: 192.168.1.2" +echo "__file__:__line__: encap uuid: $en21_uuid, ip: 192.168.2.1" +echo "__file__:__line__: encap uuid: $en22_uuid, ip: 192.168.2.2" + +check ovn-nbctl --wait=sb ls-add ls1 +check ovn-nbctl --wait=sb lsp-add ls1 lsp1 +check ovn-nbctl --wait=sb lsp-add ls1 lsp2 +ovn-nbctl show + +# set options:requested-encap-ip without requested-chassis +check ovn-nbctl --wait=sb set logical-switch-port lsp1 \ + options:requested-encap-ip=192.168.1.1 +check ovn-nbctl --wait=sb sync +wait_row_count Port_Binding 1 logical_port=lsp1 encap="$en11_uuid" + +# With requested-chassis set to a different chassis, encap should be cleared. +check ovn-nbctl --wait=sb set logical-switch-port lsp1 \ + options:requested-chassis=ch2 +wait_row_count Port_Binding 1 logical_port=lsp1 'encap=[[]]' + +# Set both options to a matching chassis+IP. +check ovn-nbctl --wait=sb set logical-switch-port lsp1 \ + options:requested-chassis=ch1 \ + options:requested-encap-ip=192.168.1.1 +check ovn-nbctl --wait=sb set logical-switch-port lsp2 \ + options:requested-chassis=ch2 \ + options:requested-encap-ip=192.168.2.2 + +wait_row_count Port_Binding 1 logical_port=lsp1 encap="$en11_uuid" +wait_row_count Port_Binding 1 logical_port=lsp2 encap="$en22_uuid" + +# Add geneve encap with the same IP and ensure it is preferred over vxlan. +check_uuid ovn-sbctl \ + -- --id=@e11g create encap chassis_name=ch1 ip="192.168.1.1" type="geneve" \ + -- add chassis ch1 encaps @e11g +wait_row_count Encap 5 +en11g_uuid=$(fetch_column Encap _uuid chassis_name=ch1 ip="192.168.1.1" type=geneve) +wait_row_count Port_Binding 1 logical_port=lsp1 encap="$en11g_uuid" + +# Router LSP path has no requested-chassis, but requested-encap-ip should work. +check ovn-nbctl --wait=sb lr-add lr1 +check ovn-nbctl --wait=sb lrp-add lr1 lrp1 00:00:00:01:00:01 100.64.0.1/24 +check ovn-nbctl --wait=sb lsp-add ls1 lsp-router1 \ + -- lsp-set-type lsp-router1 router \ + -- lsp-set-options lsp-router1 router-port=lrp1 \ + -- lsp-set-addresses lsp-router1 router +check ovn-nbctl --wait=sb set logical-switch-port lsp-router1 \ + options:requested-encap-ip=192.168.2.1 +wait_row_count Port_Binding 1 logical_port=lsp-router1 encap="$en21_uuid" +wait_row_count Port_Binding 1 logical_port=lsp-router1 \ + options:requested-encap-ip=192.168.2.1 + +# remove options:requested-encap-ip from lsp1 +check ovn-nbctl --wait=sb remove logical_switch_port lsp1 \ + options requested-encap-ip=192.168.1.1 +wait_row_count Port_Binding 1 logical_port=lsp1 'encap=[[]]' + +# remove options:requested-chassis from lsp2 and keep requested-encap-ip +check ovn-nbctl --wait=sb remove logical_switch_port lsp2 \ + options requested-chassis=ch2 +wait_row_count Port_Binding 1 logical_port=lsp2 encap="$en22_uuid" + +# remove options:requested-encap-ip from lsp2 +check ovn-nbctl --wait=sb remove logical_switch_port lsp2 \ + options requested-encap-ip=192.168.2.2 +wait_row_count Port_Binding 1 logical_port=lsp2 'encap=[[]]' + +OVN_CLEANUP_NORTHD +AT_CLEANUP +]) + OVN_FOR_EACH_NORTHD_NO_HV([ AT_SETUP([port requested-tnl-key]) AT_KEYWORDS([requested tnl tunnel key keys]) diff --git a/tests/ovn.at b/tests/ovn.at index 9082bba82..58e62e2f0 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -40748,6 +40748,57 @@ ignored_dp=lsw0]) AT_CLEANUP ]) +OVN_FOR_EACH_NORTHD([ +AT_SETUP([ovn-controller - requested-encap-ip should override VIF encap-ip]) +ovn_start +net_add n1 + +sim_add hv1 +as hv1 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 +check ovs-vsctl set Open_vSwitch . \ + external_ids:ovn-encap-ip="192.168.0.1,192.168.0.11" \ + external_ids:ovn-encap-ip-default=192.168.0.1 \ + external_ids:ovn-enable-flow-based-tunnels=false + +check ovn-nbctl ls-add ls0 +check ovn-nbctl lsp-add ls0 lsp0 +check ovn-nbctl lsp-set-addresses lsp0 "50:54:00:00:00:01 10.0.0.1" + +as hv1 +check ovs-vsctl -- add-port br-int vif0 -- \ + set Interface vif0 external-ids:iface-id=lsp0 \ + external-ids:encap-ip=192.168.0.11 + +wait_row_count Chassis 1 name=hv1 +wait_row_count Encap 4 chassis_name=hv1 +check ovn-nbctl --wait=hv sync +wait_for_ports_up lsp0 + +encap_uuid_vif=$(ovn-sbctl --bare --columns _uuid find Encap \ + chassis_name=hv1 ip="192.168.0.11" type=geneve) +encap_uuid_nb=$(ovn-sbctl --bare --columns _uuid find Encap \ + chassis_name=hv1 ip="192.168.0.1" type=geneve) + +get_pb_encap_uuid() { + fetch_column Port_Binding encap logical_port=lsp0 +} + +# Verify local VIF encap-ip is reflected by ovn-controller. +OVS_WAIT_UNTIL([test "$encap_uuid_vif" = "$(get_pb_encap_uuid)"]) + +# Now request NB-driven encap. +check ovn-nbctl --wait=sb lsp-set-options lsp0 \ + requested-chassis=hv1 requested-encap-ip=192.168.0.1 + +# Expected behavior: NB request should win over local iface encap-ip. +OVS_WAIT_UNTIL([test "$encap_uuid_nb" = "$(get_pb_encap_uuid)"]) + +OVN_CLEANUP([hv1]) +AT_CLEANUP +]) + OVN_FOR_EACH_NORTHD([ AT_SETUP([DHCP RELAY]) ovn_start -- 2.43.0 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
