On 7/11/25 4:56 AM, Dumitru Ceara wrote: > On 7/10/25 7:46 PM, Rosemarie O'Riorden wrote: >> Previously, if there was a logical switch with a virtual port that had a >> virtual parent port configured, and then the parent port was deleted and >> recreated, the parent port would not be reclaimed by the chassis and >> thus would not behave as the parent port, breaking traffic. >> >> So long as virtual ports have a parent port configured, there should be >> no issue deleting and recreating the parent. It should continue working >> as the parent as soon as it's up again. >> >> With this change, the parent port will function as the parent even after >> deletion and recreation. The chassis will properly reclaim the virtual >> port. >> >> Reported-at: https://issues.redhat.com/browse/FDP-710 >> Co-authored-by: Mohammad Heib <mh...@redhat.com> >> Signed-off-by: Mohammad Heib <mh...@redhat.com> >> Signed-off-by: Rosemarie O'Riorden <rosema...@redhat.com> >> --- > > Hi Rosemarie, > > Thanks for the patch!
Thank you for the review! > > I didn't get a chance to review it yet but it seems it introduces a > memory leak. Please see the CI output here: > > https://github.com/ovsrobot/ovn/actions/runs/16202471658/job/45754556600#step:12:5607 Thank you for making me aware of this. I saw that some tests were failing but I thought it was a fluke because of the final error message: + echo '*** ERROR: 1 ***' + podman rm -f 445906a9d9d9d8265c03ea9fdfb7032fc409857522e061ac6d957184a75032ff 445906a9d9d9d8265c03ea9fdfb7032fc409857522e061ac6d957184a75032ff Error: Process completed with exit code 1. I think this sometimes indicates a random CI failure, that will fix itself upon rerun. So I missed the very valid reason for failure this time :) > > I'll move the series to changes requested in patchwork for now, it might > be better to have green CI before we fully review this. Ack! > > Regards, > Dumitru > >> northd/northd.c | 29 ++++++++++++++++ >> tests/ovn.at | 90 +++++++++++++++++++++++++++++++++++++++++++++++++ >> 2 files changed, 119 insertions(+) >> >> diff --git a/northd/northd.c b/northd/northd.c >> index 052e15c2a..6cb1b5c24 100644 >> --- a/northd/northd.c >> +++ b/northd/northd.c >> @@ -4990,6 +4990,8 @@ ls_handle_lsp_changes(struct ovsdb_idl_txn >> *ovnsb_idl_txn, >> && (vector_len(&od->router_ports) == hmap_count(&od->ports))); >> >> struct ovn_port *op; >> + struct ovs_list exist_virtual_ports; >> + ovs_list_init(&exist_virtual_ports); >> HMAP_FOR_EACH (op, dp_node, &od->ports) { >> op->visited = false; >> } >> @@ -5059,6 +5061,8 @@ ls_handle_lsp_changes(struct ovsdb_idl_txn >> *ovnsb_idl_txn, >> delete_fdb_entries(ni->sbrec_fdb_by_dp_and_port, >> od->tunnel_key, old_tunnel_key); >> } >> + } else if (!strcmp(op->nbsp->type, "virtual")) { >> + ovs_list_push_back(&exist_virtual_ports, &op->list); >> } >> op->visited = true; >> } >> @@ -5105,6 +5109,31 @@ ls_handle_lsp_changes(struct ovsdb_idl_txn >> *ovnsb_idl_txn, >> } >> } >> >> + /* >> + * Update old virtual ports that have newly created VIF as parent port. >> + * This code handles cases where the virtual port was created >> + * before the parent port or when the parent port was recreated. >> + */ >> + struct smap op_smap = SMAP_INITIALIZER(&op_smap); >> + >> + LIST_FOR_EACH_POP (op, list, &exist_virtual_ports) { >> + smap_add(&op_smap, op->nbsp->name, >> + smap_get_def(&op->nbsp->options, "virtual-parents", "")); >> + struct smap_node *node; >> + SMAP_FOR_EACH (node, &op_smap) { >> + char *tokstr = xstrdup(node->value); >> + char *save_ptr = NULL; >> + char *vparent; >> + for (vparent = strtok_r(tokstr, ",", &save_ptr); vparent != >> NULL; >> + vparent = strtok_r(NULL, ",", &save_ptr)) { >> + if (vparent) { >> + add_op_to_northd_tracked_ports(&trk_lsps->updated, op); >> + break; >> + } >> + } >> + } >> + } >> + >> return true; >> >> fail: >> diff --git a/tests/ovn.at b/tests/ovn.at >> index 108de260e..28fc53cdc 100644 >> --- a/tests/ovn.at >> +++ b/tests/ovn.at >> @@ -43472,3 +43472,93 @@ AT_CHECK([grep -q "Postponing virtual lport >> sw0-vir" hv3/ovn-controller.log], [1 >> OVN_CLEANUP([hv1]) >> AT_CLEANUP >> ]) >> + >> +OVN_FOR_EACH_NORTHD([ >> +AT_SETUP([virtual port - parents port re-create]) >> +AT_KEYWORDS([virtual ports]) >> +ovn_start >> +send_garp() { >> + 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$hv ovs-appctl netdev-dummy/receive hv${hv}-vif$inport $request >> +} >> + >> +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 ovn-appctl vlog/set dbg >> +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ >> + set interface hv1-vif1 external-ids:iface-id=sw0-p1 \ >> + options:tx_pcap=hv1/vif1-tx.pcap \ >> + options:rxq_pcap=hv1/vif1-rx.pcap \ >> + ofport-request=1 >> + >> +check ovs-appctl -t ovn-controller vlog/set dbg >> + >> +check ovn-nbctl ls-add sw0 >> +check ovn-nbctl lsp-add sw0 sw0-p1 >> +check ovn-nbctl lsp-set-addresses sw0-p1 "50:54:00:00:00:03 10.0.0.3 >> 1000::3" >> +check ovn-nbctl lsp-set-port-security sw0-p1 "50:54:00:00:00:03 10.0.0.3 >> 10.0.0.10 1000::3" >> + >> +check ovn-nbctl lsp-add sw0 sw0-vir >> +check ovn-nbctl lsp-set-addresses sw0-vir "50:54:00:00:00:10 10.0.0.10" >> +check ovn-nbctl lsp-set-port-security sw0-vir "50:54:00:00:00:10 10.0.0.10" >> +check ovn-nbctl lsp-set-type sw0-vir virtual >> +check ovn-nbctl set logical_switch_port sw0-vir options:virtual-ip=10.0.0.10 >> +check ovn-nbctl set logical_switch_port sw0-vir >> options:virtual-parents=sw0-p1 >> + >> +wait_for_ports_up >> +check ovn-nbctl --wait=hv sync >> +hv1_ch_uuid=`ovn-sbctl --bare --columns _uuid find chassis name="hv1"` >> + >> +# From sw0-p1 send GARP for 10.0.0.10. hv1 should claim sw0-vir >> +# and sw0-p1 should be its virtual_parent. >> +eth_src=505400000003 >> +eth_dst=ffffffffffff >> +spa=$(ip_to_hex 10 0 0 10) >> +tpa=$(ip_to_hex 10 0 0 10) >> +send_garp 1 1 $eth_src $eth_dst $spa $tpa >> + >> +OVS_WAIT_UNTIL([test 1 = `cat hv1/ovn-controller.log | grep "pinctrl >> received packet-in" | \ >> +grep opcode=BIND_VPORT | grep OF_Table_ID=$(ovn-debug >> lflow-stage-to-oftable ls_in_arp_rsp) | wc -l`]) >> +wait_row_count Port_Binding 1 logical_port=sw0-vir chassis=$hv1_ch_uuid >> +check_row_count Port_Binding 1 logical_port=sw0-vir virtual_parent=sw0-p1 >> +wait_for_ports_up sw0-vir >> + >> +# Delete parent port. >> +check ovn-nbctl lsp-del sw0-p1 >> +check ovn-nbctl --wait=hv sync >> + >> +# Re-add parent port. >> +check ovn-nbctl lsp-add sw0 sw0-p1 >> +check ovn-nbctl lsp-set-addresses sw0-p1 "50:54:00:00:00:03 10.0.0.3 >> 1000::3" >> +check ovn-nbctl lsp-set-port-security sw0-p1 "50:54:00:00:00:03 10.0.0.3 >> 10.0.0.10 1000::3" >> + >> +wait_for_ports_up >> + >> +# Must sleep for vport-backoff duration, otherwise ovn-controller will >> +# increase the backoff and not claim the port. >> +sleep_time=$(ovn-sbctl get Port_Binding sw0-vir options:vport-backoff) >> +sleep $(echo "$sleep_time" | tr -d '"' | awk '{print $1/1000}') >> + >> +# From sw0-p1 send GARP for 10.0.0.10. hv1 should claim sw0-vir >> +# and sw0-p1 should be its virtual_parent. >> +eth_src=505400000003 >> +eth_dst=ffffffffffff >> +spa=$(ip_to_hex 10 0 0 10) >> +tpa=$(ip_to_hex 10 0 0 10) >> +send_garp 1 1 $eth_src $eth_dst $spa $tpa >> + >> +OVS_WAIT_UNTIL([test 2 = `cat hv1/ovn-controller.log | grep "pinctrl >> received packet-in" | \ >> +grep opcode=BIND_VPORT | grep OF_Table_ID=$(ovn-debug >> lflow-stage-to-oftable ls_in_arp_rsp) | wc -l`]) >> + >> +wait_row_count Port_Binding 1 logical_port=sw0-vir chassis=$hv1_ch_uuid >> +check_row_count Port_Binding 1 logical_port=sw0-vir virtual_parent=sw0-p1 >> +wait_for_ports_up sw0-vir >> + >> +OVN_CLEANUP([hv1]) >> +AT_CLEANUP >> +]) > -- Rosemarie O'Riorden rosema...@redhat.com _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev