)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"e0964c0c29b46df436d33faca67a00408f9f8b98","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"5970f143_d6b4dcd8","updated":"2026-05-05 14:48:06.000000000","message":"The agent extension looks good to me.","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":38298,"name":"Helen Chen","display_name":"Helen Chen","email":"ichen@redhat.com","username":"ingwherchen"},"change_message_id":"7f7a70ad93a89ab4bddf4b775c4247670e2f9a8d","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":11,"id":"6a43ae49_22c68183","updated":"2026-05-08 13:05:53.000000000","message":"recheck due to server creation timeout","commit_id":"78f5e39812e2596121cea62cf5672cf4f33664ab"}],"neutron/agent/linux/nl_dispatcher.py":[{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"1531de87d23f09de284f6133c884a28d787fe62b","unresolved":true,"context_lines":[{"line_number":87,"context_line":"                        LOG.warning(\"Netlink receive buffer overrun, \""},{"line_number":88,"context_line":"                                    \"re-dumping\")"},{"line_number":89,"context_line":"                        self._dump_existing()"},{"line_number":90,"context_line":"                    else:"},{"line_number":91,"context_line":"                        LOG.debug(\"Transient netlink error, retrying\")"},{"line_number":92,"context_line":"        except Exception:"},{"line_number":93,"context_line":"            LOG.exception(\"NetlinkDispatcher crashed\")"},{"line_number":94,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"095a59b5_9473287b","line":91,"range":{"start_line":90,"start_character":0,"end_line":91,"end_character":70},"updated":"2026-04-20 13:38:45.000000000","message":"We must not swallow the raised error here","commit_id":"df21c80008b059c97e59f6806006ba9b2a4484d8"},{"author":{"_account_id":38298,"name":"Helen Chen","display_name":"Helen Chen","email":"ichen@redhat.com","username":"ingwherchen"},"change_message_id":"b98b2fcc0278312cfbb6916e79a78925276facb3","unresolved":false,"context_lines":[{"line_number":87,"context_line":"                        LOG.warning(\"Netlink receive buffer overrun, \""},{"line_number":88,"context_line":"                                    \"re-dumping\")"},{"line_number":89,"context_line":"                        self._dump_existing()"},{"line_number":90,"context_line":"                    else:"},{"line_number":91,"context_line":"                        LOG.debug(\"Transient netlink error, retrying\")"},{"line_number":92,"context_line":"        except Exception:"},{"line_number":93,"context_line":"            LOG.exception(\"NetlinkDispatcher crashed\")"},{"line_number":94,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"f8ebc591_4863aa53","line":91,"range":{"start_line":90,"start_character":0,"end_line":91,"end_character":70},"in_reply_to":"095a59b5_9473287b","updated":"2026-05-04 14:48:20.000000000","message":"Done","commit_id":"df21c80008b059c97e59f6806006ba9b2a4484d8"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"1531de87d23f09de284f6133c884a28d787fe62b","unresolved":true,"context_lines":[{"line_number":91,"context_line":"                        LOG.debug(\"Transient netlink error, retrying\")"},{"line_number":92,"context_line":"        except Exception:"},{"line_number":93,"context_line":"            LOG.exception(\"NetlinkDispatcher crashed\")"},{"line_number":94,"context_line":""},{"line_number":95,"context_line":"    def _dispatch(self, msg):"},{"line_number":96,"context_line":"        \"\"\"Dispatch message to all registered handlers.\"\"\""},{"line_number":97,"context_line":"        for handler in self._handlers:"},{"line_number":98,"context_line":"            handler(msg)"}],"source_content_type":"text/x-python","patch_set":2,"id":"746255b7_e46edafe","line":98,"range":{"start_line":94,"start_character":0,"end_line":98,"end_character":24},"updated":"2026-04-20 13:38:45.000000000","message":"Would there be a reason to not register the handlers per the message type as I suggested in the previous PS?","commit_id":"df21c80008b059c97e59f6806006ba9b2a4484d8"},{"author":{"_account_id":38298,"name":"Helen Chen","display_name":"Helen Chen","email":"ichen@redhat.com","username":"ingwherchen"},"change_message_id":"b98b2fcc0278312cfbb6916e79a78925276facb3","unresolved":false,"context_lines":[{"line_number":91,"context_line":"                        LOG.debug(\"Transient netlink error, retrying\")"},{"line_number":92,"context_line":"        except Exception:"},{"line_number":93,"context_line":"            LOG.exception(\"NetlinkDispatcher crashed\")"},{"line_number":94,"context_line":""},{"line_number":95,"context_line":"    def _dispatch(self, msg):"},{"line_number":96,"context_line":"        \"\"\"Dispatch message to all registered handlers.\"\"\""},{"line_number":97,"context_line":"        for handler in self._handlers:"},{"line_number":98,"context_line":"            handler(msg)"}],"source_content_type":"text/x-python","patch_set":2,"id":"c43d6d53_9638f844","line":98,"range":{"start_line":94,"start_character":0,"end_line":98,"end_character":24},"in_reply_to":"746255b7_e46edafe","updated":"2026-05-04 14:48:20.000000000","message":"Done","commit_id":"df21c80008b059c97e59f6806006ba9b2a4484d8"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"e0964c0c29b46df436d33faca67a00408f9f8b98","unresolved":true,"context_lines":[{"line_number":73,"context_line":""},{"line_number":74,"context_line":"    def _dispatch(self, msg):"},{"line_number":75,"context_line":"        \"\"\"Dispatch message to the handler registered for its type.\"\"\""},{"line_number":76,"context_line":"        handler \u003d self._handlers.get(msg.get(\u0027event\u0027))"},{"line_number":77,"context_line":"        if handler:"},{"line_number":78,"context_line":"            handler(msg)"},{"line_number":79,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"432aa5a3_df6c0645","line":76,"range":{"start_line":76,"start_character":33,"end_line":76,"end_character":36},"updated":"2026-05-05 14:48:06.000000000","message":"Why do we need to call `get()` and the check right away? Can we just use KeyError if the message has no registered handler?","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":38298,"name":"Helen Chen","display_name":"Helen Chen","email":"ichen@redhat.com","username":"ingwherchen"},"change_message_id":"1505a4027509b4bcb776a1cc3286ef9a223643d5","unresolved":false,"context_lines":[{"line_number":73,"context_line":""},{"line_number":74,"context_line":"    def _dispatch(self, msg):"},{"line_number":75,"context_line":"        \"\"\"Dispatch message to the handler registered for its type.\"\"\""},{"line_number":76,"context_line":"        handler \u003d self._handlers.get(msg.get(\u0027event\u0027))"},{"line_number":77,"context_line":"        if handler:"},{"line_number":78,"context_line":"            handler(msg)"},{"line_number":79,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"46510e17_b9983d24","line":76,"range":{"start_line":76,"start_character":33,"end_line":76,"end_character":36},"in_reply_to":"432aa5a3_df6c0645","updated":"2026-05-07 14:44:40.000000000","message":"Done","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"e0964c0c29b46df436d33faca67a00408f9f8b98","unresolved":true,"context_lines":[{"line_number":98,"context_line":"                            LOG.error(\"Netlink socket error: %s, \""},{"line_number":99,"context_line":"                                      \"giving up after %d retries\","},{"line_number":100,"context_line":"                                      e, retries)"},{"line_number":101,"context_line":"                            break"},{"line_number":102,"context_line":"                        LOG.error(\"Netlink socket error: %s, \""},{"line_number":103,"context_line":"                                  \"reopening in %d seconds \""},{"line_number":104,"context_line":"                                  \"(retry %d/%d)\", e, self.RETRY_BACKOFF,"}],"source_content_type":"text/x-python","patch_set":6,"id":"680c7a70_2b4d6d45","line":101,"updated":"2026-05-05 14:48:06.000000000","message":"So in case of we run out of retries, we break here, close the socket but the OVN agent keeps running. What happens to this extension and the netlink monitoring?","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":38298,"name":"Helen Chen","display_name":"Helen Chen","email":"ichen@redhat.com","username":"ingwherchen"},"change_message_id":"1505a4027509b4bcb776a1cc3286ef9a223643d5","unresolved":false,"context_lines":[{"line_number":98,"context_line":"                            LOG.error(\"Netlink socket error: %s, \""},{"line_number":99,"context_line":"                                      \"giving up after %d retries\","},{"line_number":100,"context_line":"                                      e, retries)"},{"line_number":101,"context_line":"                            break"},{"line_number":102,"context_line":"                        LOG.error(\"Netlink socket error: %s, \""},{"line_number":103,"context_line":"                                  \"reopening in %d seconds \""},{"line_number":104,"context_line":"                                  \"(retry %d/%d)\", e, self.RETRY_BACKOFF,"}],"source_content_type":"text/x-python","patch_set":6,"id":"787d8292_e1b90a26","line":101,"in_reply_to":"13dfb8d5_ae94bf30","updated":"2026-05-07 14:44:40.000000000","message":"Updated to retry indefinitely for this error, OSError.\n\nThe thread can still die without killing the OVN agent.","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":38298,"name":"Helen Chen","display_name":"Helen Chen","email":"ichen@redhat.com","username":"ingwherchen"},"change_message_id":"ee3e4ffe676c5f5e23efc7d0de551626ee142262","unresolved":true,"context_lines":[{"line_number":98,"context_line":"                            LOG.error(\"Netlink socket error: %s, \""},{"line_number":99,"context_line":"                                      \"giving up after %d retries\","},{"line_number":100,"context_line":"                                      e, retries)"},{"line_number":101,"context_line":"                            break"},{"line_number":102,"context_line":"                        LOG.error(\"Netlink socket error: %s, \""},{"line_number":103,"context_line":"                                  \"reopening in %d seconds \""},{"line_number":104,"context_line":"                                  \"(retry %d/%d)\", e, self.RETRY_BACKOFF,"}],"source_content_type":"text/x-python","patch_set":6,"id":"13dfb8d5_ae94bf30","line":101,"in_reply_to":"680c7a70_2b4d6d45","updated":"2026-05-06 02:15:59.000000000","message":"The extension exits and the only way to recover is to restart OVN agent (manually).  Can keep retrying or force OVN agent to exit here.","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"}],"neutron/agent/ovn/extensions/bgp/netlink_monitor.py":[{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"2cb3e1f04e0211d69f4183a37f30f73927e3a989","unresolved":true,"context_lines":[{"line_number":25,"context_line":"LOG \u003d log.getLogger(__name__)"},{"line_number":26,"context_line":""},{"line_number":27,"context_line":""},{"line_number":28,"context_line":"class NetlinkMonitor:"},{"line_number":29,"context_line":"    \"\"\"Monitor netlink for EVPN VRF creation and deletion events."},{"line_number":30,"context_line":""},{"line_number":31,"context_line":"    Runs a daemon thread that binds a netlink socket to RTNLGRP_LINK"}],"source_content_type":"text/x-python","patch_set":1,"id":"18a79be2_51ec0b7f","line":28,"range":{"start_line":28,"start_character":6,"end_line":28,"end_character":20},"updated":"2026-04-13 15:47:14.000000000","message":"I think this is a great start. I thought about something more generic rather than tailored for the vrf/bgp use-case.\n\nSo this class would be in some `common` package and it would be used in the BGP agent extension like\n```\nNetlinkMonitor:\n    ...\n    def register_handler(self, msg_type, handler):\n        self._handlers[msg_type].append(handler)\n        \n    def _handle_message(self, msg):\n        \"\"\"Handle link messages based on link type.\"\"\"\n        msg_type \u003d self._link_kind(msg)\n        for msg_handler in self._handlers.get(msg_type, []):\n            msg_handler(msg)\n    ...   \n    \nclass BGPExtension:\n    def __init__(self):\n        ...\n        self.nl_monitor \u003d linux_common.NetlinkMonitor()\n        self.nl_monitor.resgister_handler(self.handle_vrf)\n        self.nl_monitor.start()\n \n    def handle_vrf(self, msg):\n        # Handle the VRF stuff\n```","commit_id":"1fbf69b0b8af095c589e31d03515cb84c6c467b2"},{"author":{"_account_id":38298,"name":"Helen Chen","display_name":"Helen Chen","email":"ichen@redhat.com","username":"ingwherchen"},"change_message_id":"bd5e42adffa6863982b158b3ac919c76af4b1f98","unresolved":false,"context_lines":[{"line_number":25,"context_line":"LOG \u003d log.getLogger(__name__)"},{"line_number":26,"context_line":""},{"line_number":27,"context_line":""},{"line_number":28,"context_line":"class NetlinkMonitor:"},{"line_number":29,"context_line":"    \"\"\"Monitor netlink for EVPN VRF creation and deletion events."},{"line_number":30,"context_line":""},{"line_number":31,"context_line":"    Runs a daemon thread that binds a netlink socket to RTNLGRP_LINK"}],"source_content_type":"text/x-python","patch_set":1,"id":"d4a54887_b1f0433e","line":28,"range":{"start_line":28,"start_character":6,"end_line":28,"end_character":20},"in_reply_to":"18a79be2_51ec0b7f","updated":"2026-05-04 14:48:36.000000000","message":"Done","commit_id":"1fbf69b0b8af095c589e31d03515cb84c6c467b2"}],"neutron/agent/ovn/extensions/evpn/__init__.py":[{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"e0964c0c29b46df436d33faca67a00408f9f8b98","unresolved":true,"context_lines":[{"line_number":15,"context_line":""},{"line_number":16,"context_line":"from oslo_log import log"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"from pyroute2.netlink.rtnl import RTMGRP_LINK"},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"from neutron.agent.linux import nl_dispatcher"},{"line_number":21,"context_line":"from neutron.agent.ovn.extensions.evpn import netlink_monitor"}],"source_content_type":"text/x-python","patch_set":6,"id":"adb005cf_3e7ede7c","line":18,"updated":"2026-05-05 14:48:06.000000000","message":"We should not import objects from modules: https://docs.openstack.org/charm-guide/victoria/coding-guidelines.html#import-ordering-and-style","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":38298,"name":"Helen Chen","display_name":"Helen Chen","email":"ichen@redhat.com","username":"ingwherchen"},"change_message_id":"1505a4027509b4bcb776a1cc3286ef9a223643d5","unresolved":false,"context_lines":[{"line_number":15,"context_line":""},{"line_number":16,"context_line":"from oslo_log import log"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"from pyroute2.netlink.rtnl import RTMGRP_LINK"},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"from neutron.agent.linux import nl_dispatcher"},{"line_number":21,"context_line":"from neutron.agent.ovn.extensions.evpn import netlink_monitor"}],"source_content_type":"text/x-python","patch_set":6,"id":"4fad3294_007af62a","line":18,"in_reply_to":"adb005cf_3e7ede7c","updated":"2026-05-07 14:44:40.000000000","message":"Done","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"e0964c0c29b46df436d33faca67a00408f9f8b98","unresolved":true,"context_lines":[{"line_number":35,"context_line":"        self.nl_dispatcher \u003d nl_dispatcher.NetlinkDispatcher("},{"line_number":36,"context_line":"            RTMGRP_LINK)"},{"line_number":37,"context_line":"        self.nl_dispatcher.register_handler("},{"line_number":38,"context_line":"            \u0027RTM_NEWLINK\u0027, vrf_handler.handle_newlink)"},{"line_number":39,"context_line":"        self.nl_dispatcher.register_handler("},{"line_number":40,"context_line":"            \u0027RTM_DELLINK\u0027, vrf_handler.handle_dellink)"},{"line_number":41,"context_line":"        self.nl_dispatcher.start()"}],"source_content_type":"text/x-python","patch_set":6,"id":"58601be4_f777b773","line":38,"range":{"start_line":38,"start_character":12,"end_line":38,"end_character":25},"updated":"2026-05-05 14:48:06.000000000","message":"Perhaps we shall create constants for these? I know pyroute2 uses strings but would be good to avoid it in Neutron.","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":38298,"name":"Helen Chen","display_name":"Helen Chen","email":"ichen@redhat.com","username":"ingwherchen"},"change_message_id":"1505a4027509b4bcb776a1cc3286ef9a223643d5","unresolved":false,"context_lines":[{"line_number":35,"context_line":"        self.nl_dispatcher \u003d nl_dispatcher.NetlinkDispatcher("},{"line_number":36,"context_line":"            RTMGRP_LINK)"},{"line_number":37,"context_line":"        self.nl_dispatcher.register_handler("},{"line_number":38,"context_line":"            \u0027RTM_NEWLINK\u0027, vrf_handler.handle_newlink)"},{"line_number":39,"context_line":"        self.nl_dispatcher.register_handler("},{"line_number":40,"context_line":"            \u0027RTM_DELLINK\u0027, vrf_handler.handle_dellink)"},{"line_number":41,"context_line":"        self.nl_dispatcher.start()"}],"source_content_type":"text/x-python","patch_set":6,"id":"0e9223c6_94a831e1","line":38,"range":{"start_line":38,"start_character":12,"end_line":38,"end_character":25},"in_reply_to":"58601be4_f777b773","updated":"2026-05-07 14:44:40.000000000","message":"Done","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"}],"neutron/agent/ovn/extensions/evpn/netlink_monitor.py":[{"author":{"_account_id":34271,"name":"Miro Tomaska","display_name":"Miro Tomaska","email":"mtomaska@redhat.com","username":"mtomaska"},"change_message_id":"255cf79b23c3b6d5dd6c9f18f12617c3a94ffcc6","unresolved":true,"context_lines":[{"line_number":48,"context_line":"                    return ifname, int("},{"line_number":49,"context_line":"                        ifname[len(evpn_const.EVPN_VRF_PREFIX):])"},{"line_number":50,"context_line":"                except (ValueError, IndexError):"},{"line_number":51,"context_line":"                    pass"},{"line_number":52,"context_line":"        return None"},{"line_number":53,"context_line":""},{"line_number":54,"context_line":"    def handle_newlink(self, msg):"}],"source_content_type":"text/x-python","patch_set":3,"id":"4fd070a4_ce02bfe9","line":51,"updated":"2026-04-30 02:04:31.000000000","message":"I personally don\u0027t like to `pass` any exception. At least log a warn/info log,\nE.g. `f\"Failed to parse vrf from {ifname}\"`\n\nnit: I dont see how that code would produce an IndexError","commit_id":"944aa7f457f8382f5b991c282e9fb24146ae6a4a"},{"author":{"_account_id":38298,"name":"Helen Chen","display_name":"Helen Chen","email":"ichen@redhat.com","username":"ingwherchen"},"change_message_id":"b98b2fcc0278312cfbb6916e79a78925276facb3","unresolved":false,"context_lines":[{"line_number":48,"context_line":"                    return ifname, int("},{"line_number":49,"context_line":"                        ifname[len(evpn_const.EVPN_VRF_PREFIX):])"},{"line_number":50,"context_line":"                except (ValueError, IndexError):"},{"line_number":51,"context_line":"                    pass"},{"line_number":52,"context_line":"        return None"},{"line_number":53,"context_line":""},{"line_number":54,"context_line":"    def handle_newlink(self, msg):"}],"source_content_type":"text/x-python","patch_set":3,"id":"20393c75_1dd6a361","line":51,"in_reply_to":"4fd070a4_ce02bfe9","updated":"2026-05-04 14:48:20.000000000","message":"I rewrote this to take out placeholder code.","commit_id":"944aa7f457f8382f5b991c282e9fb24146ae6a4a"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"e0964c0c29b46df436d33faca67a00408f9f8b98","unresolved":true,"context_lines":[{"line_number":32,"context_line":"        self._known_vrfs \u003d set()"},{"line_number":33,"context_line":""},{"line_number":34,"context_line":"    @staticmethod"},{"line_number":35,"context_line":"    def _link_kind(msg):"},{"line_number":36,"context_line":"        \"\"\"Extract IFLA_INFO_KIND from nested IFLA_LINKINFO.\"\"\""},{"line_number":37,"context_line":"        linkinfo \u003d msg.get_attr(\u0027IFLA_LINKINFO\u0027)"},{"line_number":38,"context_line":"        if linkinfo:"}],"source_content_type":"text/x-python","patch_set":6,"id":"499bce4b_5dd9b60a","line":35,"range":{"start_line":35,"start_character":8,"end_line":35,"end_character":18},"updated":"2026-05-05 14:48:06.000000000","message":"nit: As the word link can also sound as a verb, I\u0027d use `_get_link_kind`","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":38298,"name":"Helen Chen","display_name":"Helen Chen","email":"ichen@redhat.com","username":"ingwherchen"},"change_message_id":"1505a4027509b4bcb776a1cc3286ef9a223643d5","unresolved":false,"context_lines":[{"line_number":32,"context_line":"        self._known_vrfs \u003d set()"},{"line_number":33,"context_line":""},{"line_number":34,"context_line":"    @staticmethod"},{"line_number":35,"context_line":"    def _link_kind(msg):"},{"line_number":36,"context_line":"        \"\"\"Extract IFLA_INFO_KIND from nested IFLA_LINKINFO.\"\"\""},{"line_number":37,"context_line":"        linkinfo \u003d msg.get_attr(\u0027IFLA_LINKINFO\u0027)"},{"line_number":38,"context_line":"        if linkinfo:"}],"source_content_type":"text/x-python","patch_set":6,"id":"4a8a8753_6ae31605","line":35,"range":{"start_line":35,"start_character":8,"end_line":35,"end_character":18},"in_reply_to":"499bce4b_5dd9b60a","updated":"2026-05-07 14:44:40.000000000","message":"Removed this function since the get_nested() suggestion works.","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"e0964c0c29b46df436d33faca67a00408f9f8b98","unresolved":true,"context_lines":[{"line_number":34,"context_line":"    @staticmethod"},{"line_number":35,"context_line":"    def _link_kind(msg):"},{"line_number":36,"context_line":"        \"\"\"Extract IFLA_INFO_KIND from nested IFLA_LINKINFO.\"\"\""},{"line_number":37,"context_line":"        linkinfo \u003d msg.get_attr(\u0027IFLA_LINKINFO\u0027)"},{"line_number":38,"context_line":"        if linkinfo:"},{"line_number":39,"context_line":"            return linkinfo.get_attr(\u0027IFLA_INFO_KIND\u0027)"},{"line_number":40,"context_line":"        return None"},{"line_number":41,"context_line":""},{"line_number":42,"context_line":"    def _parse_evpn_vrf(self, msg):"},{"line_number":43,"context_line":"        \"\"\"Parse VNI from an EVPN VRF message, or return None.\"\"\""}],"source_content_type":"text/x-python","patch_set":6,"id":"017b1819_342cda82","line":40,"range":{"start_line":37,"start_character":0,"end_line":40,"end_character":19},"updated":"2026-05-05 14:48:06.000000000","message":"Would this do the same?\n```\nreturn msg.get_nested(\u0027IFLA_LINKINFO\u0027, \u0027IFLA_INFO_KIND\u0027)\n```","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":38298,"name":"Helen Chen","display_name":"Helen Chen","email":"ichen@redhat.com","username":"ingwherchen"},"change_message_id":"1505a4027509b4bcb776a1cc3286ef9a223643d5","unresolved":false,"context_lines":[{"line_number":34,"context_line":"    @staticmethod"},{"line_number":35,"context_line":"    def _link_kind(msg):"},{"line_number":36,"context_line":"        \"\"\"Extract IFLA_INFO_KIND from nested IFLA_LINKINFO.\"\"\""},{"line_number":37,"context_line":"        linkinfo \u003d msg.get_attr(\u0027IFLA_LINKINFO\u0027)"},{"line_number":38,"context_line":"        if linkinfo:"},{"line_number":39,"context_line":"            return linkinfo.get_attr(\u0027IFLA_INFO_KIND\u0027)"},{"line_number":40,"context_line":"        return None"},{"line_number":41,"context_line":""},{"line_number":42,"context_line":"    def _parse_evpn_vrf(self, msg):"},{"line_number":43,"context_line":"        \"\"\"Parse VNI from an EVPN VRF message, or return None.\"\"\""}],"source_content_type":"text/x-python","patch_set":6,"id":"410bb800_faa49e93","line":40,"range":{"start_line":37,"start_character":0,"end_line":40,"end_character":19},"in_reply_to":"017b1819_342cda82","updated":"2026-05-07 14:44:40.000000000","message":"Done","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"e0964c0c29b46df436d33faca67a00408f9f8b98","unresolved":true,"context_lines":[{"line_number":41,"context_line":""},{"line_number":42,"context_line":"    def _parse_evpn_vrf(self, msg):"},{"line_number":43,"context_line":"        \"\"\"Parse VNI from an EVPN VRF message, or return None.\"\"\""},{"line_number":44,"context_line":"        result \u003d None"},{"line_number":45,"context_line":"        if self._link_kind(msg) \u003d\u003d evpn_const.EVPN_LINK_KIND_VRF:"},{"line_number":46,"context_line":"            ifname \u003d msg.get_attr(\u0027IFLA_IFNAME\u0027)"},{"line_number":47,"context_line":"            if ifname and ifname.startswith(evpn_const.EVPN_VRF_PREFIX):"}],"source_content_type":"text/x-python","patch_set":6,"id":"46f5ce25_f6a08b34","line":44,"updated":"2026-05-05 14:48:06.000000000","message":"Is the None value used anywhere? It seems to me when None is returned it means we didn\u0027t parse and we should not do anything, which should be treated as an exception.","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":38298,"name":"Helen Chen","display_name":"Helen Chen","email":"ichen@redhat.com","username":"ingwherchen"},"change_message_id":"ee3e4ffe676c5f5e23efc7d0de551626ee142262","unresolved":true,"context_lines":[{"line_number":41,"context_line":""},{"line_number":42,"context_line":"    def _parse_evpn_vrf(self, msg):"},{"line_number":43,"context_line":"        \"\"\"Parse VNI from an EVPN VRF message, or return None.\"\"\""},{"line_number":44,"context_line":"        result \u003d None"},{"line_number":45,"context_line":"        if self._link_kind(msg) \u003d\u003d evpn_const.EVPN_LINK_KIND_VRF:"},{"line_number":46,"context_line":"            ifname \u003d msg.get_attr(\u0027IFLA_IFNAME\u0027)"},{"line_number":47,"context_line":"            if ifname and ifname.startswith(evpn_const.EVPN_VRF_PREFIX):"}],"source_content_type":"text/x-python","patch_set":6,"id":"49ee8456_5c73b97f","line":44,"in_reply_to":"46f5ce25_f6a08b34","updated":"2026-05-06 02:15:59.000000000","message":"When we subscribe for RTM_NEWLINK or RTM_DELLINK messages, we get all the \"ip link add\" and \"ip link del\" messages.  We only care about link messages that are type vrf and only the vrf links that are EVPN VRFs.  (OVN can also create VRFs for core BGP.)\n\nSo, result is None occurs when the message is about all other types of links that the extension doesn\u0027t care to process.","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":38298,"name":"Helen Chen","display_name":"Helen Chen","email":"ichen@redhat.com","username":"ingwherchen"},"change_message_id":"1505a4027509b4bcb776a1cc3286ef9a223643d5","unresolved":false,"context_lines":[{"line_number":41,"context_line":""},{"line_number":42,"context_line":"    def _parse_evpn_vrf(self, msg):"},{"line_number":43,"context_line":"        \"\"\"Parse VNI from an EVPN VRF message, or return None.\"\"\""},{"line_number":44,"context_line":"        result \u003d None"},{"line_number":45,"context_line":"        if self._link_kind(msg) \u003d\u003d evpn_const.EVPN_LINK_KIND_VRF:"},{"line_number":46,"context_line":"            ifname \u003d msg.get_attr(\u0027IFLA_IFNAME\u0027)"},{"line_number":47,"context_line":"            if ifname and ifname.startswith(evpn_const.EVPN_VRF_PREFIX):"}],"source_content_type":"text/x-python","patch_set":6,"id":"0c402eb1_b973ae5c","line":44,"in_reply_to":"49ee8456_5c73b97f","updated":"2026-05-07 14:44:40.000000000","message":"Done","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"e0964c0c29b46df436d33faca67a00408f9f8b98","unresolved":true,"context_lines":[{"line_number":44,"context_line":"        result \u003d None"},{"line_number":45,"context_line":"        if self._link_kind(msg) \u003d\u003d evpn_const.EVPN_LINK_KIND_VRF:"},{"line_number":46,"context_line":"            ifname \u003d msg.get_attr(\u0027IFLA_IFNAME\u0027)"},{"line_number":47,"context_line":"            if ifname and ifname.startswith(evpn_const.EVPN_VRF_PREFIX):"},{"line_number":48,"context_line":"                # Assume placeholder VRF name pattern evpnvrf- for now"},{"line_number":49,"context_line":"                result \u003d ifname, int(ifname[len(evpn_const.EVPN_VRF_PREFIX):])"},{"line_number":50,"context_line":"        return result"}],"source_content_type":"text/x-python","patch_set":6,"id":"24d9f7b1_c964beb2","line":47,"updated":"2026-05-05 14:48:06.000000000","message":"We should rely on naming here and treat all vrfs as created by the ovn-controller.","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"29858243e27e782f53f9f031931653eabc24a839","unresolved":true,"context_lines":[{"line_number":44,"context_line":"        result \u003d None"},{"line_number":45,"context_line":"        if self._link_kind(msg) \u003d\u003d evpn_const.EVPN_LINK_KIND_VRF:"},{"line_number":46,"context_line":"            ifname \u003d msg.get_attr(\u0027IFLA_IFNAME\u0027)"},{"line_number":47,"context_line":"            if ifname and ifname.startswith(evpn_const.EVPN_VRF_PREFIX):"},{"line_number":48,"context_line":"                # Assume placeholder VRF name pattern evpnvrf- for now"},{"line_number":49,"context_line":"                result \u003d ifname, int(ifname[len(evpn_const.EVPN_VRF_PREFIX):])"},{"line_number":50,"context_line":"        return result"}],"source_content_type":"text/x-python","patch_set":6,"id":"56507bc5_ba6a9049","line":47,"in_reply_to":"24d9f7b1_c964beb2","updated":"2026-05-06 13:01:26.000000000","message":"Correction: We should *NOT* rely on naming :) and just assume only ovn-controller can be the one creating vrfs.","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":38298,"name":"Helen Chen","display_name":"Helen Chen","email":"ichen@redhat.com","username":"ingwherchen"},"change_message_id":"1505a4027509b4bcb776a1cc3286ef9a223643d5","unresolved":false,"context_lines":[{"line_number":44,"context_line":"        result \u003d None"},{"line_number":45,"context_line":"        if self._link_kind(msg) \u003d\u003d evpn_const.EVPN_LINK_KIND_VRF:"},{"line_number":46,"context_line":"            ifname \u003d msg.get_attr(\u0027IFLA_IFNAME\u0027)"},{"line_number":47,"context_line":"            if ifname and ifname.startswith(evpn_const.EVPN_VRF_PREFIX):"},{"line_number":48,"context_line":"                # Assume placeholder VRF name pattern evpnvrf- for now"},{"line_number":49,"context_line":"                result \u003d ifname, int(ifname[len(evpn_const.EVPN_VRF_PREFIX):])"},{"line_number":50,"context_line":"        return result"}],"source_content_type":"text/x-python","patch_set":6,"id":"ae3e9374_ac5b7194","line":47,"in_reply_to":"56507bc5_ba6a9049","updated":"2026-05-07 14:44:40.000000000","message":"Even when assuming that only ovn-controller create VRFs, can\u0027t assume all VRFs are for EVPN, since ovn-controller also creates VRFs for core BGP.","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"e0964c0c29b46df436d33faca67a00408f9f8b98","unresolved":true,"context_lines":[{"line_number":54,"context_line":"        if result:"},{"line_number":55,"context_line":"            # Placeholder VRF name includes VNI in the VRF name"},{"line_number":56,"context_line":"            ifname, vni \u003d result"},{"line_number":57,"context_line":"            if vni not in self._known_vrfs:"},{"line_number":58,"context_line":"                self._known_vrfs.add(vni)"},{"line_number":59,"context_line":"                LOG.info(\"VRF created: %s (VNI %d)\", ifname, vni)"},{"line_number":60,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"ca2f181f_5745a118","line":57,"updated":"2026-05-05 14:48:06.000000000","message":"Why do we need this check and when can it happen we\u0027d get new vrf for already known vrfs?","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":38298,"name":"Helen Chen","display_name":"Helen Chen","email":"ichen@redhat.com","username":"ingwherchen"},"change_message_id":"1505a4027509b4bcb776a1cc3286ef9a223643d5","unresolved":false,"context_lines":[{"line_number":54,"context_line":"        if result:"},{"line_number":55,"context_line":"            # Placeholder VRF name includes VNI in the VRF name"},{"line_number":56,"context_line":"            ifname, vni \u003d result"},{"line_number":57,"context_line":"            if vni not in self._known_vrfs:"},{"line_number":58,"context_line":"                self._known_vrfs.add(vni)"},{"line_number":59,"context_line":"                LOG.info(\"VRF created: %s (VNI %d)\", ifname, vni)"},{"line_number":60,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"d5e6fd94_942926a7","line":57,"in_reply_to":"76f99021_43c97a81","updated":"2026-05-07 14:44:40.000000000","message":"I forgot that this check exists because both \"ip link add\" and \"ip link set \u003clink\u003e up\" both come as RTM_NEWLINK messages and there\u0027s no way to distinguish them.  The flag NLM_F_CREATE in the message is not set in these messages that the kernel relays.  So, it is necessary to check to filter out the second RTM_NEWLINK message.","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":38298,"name":"Helen Chen","display_name":"Helen Chen","email":"ichen@redhat.com","username":"ingwherchen"},"change_message_id":"ee3e4ffe676c5f5e23efc7d0de551626ee142262","unresolved":true,"context_lines":[{"line_number":54,"context_line":"        if result:"},{"line_number":55,"context_line":"            # Placeholder VRF name includes VNI in the VRF name"},{"line_number":56,"context_line":"            ifname, vni \u003d result"},{"line_number":57,"context_line":"            if vni not in self._known_vrfs:"},{"line_number":58,"context_line":"                self._known_vrfs.add(vni)"},{"line_number":59,"context_line":"                LOG.info(\"VRF created: %s (VNI %d)\", ifname, vni)"},{"line_number":60,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"76f99021_43c97a81","line":57,"in_reply_to":"ca2f181f_5745a118","updated":"2026-05-06 02:15:59.000000000","message":"You\u0027re right.  We don\u0027t need to check here.","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"}],"neutron/tests/unit/agent/linux/test_nl_dispatcher.py":[{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"e0964c0c29b46df436d33faca67a00408f9f8b98","unresolved":true,"context_lines":[{"line_number":1,"context_line":"# Copyright 2026 Red Hat, Inc."},{"line_number":2,"context_line":"# All Rights Reserved."},{"line_number":3,"context_line":"#"},{"line_number":4,"context_line":"#    Licensed under the Apache License, Version 2.0 (the \"License\"); you may"}],"source_content_type":"text/x-python","patch_set":6,"id":"98a51fc6_54201c0b","line":1,"updated":"2026-05-05 14:48:06.000000000","message":"As the netlink dispatcher mostly interacts with kernel, I wonder if it makes sense to have such unittests for it. I\u0027d rather have isolated functional tests that would work with real netlink messages.","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":38298,"name":"Helen Chen","display_name":"Helen Chen","email":"ichen@redhat.com","username":"ingwherchen"},"change_message_id":"8cfb2ab5dc0a3b4fdeb16bbc4b13046d9d5d7382","unresolved":false,"context_lines":[{"line_number":1,"context_line":"# Copyright 2026 Red Hat, Inc."},{"line_number":2,"context_line":"# All Rights Reserved."},{"line_number":3,"context_line":"#"},{"line_number":4,"context_line":"#    Licensed under the Apache License, Version 2.0 (the \"License\"); you may"}],"source_content_type":"text/x-python","patch_set":6,"id":"7c5ddf28_6eb0d2f3","line":1,"in_reply_to":"0b80f6bf_925408c7","updated":"2026-05-07 14:44:57.000000000","message":"Done","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"},{"author":{"_account_id":38298,"name":"Helen Chen","display_name":"Helen Chen","email":"ichen@redhat.com","username":"ingwherchen"},"change_message_id":"ee3e4ffe676c5f5e23efc7d0de551626ee142262","unresolved":true,"context_lines":[{"line_number":1,"context_line":"# Copyright 2026 Red Hat, Inc."},{"line_number":2,"context_line":"# All Rights Reserved."},{"line_number":3,"context_line":"#"},{"line_number":4,"context_line":"#    Licensed under the Apache License, Version 2.0 (the \"License\"); you may"}],"source_content_type":"text/x-python","patch_set":6,"id":"0b80f6bf_925408c7","line":1,"in_reply_to":"98a51fc6_54201c0b","updated":"2026-05-06 02:15:59.000000000","message":"I can remove it.  I find it to be a lightweight tool to test for conditions such as buffer full in the dispatcher loop.","commit_id":"dc86f6e374d947769a8c0713f6c77536e1a13ac9"}]}
