)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":36998,"name":"Ilia Baikov","display_name":"Ilia Baikov","email":"ilia.baikov@ib.systems","username":"frct1"},"change_message_id":"189f3f641585f179ca58951d4dec6346a4801982","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"7378bb7b_248a04b8","updated":"2026-02-19 16:51:20.000000000","message":"Hello Jakub!\nAbsolutely enchantend by this feature.\nSince with ovn-bgp-agent routing is done on behalf of OS which leads to growing IRQ, I guess with native BGP implementation and both NIC\u0027s interfaces connected to br-ex it would add more performance with less management overhead.\n\nHow would it be possible to achieve ECMP for loadbalancing? Is it going to be the same approach as ovn-bgp-agent with additional ovn cluster per chassis? Like having br-ex and br-ex-2 with eno1np0 attached to br-ex and eno2np1 attached to br-ex-2. Something like that.","commit_id":"590afafc5306e414492503a7c06fef476d41a5da"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"b56a02a04b385e7544751403ac2557e0d05b6db5","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"c96c6e0a_fc14ac62","in_reply_to":"0f4d5274_2ca17141","updated":"2026-02-25 21:55:14.000000000","message":"With the bgp extension you can\u0027t have L2, all IPs get routed on the L3. The br-ex stays as in the legacy topology and serves as a bridge to the \"BGP topology\" in OVN, underneath what Neutron creates in OVN. Then, as you correctly pointed out, each NIC connected to the leafs has its own OVS bridge. To have the control plane traffic on L2 you\u0027d need to have a dedicated NIC with L2 stretched across the spine\u0027n leaf - or use some routing suite, such as FRR, to advertise the host IPs over the BGP - which is preferable.\n\nas for exposing fixed_ips - that is done by OVN. OVN decides based on the logical router configuration which IPs get \"advertised\" - under the hood it just creates blackhole routes in the local VRF associated with the logical router, so no extra code is required in Neutron.","commit_id":"590afafc5306e414492503a7c06fef476d41a5da"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"f68c2089e73ab52b5183dab74a5ec05eafb59d9c","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"4c20408a_3b9ad6f6","in_reply_to":"3c59293a_b98c03ff","updated":"2026-02-26 13:07:35.000000000","message":"The router that decides what IPs from Neuron are advertised is the \"BGP distributed router\" in this picture. As it has the connection (dashed line) to the public logical switch it picks all addresses this switch can \"see\" and advertises those. All those LSP addresses are advertised as host routes. The per-chassis routers are there merely to learn the routes out from the OVN system. I think it should work with multiple subnets on a single LS - I haven\u0027t tried that though.","commit_id":"590afafc5306e414492503a7c06fef476d41a5da"},{"author":{"_account_id":36998,"name":"Ilia Baikov","display_name":"Ilia Baikov","email":"ilia.baikov@ib.systems","username":"frct1"},"change_message_id":"a1967b4a7c3539e6e2a57417a4758e6e36961431","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"ad1abf84_5148c476","in_reply_to":"4a8ba56b_eb1f3297","updated":"2026-02-25 17:27:02.000000000","message":"Wooooah! Go for it!\n\nAbout IRQ: I guess it happens because of kernel routing overhead, like ip route lookup br-ex...\n\nAs OVN having issues on hanlding OVN within large L2 domains (starting from about 2,000 running instances) the best choice is to switch to L3 using ovn-bgp-agent, with it\u0027s down pitfalls, but it works, despite high IRQ, it is like 10% IRQ on 2Gbps rate.\n\nAm I right that in case of ECMP we just placing both interfaces into it\u0027s own br-ex (lets call them br-ex-1 and br-ex-2) and to keep OpenStack\u0027s controlplane functioning on a L2 level implementation adds flows for host IPs (such as running OpenStack in L2 VLAN with host IPs provided from 10.10.0.0/24) to return controlplane traffic back to kernel processing? Would it be possible to still create a vlan interfaces on it? Controlplane is connected to the L2 networking using eno1np0 with vlan-id 1010 (projecting current setup case)","commit_id":"590afafc5306e414492503a7c06fef476d41a5da"},{"author":{"_account_id":36998,"name":"Ilia Baikov","display_name":"Ilia Baikov","email":"ilia.baikov@ib.systems","username":"frct1"},"change_message_id":"3e7b927f01ae8ffea28099161b10a15e41ac2d80","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"90051ee3_45e2aed4","in_reply_to":"4c20408a_3b9ad6f6","updated":"2026-02-26 19:17:51.000000000","message":"I guess i understand how would it work, thank you!\nIs this feature planned for release in 2026.1? Will this be backported to let\u0027s say 2025.2 OpenStack release (to use with 25.09.2 OVN)?","commit_id":"590afafc5306e414492503a7c06fef476d41a5da"},{"author":{"_account_id":36998,"name":"Ilia Baikov","display_name":"Ilia Baikov","email":"ilia.baikov@ib.systems","username":"frct1"},"change_message_id":"927f19fad859d398b417b874462fc9094e9dad2a","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"ef3652f5_9a7aedf8","in_reply_to":"7378bb7b_248a04b8","updated":"2026-02-19 22:44:36.000000000","message":"Re-advised specs at https://specs.openstack.org/openstack/neutron-specs/specs/2025.2/ovn-bgp-integration.html\n\nAm I right that initially there is no option to support VMs /32 fixed IPs to be advertised like ovn-bgp-agent do at this moment?","commit_id":"590afafc5306e414492503a7c06fef476d41a5da"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"405cb65947c15f6246f1a0e9dde21e367ba9c443","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"eb25eeb1_b13a45d7","in_reply_to":"90051ee3_45e2aed4","updated":"2026-02-26 23:29:29.000000000","message":"Yes, this is planned for 2026.1 best effort. It won\u0027t get backported to the stable branches as it\u0027s a new feature.","commit_id":"590afafc5306e414492503a7c06fef476d41a5da"},{"author":{"_account_id":36998,"name":"Ilia Baikov","display_name":"Ilia Baikov","email":"ilia.baikov@ib.systems","username":"frct1"},"change_message_id":"d5e60ae99b9916cd8441c324d27f92a537fd68b9","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"0f4d5274_2ca17141","in_reply_to":"ad1abf84_5148c476","updated":"2026-02-25 18:54:33.000000000","message":"I\u0027ve tried to explore all of the patches, but didn\u0027t find any mentions on exposing fixed_ips (Port_Binding table in OVN). Is it not implemented yet or not planned at all? It would completely replace ovn-bgp-agent with native one","commit_id":"590afafc5306e414492503a7c06fef476d41a5da"},{"author":{"_account_id":36998,"name":"Ilia Baikov","display_name":"Ilia Baikov","email":"ilia.baikov@ib.systems","username":"frct1"},"change_message_id":"7e5dc081e1c95ca86613eb9b3da4b3865e6e7beb","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"3c59293a_b98c03ff","in_reply_to":"b1d17f08_dc2a4145","updated":"2026-02-25 23:21:05.000000000","message":"\u003e As for exposing fixed_ips - that is done by OVN. OVN decides based on the logical router configuration which IPs get \"advertised\" - under the hood it just creates blackhole routes in the local VRF associated with the logical router, so no extra code is required in Neutron.\n\nTrying to understand would it work with plain provider network with a lot of subnets configured (simple stupid public network that runs L2 but moving forward to migrate to L3).","commit_id":"590afafc5306e414492503a7c06fef476d41a5da"},{"author":{"_account_id":36998,"name":"Ilia Baikov","display_name":"Ilia Baikov","email":"ilia.baikov@ib.systems","username":"frct1"},"change_message_id":"efdac75dcb0c1025dfc9e9c24d13a0cf1d33c203","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"b1d17f08_dc2a4145","in_reply_to":"c96c6e0a_fc14ac62","updated":"2026-02-25 23:04:19.000000000","message":"Am I right that per-chassis Logical Router named like bgp-router or something will decide on what to advertise? Like Logical Switch Ports that has port binding on that chassis? Should then Logical_Switch (neutron\u0027s provider network for external connectiviy and allocating fixed_ips from for instances) have any options like LR\u0027s dynamic-routing enabled?\nFor me it seems like result of your overall work is make it drop-in replacement of painful L2.","commit_id":"590afafc5306e414492503a7c06fef476d41a5da"},{"author":{"_account_id":36998,"name":"Ilia Baikov","display_name":"Ilia Baikov","email":"ilia.baikov@ib.systems","username":"frct1"},"change_message_id":"7d4e66eb8bf5f577e61d7f2e552d60261148815f","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"6cd42aa0_97713a8d","in_reply_to":"eb25eeb1_b13a45d7","updated":"2026-02-27 02:28:06.000000000","message":"Finally a good reason to upgrade all of the regions to 2026.1 :D\nCan\u0027t wait. Thank you for your job Jakub!","commit_id":"590afafc5306e414492503a7c06fef476d41a5da"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"274f8bcab5d47ba4fac4e6fd2489c017cfbd14b2","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"4a8ba56b_eb1f3297","in_reply_to":"ef3652f5_9a7aedf8","updated":"2026-02-25 16:55:41.000000000","message":"Hi Ilia,\nthank your looking at the patches.\n\nI\u0027m not sure about the IRQs with ovn-bgp-agent and how different it is with this solution but essentially the packet from VM tap is delivered to a peering NIC all the way though the OVS datapath, no linux devices or kernel routes involved. If it helps with IRQs I can\u0027t tell though - I just would assume it should.\n\nYes, this solution does ECMP routing for egress traffic. The routes are learned from the BGP speaker the node peers with. There are dedicated OVS bridges per each peer link.\n\nThe spec might be confusing at this point and probably the diagram should be updated. The goal is that if you have a neutron provider network - similarly to the Public LS in the diagram - it will advertise all host routes for the VMs plugged directly in that LS/network - just like ovn-bgp-agent does.\n\nI hope it answers your questions, if you have more, feel free to reach out.","commit_id":"590afafc5306e414492503a7c06fef476d41a5da"},{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"583016941721b636aead5c74ad3f73dcc73305cc","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"c87c1e11_aada1ac8","updated":"2026-02-27 17:20:00.000000000","message":"Mostly just some semi-nitty \"bundle multiple execute() calls into single transactions\" etc. I haven\u0027t yet tracked down what was happening with the functional test failure at https://storage.gra.cloud.ovh.net/v1/AUTH_dcaab5e32b234d56b626f72581e3644c/zuul_opendev_logs_1a1/openstack/1a1d266f2dae4389a579637180d4b1fd/testr_results.html","commit_id":"422c76f6d871d7d20c68a299bac3015ebaafec77"},{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"b42721342814977c5eb2dab054c14885dcd7f703","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"45471308_6f4f6896","updated":"2026-03-03 20:48:05.000000000","message":"recheck possibly related to uncomfirmed bug 2131694","commit_id":"dc571c192f565759bd95030a4a729ee9b966acdb"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"b354e16e8823996cc16a917f24b5bb88955cd613","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":8,"id":"12428448_09f5403e","updated":"2026-03-09 19:11:05.000000000","message":"recheck OVS mech driver tempest failure","commit_id":"0a1fb53097dca5811b95c426b5cb1755ad8278fe"}],"neutron/services/bgp/commands.py":[{"author":{"_account_id":34271,"name":"Miro Tomaska","display_name":"Miro Tomaska","email":"mtomaska@redhat.com","username":"mtomaska"},"change_message_id":"512d700c9108bef1a640b91e83379da75c6d1dbd","unresolved":true,"context_lines":[{"line_number":71,"context_line":"    gw_ips \u003d ["},{"line_number":72,"context_line":"        gw_ip for dhcp_opt in nb_idl.tables[\u0027DHCP_Options\u0027].rows.values()"},{"line_number":73,"context_line":"        if dhcp_opt.external_ids.get("},{"line_number":74,"context_line":"            ovn_const.OVN_NETWORK_ID_EXT_ID_KEY) \u003d\u003d n_net_id and"},{"line_number":75,"context_line":"        (gw_ip :\u003d helpers.get_gw_ip_from_dhcp_options(dhcp_opt)) is not None]"},{"line_number":76,"context_line":"    LOG.debug(\"For logical switch %s, found gateway IPs: %s\","},{"line_number":77,"context_line":"              switch.name, gw_ips)"}],"source_content_type":"text/x-python","patch_set":7,"id":"0cc5806d_739f5fe5","line":74,"range":{"start_line":74,"start_character":22,"end_line":74,"end_character":47},"updated":"2026-03-02 21:34:45.000000000","message":"At what point do we store store `neutron:network_id` in `external_ids` on a DHCP_options record? I only see `subnet_id` stored there for which that DHCP option is applied.","commit_id":"dc571c192f565759bd95030a4a729ee9b966acdb"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"20ae7c7eb032a18bfb4bef8334553ee1f0b2965c","unresolved":true,"context_lines":[{"line_number":71,"context_line":"    gw_ips \u003d ["},{"line_number":72,"context_line":"        gw_ip for dhcp_opt in nb_idl.tables[\u0027DHCP_Options\u0027].rows.values()"},{"line_number":73,"context_line":"        if dhcp_opt.external_ids.get("},{"line_number":74,"context_line":"            ovn_const.OVN_NETWORK_ID_EXT_ID_KEY) \u003d\u003d n_net_id and"},{"line_number":75,"context_line":"        (gw_ip :\u003d helpers.get_gw_ip_from_dhcp_options(dhcp_opt)) is not None]"},{"line_number":76,"context_line":"    LOG.debug(\"For logical switch %s, found gateway IPs: %s\","},{"line_number":77,"context_line":"              switch.name, gw_ips)"}],"source_content_type":"text/x-python","patch_set":7,"id":"39d06efd_f5888aca","line":74,"range":{"start_line":74,"start_character":22,"end_line":74,"end_character":47},"in_reply_to":"0cc5806d_739f5fe5","updated":"2026-03-03 12:58:55.000000000","message":"https://review.opendev.org/c/openstack/neutron/+/976692","commit_id":"dc571c192f565759bd95030a4a729ee9b966acdb"},{"author":{"_account_id":34271,"name":"Miro Tomaska","display_name":"Miro Tomaska","email":"mtomaska@redhat.com","username":"mtomaska"},"change_message_id":"a016e910f10c88a3e2bf22ebb85f440e3e2640de","unresolved":false,"context_lines":[{"line_number":71,"context_line":"    gw_ips \u003d ["},{"line_number":72,"context_line":"        gw_ip for dhcp_opt in nb_idl.tables[\u0027DHCP_Options\u0027].rows.values()"},{"line_number":73,"context_line":"        if dhcp_opt.external_ids.get("},{"line_number":74,"context_line":"            ovn_const.OVN_NETWORK_ID_EXT_ID_KEY) \u003d\u003d n_net_id and"},{"line_number":75,"context_line":"        (gw_ip :\u003d helpers.get_gw_ip_from_dhcp_options(dhcp_opt)) is not None]"},{"line_number":76,"context_line":"    LOG.debug(\"For logical switch %s, found gateway IPs: %s\","},{"line_number":77,"context_line":"              switch.name, gw_ips)"}],"source_content_type":"text/x-python","patch_set":7,"id":"39d00ceb_f1eff038","line":74,"range":{"start_line":74,"start_character":22,"end_line":74,"end_character":47},"in_reply_to":"39d06efd_f5888aca","updated":"2026-03-03 15:58:18.000000000","message":"Acknowledged","commit_id":"dc571c192f565759bd95030a4a729ee9b966acdb"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"c2c0dc2c6f0df6c2c2c74d2eb50ea9b0d5add132","unresolved":true,"context_lines":[{"line_number":263,"context_line":"    def __init__(self, api, interconnect_switch_name, related_resource\u003dNone):"},{"line_number":264,"context_line":"        super().__init__(api)"},{"line_number":265,"context_line":"        self.interconnect_switch_name \u003d interconnect_switch_name"},{"line_number":266,"context_line":"        self.router \u003d _get_main_router(api)"},{"line_number":267,"context_line":"        self.related_resource \u003d related_resource"},{"line_number":268,"context_line":""},{"line_number":269,"context_line":"    def run_idl(self, txn):"}],"source_content_type":"text/x-python","patch_set":7,"id":"0d71fa93_172d4ed2","line":266,"updated":"2026-03-03 20:43:55.000000000","message":"This is not within a transaction","commit_id":"dc571c192f565759bd95030a4a729ee9b966acdb"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"942e8da397e5528ca1c8bfc2340db18296c5c189","unresolved":false,"context_lines":[{"line_number":263,"context_line":"    def __init__(self, api, interconnect_switch_name, related_resource\u003dNone):"},{"line_number":264,"context_line":"        super().__init__(api)"},{"line_number":265,"context_line":"        self.interconnect_switch_name \u003d interconnect_switch_name"},{"line_number":266,"context_line":"        self.router \u003d _get_main_router(api)"},{"line_number":267,"context_line":"        self.related_resource \u003d related_resource"},{"line_number":268,"context_line":""},{"line_number":269,"context_line":"    def run_idl(self, txn):"}],"source_content_type":"text/x-python","patch_set":7,"id":"9b9a4324_9f16e049","line":266,"in_reply_to":"0d71fa93_172d4ed2","updated":"2026-03-03 22:10:38.000000000","message":"Done","commit_id":"dc571c192f565759bd95030a4a729ee9b966acdb"},{"author":{"_account_id":34271,"name":"Miro Tomaska","display_name":"Miro Tomaska","email":"mtomaska@redhat.com","username":"mtomaska"},"change_message_id":"512d700c9108bef1a640b91e83379da75c6d1dbd","unresolved":true,"context_lines":[{"line_number":351,"context_line":"        fake_lrp \u003d _run_idl_command(_LrpAddCommand("},{"line_number":352,"context_line":"            self.api,"},{"line_number":353,"context_line":"            self.router,"},{"line_number":354,"context_line":"            f\u0027{self.router}-dead-lrp\u0027,"},{"line_number":355,"context_line":"            may_exist\u003dTrue,"},{"line_number":356,"context_line":"        ), txn)"},{"line_number":357,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"2e9567a1_b12c41ac","line":354,"range":{"start_line":354,"start_character":28,"end_line":354,"end_character":32},"updated":"2026-03-02 21:34:45.000000000","message":"nit: Can this be more descriptive than \u0027dead\u0027 because to me \u0027dead\u0027 does not serve any purpose. Although I dont have any better name (naming is hard :) )\nMaybe: `-tunnel-route-lrp` or `-to-pass-route-lrp`","commit_id":"dc571c192f565759bd95030a4a729ee9b966acdb"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"20ae7c7eb032a18bfb4bef8334553ee1f0b2965c","unresolved":true,"context_lines":[{"line_number":351,"context_line":"        fake_lrp \u003d _run_idl_command(_LrpAddCommand("},{"line_number":352,"context_line":"            self.api,"},{"line_number":353,"context_line":"            self.router,"},{"line_number":354,"context_line":"            f\u0027{self.router}-dead-lrp\u0027,"},{"line_number":355,"context_line":"            may_exist\u003dTrue,"},{"line_number":356,"context_line":"        ), txn)"},{"line_number":357,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"651cf743_3e7213c2","line":354,"range":{"start_line":354,"start_character":28,"end_line":354,"end_character":32},"in_reply_to":"2e9567a1_b12c41ac","updated":"2026-03-03 12:58:55.000000000","message":"I like \u0027dead\u0027 as in the sense it has no live traffic. I would not guess that from your names - I\u0027m open for a better naming, or maybe we can document it somewhere?","commit_id":"dc571c192f565759bd95030a4a729ee9b966acdb"},{"author":{"_account_id":34271,"name":"Miro Tomaska","display_name":"Miro Tomaska","email":"mtomaska@redhat.com","username":"mtomaska"},"change_message_id":"38bbb37dbb33f232b93587e01b3c529a3b55e83d","unresolved":false,"context_lines":[{"line_number":351,"context_line":"        fake_lrp \u003d _run_idl_command(_LrpAddCommand("},{"line_number":352,"context_line":"            self.api,"},{"line_number":353,"context_line":"            self.router,"},{"line_number":354,"context_line":"            f\u0027{self.router}-dead-lrp\u0027,"},{"line_number":355,"context_line":"            may_exist\u003dTrue,"},{"line_number":356,"context_line":"        ), txn)"},{"line_number":357,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"3aa1508e_b63f0df5","line":354,"range":{"start_line":354,"start_character":28,"end_line":354,"end_character":32},"in_reply_to":"651cf743_3e7213c2","updated":"2026-03-05 13:59:33.000000000","message":"I dont feel strongly about not going with `dead` if you like it over my suggestions then it is fine with me","commit_id":"dc571c192f565759bd95030a4a729ee9b966acdb"},{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"32f07476b11c73efb735aa279a4173c63afc8a91","unresolved":true,"context_lines":[{"line_number":272,"context_line":"        for lrp in helpers.lrps_to_chassis_routers(router):"},{"line_number":273,"context_line":"            ReconcileMainRouterPoliciesCommand("},{"line_number":274,"context_line":"                self.api,"},{"line_number":275,"context_line":"                router,"},{"line_number":276,"context_line":"                lrp_interconnect_name,"},{"line_number":277,"context_line":"                lrp,"},{"line_number":278,"context_line":"                self.related_resource,"}],"source_content_type":"text/x-python","patch_set":8,"id":"3e39acbe_a0a2efc3","line":275,"updated":"2026-03-03 22:28:35.000000000","message":"If we pass the router here, that means that the `ReconcileMainRouterPoliciesCommand` basically has the same issue--it\u0027s storing an object that could conceivably come from outside a txn, though in this case it doesn\u0027t. If we\u0027re trying to treat all Commands here as though they could be called from an outside API call, then it\u0027ll need to be changed to take a name instead of a router as well (or do the lookup w/o having it passed since it\u0027s the main router, just like here)","commit_id":"0a1fb53097dca5811b95c426b5cb1755ad8278fe"},{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"16f33f7d661667bbfc3b4dba98bd5375824aaa49","unresolved":true,"context_lines":[{"line_number":272,"context_line":"        for lrp in helpers.lrps_to_chassis_routers(router):"},{"line_number":273,"context_line":"            ReconcileMainRouterPoliciesCommand("},{"line_number":274,"context_line":"                self.api,"},{"line_number":275,"context_line":"                router,"},{"line_number":276,"context_line":"                lrp_interconnect_name,"},{"line_number":277,"context_line":"                lrp,"},{"line_number":278,"context_line":"                self.related_resource,"}],"source_content_type":"text/x-python","patch_set":8,"id":"e9edfcaa_a869fbc3","line":275,"in_reply_to":"3e39acbe_a0a2efc3","updated":"2026-03-04 19:43:52.000000000","message":"Note, it\u0027s perfectly fine to optimize the commands to store Rows when you know that is safe, e.g. when the Command is instantiated from another Command.run_idl() that is run while the txn is being processed, or if the object stored is a frozen_row from an event, etc.\n\nThis is just pointing out that the previous change which moved the lookup() to inside run_idl() was changing something that is fundamentally similar to this code as well. If an object takes a Row and stores it, a lookup() outside the current txn to create that row is possible (but, not necessarily happening and probably isn\u0027t going to the way you are using your commands).","commit_id":"0a1fb53097dca5811b95c426b5cb1755ad8278fe"},{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"316861d32af32ec4c7273582e41fc2091c3d60d1","unresolved":false,"context_lines":[{"line_number":272,"context_line":"        for lrp in helpers.lrps_to_chassis_routers(router):"},{"line_number":273,"context_line":"            ReconcileMainRouterPoliciesCommand("},{"line_number":274,"context_line":"                self.api,"},{"line_number":275,"context_line":"                router,"},{"line_number":276,"context_line":"                lrp_interconnect_name,"},{"line_number":277,"context_line":"                lrp,"},{"line_number":278,"context_line":"                self.related_resource,"}],"source_content_type":"text/x-python","patch_set":8,"id":"5b786e46_f6a1a65c","line":275,"in_reply_to":"e9edfcaa_a869fbc3","updated":"2026-03-06 17:40:42.000000000","message":"Done","commit_id":"0a1fb53097dca5811b95c426b5cb1755ad8278fe"}],"neutron/services/bgp/constants.py":[{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"583016941721b636aead5c74ad3f73dcc73305cc","unresolved":true,"context_lines":[{"line_number":35,"context_line":""},{"line_number":36,"context_line":"BGP_BRIDGE_NIC_TYPES \u003d (\u0027\u0027, \u0027system\u0027)"},{"line_number":37,"context_line":""},{"line_number":38,"context_line":"PROVIDER_NETWORK_TYPES \u003d [n_lib_const.TYPE_FLAT, n_lib_const.TYPE_VLAN]"},{"line_number":39,"context_line":""},{"line_number":40,"context_line":"BGP_LRP_TO_CHASSIS \u003d \u0027neutron-bgp-lrp-to-chassis-router\u0027"},{"line_number":41,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"a7b082e2_40ce4fde","line":38,"updated":"2026-02-27 17:20:00.000000000","message":"No geneve provider networks? If phsyical networks, there is n_lib_const.TYPE_PHYSICAL which equals these two.","commit_id":"422c76f6d871d7d20c68a299bac3015ebaafec77"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"abb8bb5a6b62d0cb0fb01fb1eb3b47e62a3112b9","unresolved":false,"context_lines":[{"line_number":35,"context_line":""},{"line_number":36,"context_line":"BGP_BRIDGE_NIC_TYPES \u003d (\u0027\u0027, \u0027system\u0027)"},{"line_number":37,"context_line":""},{"line_number":38,"context_line":"PROVIDER_NETWORK_TYPES \u003d [n_lib_const.TYPE_FLAT, n_lib_const.TYPE_VLAN]"},{"line_number":39,"context_line":""},{"line_number":40,"context_line":"BGP_LRP_TO_CHASSIS \u003d \u0027neutron-bgp-lrp-to-chassis-router\u0027"},{"line_number":41,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"8a8e4c3b_75c30d59","line":38,"in_reply_to":"a7b082e2_40ce4fde","updated":"2026-03-02 20:04:51.000000000","message":"Done","commit_id":"422c76f6d871d7d20c68a299bac3015ebaafec77"}],"neutron/services/bgp/helpers.py":[{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"583016941721b636aead5c74ad3f73dcc73305cc","unresolved":true,"context_lines":[{"line_number":149,"context_line":"def get_gw_ips_for_switch(nb_idl, switch):"},{"line_number":150,"context_line":"    n_net_id \u003d get_neutron_id_from_ovn_name(switch)"},{"line_number":151,"context_line":"    gw_ips \u003d ["},{"line_number":152,"context_line":"        gw_ip for dhcp_opt in nb_idl.tables[\u0027DHCP_Options\u0027].rows.values()"},{"line_number":153,"context_line":"        if dhcp_opt.external_ids.get("},{"line_number":154,"context_line":"            ovn_const.OVN_NETWORK_ID_EXT_ID_KEY) \u003d\u003d n_net_id and"},{"line_number":155,"context_line":"        (gw_ip :\u003d get_gw_ip_with_cidr(dhcp_opt)) is not None]"}],"source_content_type":"text/x-python","patch_set":4,"id":"2045fc8b_4e8800ad","line":152,"range":{"start_line":152,"start_character":0,"end_line":152,"end_character":73},"updated":"2026-02-27 17:20:00.000000000","message":"I\u0027m still working through exactly how I feel about this.\n\nOn one hand, we shouldn\u0027t generally access \u0027tables\u0027 directly outside of Command objects. On the other hand, a lot of the methods in here are only used in Command objects. But there\u0027s also no way to really ensure that is the case--and in this particular case, the method is also used in test code (unlike, for example `get_all_provider_switches()`).\n\nIdeally, I think the methods listed in helpers.py, if they are intended only to be used by Command code should just be located in commands.py. I get that it\u0027s annoying that the way you would execute the method from inside a command is entirely different than how you\u0027d do it for public consumption (e.g. using txns which you wouldn\u0027t use in Command-related code).","commit_id":"422c76f6d871d7d20c68a299bac3015ebaafec77"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"abb8bb5a6b62d0cb0fb01fb1eb3b47e62a3112b9","unresolved":false,"context_lines":[{"line_number":149,"context_line":"def get_gw_ips_for_switch(nb_idl, switch):"},{"line_number":150,"context_line":"    n_net_id \u003d get_neutron_id_from_ovn_name(switch)"},{"line_number":151,"context_line":"    gw_ips \u003d ["},{"line_number":152,"context_line":"        gw_ip for dhcp_opt in nb_idl.tables[\u0027DHCP_Options\u0027].rows.values()"},{"line_number":153,"context_line":"        if dhcp_opt.external_ids.get("},{"line_number":154,"context_line":"            ovn_const.OVN_NETWORK_ID_EXT_ID_KEY) \u003d\u003d n_net_id and"},{"line_number":155,"context_line":"        (gw_ip :\u003d get_gw_ip_with_cidr(dhcp_opt)) is not None]"}],"source_content_type":"text/x-python","patch_set":4,"id":"7b9d76d4_92b9b65b","line":152,"range":{"start_line":152,"start_character":0,"end_line":152,"end_character":73},"in_reply_to":"2045fc8b_4e8800ad","updated":"2026-03-02 20:04:51.000000000","message":"I think it\u0027s a great idea to put it to commands.py and make them \"module private\", thanks!","commit_id":"422c76f6d871d7d20c68a299bac3015ebaafec77"}],"neutron/tests/functional/services/bgp/test_commands.py":[{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"583016941721b636aead5c74ad3f73dcc73305cc","unresolved":true,"context_lines":[{"line_number":918,"context_line":"                addresses\u003d[\u0027unknown\u0027]"},{"line_number":919,"context_line":"            ))"},{"line_number":920,"context_line":""},{"line_number":921,"context_line":"        return self.nb_api.ls_get(ls_name).execute(check_error\u003dTrue)"},{"line_number":922,"context_line":""},{"line_number":923,"context_line":""},{"line_number":924,"context_line":"class ReconcileNeutronSwitchCommandTestCase(_BaseNeutronSwitchCommandTestCase):"}],"source_content_type":"text/x-python","patch_set":4,"id":"07203880_df4b7e45","line":921,"updated":"2026-02-27 17:20:00.000000000","message":"nittiest of nits: Just as an FYI, you can do something like\n\n```\nwith self.nb_api.transaction() as txn:\n    ls \u003d txn.add(self.nb_api.ls_add(ls_name))\n...\nreturn ls.result\n```\n\nto avoid the second lookup.","commit_id":"422c76f6d871d7d20c68a299bac3015ebaafec77"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"abb8bb5a6b62d0cb0fb01fb1eb3b47e62a3112b9","unresolved":false,"context_lines":[{"line_number":918,"context_line":"                addresses\u003d[\u0027unknown\u0027]"},{"line_number":919,"context_line":"            ))"},{"line_number":920,"context_line":""},{"line_number":921,"context_line":"        return self.nb_api.ls_get(ls_name).execute(check_error\u003dTrue)"},{"line_number":922,"context_line":""},{"line_number":923,"context_line":""},{"line_number":924,"context_line":"class ReconcileNeutronSwitchCommandTestCase(_BaseNeutronSwitchCommandTestCase):"}],"source_content_type":"text/x-python","patch_set":4,"id":"ee1d4e9e_f156af09","line":921,"in_reply_to":"07203880_df4b7e45","updated":"2026-03-02 20:04:51.000000000","message":"Done","commit_id":"422c76f6d871d7d20c68a299bac3015ebaafec77"},{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"583016941721b636aead5c74ad3f73dcc73305cc","unresolved":false,"context_lines":[{"line_number":964,"context_line":"        network_name \u003d \u0027provider-net\u0027"},{"line_number":965,"context_line":"        n_switch \u003d self._create_neutron_switch_with_localnet(network_name, [])"},{"line_number":966,"context_line":""},{"line_number":967,"context_line":"        commands.ReconcileNeutronSwitchCommand("},{"line_number":968,"context_line":"            self.nb_api, n_switch"},{"line_number":969,"context_line":"        ).execute(check_error\u003dTrue)"},{"line_number":970,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"f7f14871_fcba48a6","line":967,"updated":"2026-02-27 17:20:00.000000000","message":"For some reason it took until right here where I realized, even though it is not related to these internally-used-only commands, that the normal ovsdbapp usage would be to define an Api class that defines the public interface to your app. For BGP extension I think that would just be the outermost commands which are called from `reconciler.py` (though there would be nothing wrong with adding API definition for the others if you thought it would help if ever having to adopt a different backend that may never exist :p) Marking resolved since that wouldn\u0027t be part of this patch.","commit_id":"422c76f6d871d7d20c68a299bac3015ebaafec77"},{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"583016941721b636aead5c74ad3f73dcc73305cc","unresolved":true,"context_lines":[{"line_number":1038,"context_line":"        self.main_router \u003d self.nb_api.lr_get("},{"line_number":1039,"context_line":"            self.main_router_name).execute(check_error\u003dTrue)"},{"line_number":1040,"context_line":""},{"line_number":1041,"context_line":"    def _create_chassis_lrp(self):"},{"line_number":1042,"context_line":"        chassis_router_name \u003d _get_unique_name(\u0027chassis-lr\u0027)"},{"line_number":1043,"context_line":"        self.nb_api.lr_add(chassis_router_name).execute(check_error\u003dTrue)"},{"line_number":1044,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"bd926ee2_83401a42","line":1041,"updated":"2026-02-27 17:20:00.000000000","message":"another nitty example of using cmd.result and bundling multiple cmds in a single transaction:\n```\n    def _create_chassis_lrp(self):\n        chassis_router_name \u003d _get_unique_name(\u0027chassis-lr\u0027)\n        lrp_main_name \u003d helpers.get_lrp_name(\n            self.main_router_name, chassis_router_name)\n        lrp_chassis_name \u003d helpers.get_lrp_name(\n            chassis_router_name, self.main_router_name)\n\n        with self.nb_api.transaction(check_error\u003dTrue) as txn:\n            txn.add(self.nb_api.lr_add(chassis_router_name))\n            txn.add(self.nb_api.lrp_add(\n                chassis_router_name, lrp_chassis_name,\n                mac\u003dhelpers.get_mac_address_from_lrp_name(lrp_chassis_name),\n                networks\u003d[\u002710.0.0.1/30\u0027],\n                peer\u003dlrp_main_name))\n            lrp \u003d txn.add(self.nb_api.lrp_add(\n                self.main_router_name, lrp_main_name,\n                mac\u003dhelpers.get_mac_address_from_lrp_name(lrp_main_name),\n                networks\u003d[\u002710.0.0.2/30\u0027],\n                peer\u003dlrp_chassis_name,\n                external_ids\u003d{constants.BGP_LRP_TO_CHASSIS:\n                              chassis_router_name}))\n\n        return lrp.result\n```","commit_id":"422c76f6d871d7d20c68a299bac3015ebaafec77"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"abb8bb5a6b62d0cb0fb01fb1eb3b47e62a3112b9","unresolved":false,"context_lines":[{"line_number":1038,"context_line":"        self.main_router \u003d self.nb_api.lr_get("},{"line_number":1039,"context_line":"            self.main_router_name).execute(check_error\u003dTrue)"},{"line_number":1040,"context_line":""},{"line_number":1041,"context_line":"    def _create_chassis_lrp(self):"},{"line_number":1042,"context_line":"        chassis_router_name \u003d _get_unique_name(\u0027chassis-lr\u0027)"},{"line_number":1043,"context_line":"        self.nb_api.lr_add(chassis_router_name).execute(check_error\u003dTrue)"},{"line_number":1044,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"c9388d2f_1d8acbd6","line":1041,"in_reply_to":"bd926ee2_83401a42","updated":"2026-03-02 20:04:51.000000000","message":"Done","commit_id":"422c76f6d871d7d20c68a299bac3015ebaafec77"},{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"583016941721b636aead5c74ad3f73dcc73305cc","unresolved":true,"context_lines":[{"line_number":1166,"context_line":"        commands.ReconcileMainRouterCommand("},{"line_number":1167,"context_line":"            self.nb_api).execute(check_error\u003dTrue)"},{"line_number":1168,"context_line":""},{"line_number":1169,"context_line":"    def _create_chassis_lrp(self, chassis_name\u003dNone):"},{"line_number":1170,"context_line":"        chassis_router_name \u003d chassis_name or _get_unique_name(\u0027chassis-lr\u0027)"},{"line_number":1171,"context_line":"        self.nb_api.lr_add(chassis_router_name).execute(check_error\u003dTrue)"},{"line_number":1172,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"1cf6c919_3c379e7a","line":1169,"updated":"2026-02-27 17:20:00.000000000","message":"This looks exactly duplicated from ReconcileMainRouterPoliciesCommandTestCase, except for the first line that provides an override for the chassis_name.","commit_id":"422c76f6d871d7d20c68a299bac3015ebaafec77"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"abb8bb5a6b62d0cb0fb01fb1eb3b47e62a3112b9","unresolved":false,"context_lines":[{"line_number":1166,"context_line":"        commands.ReconcileMainRouterCommand("},{"line_number":1167,"context_line":"            self.nb_api).execute(check_error\u003dTrue)"},{"line_number":1168,"context_line":""},{"line_number":1169,"context_line":"    def _create_chassis_lrp(self, chassis_name\u003dNone):"},{"line_number":1170,"context_line":"        chassis_router_name \u003d chassis_name or _get_unique_name(\u0027chassis-lr\u0027)"},{"line_number":1171,"context_line":"        self.nb_api.lr_add(chassis_router_name).execute(check_error\u003dTrue)"},{"line_number":1172,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"c83414e9_268868fb","line":1169,"in_reply_to":"1cf6c919_3c379e7a","updated":"2026-03-02 20:04:51.000000000","message":"Done","commit_id":"422c76f6d871d7d20c68a299bac3015ebaafec77"}],"neutron/tests/functional/services/bgp/test_helpers.py":[{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"583016941721b636aead5c74ad3f73dcc73305cc","unresolved":true,"context_lines":[{"line_number":32,"context_line":"            options\u003doptions,"},{"line_number":33,"context_line":"            external_ids\u003d{ovn_const.OVN_NETWORK_ID_EXT_ID_KEY: net_id},"},{"line_number":34,"context_line":"        )"},{"line_number":35,"context_line":"        with self.nb_api.transaction(check_error\u003dTrue) as txn:"},{"line_number":36,"context_line":"            txn.add(cmd)"},{"line_number":37,"context_line":""},{"line_number":38,"context_line":"    def test_get_gw_ips_for_switch_returns_empty_when_no_dhcp_options(self):"}],"source_content_type":"text/x-python","patch_set":4,"id":"a591f938_0b78584d","line":35,"updated":"2026-02-27 17:20:00.000000000","message":"If it were me, I\u0027d probably return the cmd, then all of the places below that use multiple execute() calls, I\u0027d do single txns and w/ `txn.add(self._add_dhcp_options(...))`","commit_id":"422c76f6d871d7d20c68a299bac3015ebaafec77"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"abb8bb5a6b62d0cb0fb01fb1eb3b47e62a3112b9","unresolved":false,"context_lines":[{"line_number":32,"context_line":"            options\u003doptions,"},{"line_number":33,"context_line":"            external_ids\u003d{ovn_const.OVN_NETWORK_ID_EXT_ID_KEY: net_id},"},{"line_number":34,"context_line":"        )"},{"line_number":35,"context_line":"        with self.nb_api.transaction(check_error\u003dTrue) as txn:"},{"line_number":36,"context_line":"            txn.add(cmd)"},{"line_number":37,"context_line":""},{"line_number":38,"context_line":"    def test_get_gw_ips_for_switch_returns_empty_when_no_dhcp_options(self):"}],"source_content_type":"text/x-python","patch_set":4,"id":"bb7801a6_9c4bbcb2","line":35,"in_reply_to":"a591f938_0b78584d","updated":"2026-03-02 20:04:51.000000000","message":"With you being you the code gets a lot better.","commit_id":"422c76f6d871d7d20c68a299bac3015ebaafec77"},{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"583016941721b636aead5c74ad3f73dcc73305cc","unresolved":true,"context_lines":[{"line_number":50,"context_line":"        ls_name \u003d f\"neutron-{net_id}\""},{"line_number":51,"context_line":"        self.nb_api.ls_add(ls_name).execute(check_error\u003dTrue)"},{"line_number":52,"context_line":"        self._add_dhcp_options(net_id, \u002710.0.0.0/24\u0027, \u002710.0.0.5\u0027)"},{"line_number":53,"context_line":"        switch \u003d self.nb_api.lookup(\u0027Logical_Switch\u0027, ls_name)"},{"line_number":54,"context_line":""},{"line_number":55,"context_line":"        gw_ips \u003d helpers.get_gw_ips_for_switch(self.nb_api, switch)"},{"line_number":56,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"d72c23df_5ac2f0b4","line":53,"updated":"2026-02-27 17:20:00.000000000","message":"as an example, if the _add_dhcp_options change was made and this was a txn block, switch could be assigned the return of `txn.add(ls_add())`, and switch.result could be used instead of a lookup here and below.","commit_id":"422c76f6d871d7d20c68a299bac3015ebaafec77"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"abb8bb5a6b62d0cb0fb01fb1eb3b47e62a3112b9","unresolved":false,"context_lines":[{"line_number":50,"context_line":"        ls_name \u003d f\"neutron-{net_id}\""},{"line_number":51,"context_line":"        self.nb_api.ls_add(ls_name).execute(check_error\u003dTrue)"},{"line_number":52,"context_line":"        self._add_dhcp_options(net_id, \u002710.0.0.0/24\u0027, \u002710.0.0.5\u0027)"},{"line_number":53,"context_line":"        switch \u003d self.nb_api.lookup(\u0027Logical_Switch\u0027, ls_name)"},{"line_number":54,"context_line":""},{"line_number":55,"context_line":"        gw_ips \u003d helpers.get_gw_ips_for_switch(self.nb_api, switch)"},{"line_number":56,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"77431cdc_edeef25f","line":53,"in_reply_to":"d72c23df_5ac2f0b4","updated":"2026-03-02 20:04:51.000000000","message":"Done","commit_id":"422c76f6d871d7d20c68a299bac3015ebaafec77"}]}
