{"id":2267753,"url":"http://patchwork.ozlabs.org/api/patches/2267753/","web_url":"http://patchwork.ozlabs.org/project/ovn/patch/20260709171001.2825950-1-moloings@redhat.com/","project":{"id":68,"url":"http://patchwork.ozlabs.org/api/projects/68/","name":"Open Virtual Network development","link_name":"ovn","list_id":"ovs-dev.openvswitch.org","list_email":"ovs-dev@openvswitch.org","web_url":"http://openvswitch.org/","scm_url":"","webscm_url":"","list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<20260709171001.2825950-1-moloings@redhat.com>","list_archive_url":null,"date":"2026-07-09T17:10:01","name":"[ovs-dev,v3] northd: Use source IP for TTL expire on gw ports.","commit_ref":null,"pull_url":null,"state":"accepted","archived":false,"hash":"a55ffcdd42ee9dbee60ae0f14013cd5b0af3608d","submitter":{"id":91032,"url":"http://patchwork.ozlabs.org/api/people/91032/","name":"Mairtin O'Loingsigh","email":"moloings@redhat.com"},"delegate":{"id":94943,"url":"http://patchwork.ozlabs.org/api/users/94943/","username":"dceara","first_name":"Dumitru","last_name":"Ceara","email":"dceara@redhat.com"},"mbox":"http://patchwork.ozlabs.org/project/ovn/patch/20260709171001.2825950-1-moloings@redhat.com/mbox/","series":[{"id":512962,"url":"http://patchwork.ozlabs.org/api/series/512962/","web_url":"http://patchwork.ozlabs.org/project/ovn/list/?series=512962","date":"2026-07-09T17:10:01","name":"[ovs-dev,v3] northd: Use source IP for TTL expire on gw ports.","version":3,"mbox":"http://patchwork.ozlabs.org/series/512962/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2267753/comments/","check":"success","checks":"http://patchwork.ozlabs.org/api/patches/2267753/checks/","tags":{},"related":[],"headers":{"Return-Path":"<ovs-dev-bounces@openvswitch.org>","X-Original-To":["incoming@patchwork.ozlabs.org","dev@openvswitch.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","ovs-dev@lists.linuxfoundation.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=NUJ92xDA;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org\n (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org)","smtp3.osuosl.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key)\n header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=NUJ92xDA","smtp3.osuosl.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com"],"Received":["from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4gx1gW3MCnz1xqZ\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 10 Jul 2026 03:10:29 +1000 (AEST)","from localhost (localhost [127.0.0.1])\n\tby smtp3.osuosl.org (Postfix) with ESMTP id 48EDC61013;\n\tThu,  9 Jul 2026 17:10:27 +0000 (UTC)","from smtp3.osuosl.org ([127.0.0.1])\n by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id QpD2Xethnnla; Thu,  9 Jul 2026 17:10:21 +0000 (UTC)","from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56])\n\tby smtp3.osuosl.org (Postfix) with ESMTPS id B65976062A;\n\tThu,  9 Jul 2026 17:10:21 +0000 (UTC)","from lf-lists.osuosl.org (localhost [127.0.0.1])\n\tby lists.linuxfoundation.org (Postfix) with ESMTP id 993C3C0070;\n\tThu,  9 Jul 2026 17:10:21 +0000 (UTC)","from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136])\n by lists.linuxfoundation.org (Postfix) with ESMTP id 6EEEFC003D\n for <dev@openvswitch.org>; Thu,  9 Jul 2026 17:10:20 +0000 (UTC)","from localhost (localhost [127.0.0.1])\n by smtp3.osuosl.org (Postfix) with ESMTP id F3F9E6062A\n for <dev@openvswitch.org>; Thu,  9 Jul 2026 17:10:19 +0000 (UTC)","from smtp3.osuosl.org ([127.0.0.1])\n by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id cW7Tdaett6WW for <dev@openvswitch.org>;\n Thu,  9 Jul 2026 17:10:17 +0000 (UTC)","from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.133.124])\n by smtp3.osuosl.org (Postfix) with ESMTPS id 1308F61008\n for <dev@openvswitch.org>; Thu,  9 Jul 2026 17:10:15 +0000 (UTC)","from mail-qk1-f198.google.com (mail-qk1-f198.google.com\n [209.85.222.198]) by relay.mimecast.com with ESMTP with STARTTLS\n (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n us-mta-528-zkkjc_TJOdqo7Kwp0Vacww-1; Thu, 09 Jul 2026 13:10:13 -0400","by mail-qk1-f198.google.com with SMTP id\n af79cd13be357-92aea0d801dso943185a.1\n for <dev@openvswitch.org>; Thu, 09 Jul 2026 10:10:13 -0700 (PDT)","from moloings-thinkpadp1gen7.rmtie.csb\n ([2001:bb6:2be4:f100:a13c:8a56:eb6f:ed3f])\n by smtp.gmail.com with ESMTPSA id\n af79cd13be357-92e90c926basm1662661485a.22.2026.07.09.10.10.09\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Thu, 09 Jul 2026 10:10:10 -0700 (PDT)"],"X-Virus-Scanned":["amavis at osuosl.org","amavis at osuosl.org"],"X-Comment":"SPF check N/A for local connections - client-ip=140.211.9.56;\n helo=lists.linuxfoundation.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=<UNKNOWN> ","DKIM-Filter":["OpenDKIM Filter v2.11.0 smtp3.osuosl.org B65976062A","OpenDKIM Filter v2.11.0 smtp3.osuosl.org 1308F61008"],"Received-SPF":"Pass (mailfrom) identity=mailfrom; client-ip=170.10.133.124;\n helo=us-smtp-delivery-124.mimecast.com; envelope-from=moloings@redhat.com;\n receiver=<UNKNOWN>","DMARC-Filter":"OpenDMARC Filter v1.4.2 smtp3.osuosl.org 1308F61008","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1783617014;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding;\n bh=EcNZNsc53OgtRgIGiRp7DUkXtOQ/nXRiVcfH8xWQBUE=;\n b=NUJ92xDAe3Pj2F9beB1fJKPV8kJir/3llatQi0FEFfFsjAUod9JL3DSHSXGkoKUaYU5z0k\n zP/psIsvmphr/0DHsTfwbhEWOj42pP4DsmuHLbIMy0LnDJNKD4gcVsxrB/Ixe7Hlxh8rd7\n BxEA4bQxCMHftVlRgX4tyABQ5UJMu1o=","X-MC-Unique":"zkkjc_TJOdqo7Kwp0Vacww-1","X-Mimecast-MFC-AGG-ID":"zkkjc_TJOdqo7Kwp0Vacww_1783617013","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1783617013; x=1784221813;\n h=content-transfer-encoding:mime-version:message-id:date:subject:cc\n :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date\n :message-id:reply-to:content-type;\n bh=EcNZNsc53OgtRgIGiRp7DUkXtOQ/nXRiVcfH8xWQBUE=;\n b=Sb4OkVtAVH6Ax0LXCxFZMoK69rB5rQbyb97sWyMtHFIkTj/RpC0mE+zrO3b5BBsVtF\n 8aeEzjIr4Ybb3z+RPr5ewYmBwg76a64vYlx2OhN7DnEpxJwc897Fhxh7yYpRaVc0CSEu\n fKdXmgtgYRNXNz8Ls59qgAKNYiWX/I7SaBKgUycSZY6qyZyjWWZR139Ixm/W6LMxk5kF\n xYY3lMAAKRa0tymuJV8MVXyknRwH3naMazTBdXxq6a7FlktBzKkXogjqLOEBu4XeH65x\n nS1sYJJy8SpDpBqk4BagI64/+568i7f7gotyABC7wYRo6ZhZ9701LvTxrbcDm4rFM8cN\n elhA==","X-Gm-Message-State":"AOJu0Yy7pNF0Hlxke2KA8LIYMZyUHehlePklihNDg3bDf91O0XVqglOu\n lG1Sa9b1HUocE5ZmG0XqlUcp+mntwkdifesMJgJ9qWW6yFstJWKL1Ok5ukdQo38qGei2/QiJMFX\n hM2DOMsB3wvZlLB0daiNVuR7YdsBieoGM8VwBINNSP9bcamiMQi6bMZCPZIE5sQaXtCDZ6RmzLe\n XWYLKHDxu9n78iNHZ+tWWqZ8F3kIpzmGMyHJVMzQ==","X-Gm-Gg":"AfdE7cli714MrCVFUJvK2up+x0BM/KXpWQ8xFSAtSqZkF6uHIwDdxyNqEMnPEgCvAvX\n fCpW6T9UXxIwjWjxfrlIV88ve/RfqNxMZS90UhSasOLDwCrH2naTveJ7sndUoeMF13vxmrrNfX5\n l+rXP9Wmv0V9vQPv5VcgA7K8znTCIHMdV4NgUD8NUIfsKBS3NgkRSadQTR5Ni/wKUU1/1Kz6NqT\n W3+FBA2XEb3PUefcFlsWc5Q4l++XXsFFO3cuFbC4hVg72CgyP5hZ7Pd4olM91wDVv6N0VkSLMm8\n 0E6ffCPwjlyHQYfV/DY5pfY54WDSLXrKYPL9vBhq6LO43XKdRXs39YkjnfxSkEl+LHzHicFtG8v\n v+cDE8UUsuoWUMjOvnU6u95/Zr/r6DJSf4XdOWQjA0SaqG7NLQat9mbOZJ8FaiepPwpuosxURrg\n ==","X-Received":["by 2002:a05:620a:1998:b0:915:d10e:8c4f with SMTP id\n af79cd13be357-92ecf68cef1mr884319085a.53.1783617012328;\n Thu, 09 Jul 2026 10:10:12 -0700 (PDT)","by 2002:a05:620a:1998:b0:915:d10e:8c4f with SMTP id\n af79cd13be357-92ecf68cef1mr884306085a.53.1783617011260;\n Thu, 09 Jul 2026 10:10:11 -0700 (PDT)"],"To":"dev@openvswitch.org","Date":"Thu,  9 Jul 2026 18:10:01 +0100","Message-ID":"<20260709171001.2825950-1-moloings@redhat.com>","X-Mailer":"git-send-email 2.54.0","MIME-Version":"1.0","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"75rpruDCiOlAvZeNuja8xrJmItsCtuUARLzR6LaJ_Cg_1783617013","X-Mimecast-Originator":"redhat.com","Subject":"[ovs-dev] [PATCH ovn v3] northd: Use source IP for TTL expire on gw\n ports.","X-BeenThere":"ovs-dev@openvswitch.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"<ovs-dev.openvswitch.org>","List-Unsubscribe":"<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>","List-Archive":"<http://mail.openvswitch.org/pipermail/ovs-dev/>","List-Post":"<mailto:ovs-dev@openvswitch.org>","List-Help":"<mailto:ovs-dev-request@openvswitch.org?subject=help>","List-Subscribe":"<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=subscribe>","From":"Mairtin O'Loingsigh via dev <ovs-dev@openvswitch.org>","Reply-To":"Mairtin O'Loingsigh <moloings@redhat.com>","Cc":"i.maximets@ovn.org","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Errors-To":"ovs-dev-bounces@openvswitch.org","Sender":"\"dev\" <ovs-dev-bounces@openvswitch.org>"},"content":"When transit traffic arrives on an l3dgw port with TTL=0 or TTL=1,\nnorthd generates an ICMP Time Exceeded reply. Previously, the action\nfor l3dgw ports used \"ip4.dst <-> ip4.src\", which swaps the source\nand destination addresses. This sets the ICMP reply source to the\noriginal packet's destination, instead of the receiving router port\naddress. For example, a packet from 203.0.113.50 destined to\n10.0.0.5 would produce an ICMP error with source 10.0.0.5 instead\nof the router port's own address.\n\nUse \"ip4.dst = ip4.src; ip4.src = <router_port_ip>\" and\n\"eth.dst = eth.src; eth.src = %s\" unconditionally\nfor both l3dgw and non-l3dgw ports, so the ICMP reply MAC and IP\naddress are always the router port's address in the matching subnet.\n\nFixes: 4ecc61247d86 (\"northd: fix ttl exceeded with FIP\")\nReported-at: https://redhat.atlassian.net/browse/FDP-4078\nSigned-off-by: Mairtin O'Loingsigh <moloings@redhat.com>\n---\nv2 -> v3:\n  - Rebase on main.\nv1 -> v2:\n  - Set source MAC to router port MAC.\n\n NEWS                |   2 +\n northd/northd.c     |  68 ++++++++++++-------------\n tests/ovn-northd.at | 119 ++++++++++++++++++++++++++++++++++----------\n 3 files changed, 128 insertions(+), 61 deletions(-)","diff":"diff --git a/NEWS b/NEWS\nindex d1a6ad27f..797e289d3 100644\n--- a/NEWS\n+++ b/NEWS\n@@ -1,5 +1,7 @@\n Post v26.03.0\n -------------\n+   - Fixed support for TTL expired. Use router port IP and MAC instead of dest\n+     IP and MAC for ICMP Time exceeded response.\n    - Load balancer health checks now \"fail closed\" for newly added backends:\n      ovn-northd initializes a newly created Service_Monitor row to the\n      \"offline\" state, so traffic is not forwarded to a backend until its first\ndiff --git a/northd/northd.c b/northd/northd.c\nindex e4cd93969..16356c6ca 100644\n--- a/northd/northd.c\n+++ b/northd/northd.c\n@@ -16947,19 +16947,9 @@ build_lrouter_ipv4_default_ttl_expired_flows(\n         return;\n     }\n \n-    struct ds ip_ds = DS_EMPTY_INITIALIZER;\n     for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {\n         ds_clear(match);\n         ds_clear(actions);\n-        ds_clear(&ip_ds);\n-        if (lrp_is_l3dgw(op)) {\n-            ds_put_cstr(&ip_ds, \"ip4.dst <-> ip4.src\");\n-            ds_put_format(match, \"is_chassis_resident(%s) && \",\n-                          op->cr_port->json_key);\n-        } else {\n-            ds_put_format(&ip_ds, \"ip4.dst = ip4.src; ip4.src = %s\",\n-                          op->lrp_networks.ipv4_addrs[i].addr_s);\n-        }\n         ds_put_format(match,\n                       \"inport == %s && ip4 && \"\n                       \"ip4.src == %s/%d && \"\n@@ -16967,23 +16957,28 @@ build_lrouter_ipv4_default_ttl_expired_flows(\n                       op->json_key,\n                       op->lrp_networks.ipv4_addrs[i].network_s,\n                       op->lrp_networks.ipv4_addrs[i].plen);\n+        if (lrp_is_l3dgw(op)) {\n+            ds_put_format(match, \" && is_chassis_resident(%s)\",\n+                          op->cr_port->json_key);\n+        }\n+\n         ds_put_format(actions,\n                       \"icmp4 {\"\n-                      \"eth.dst <-> eth.src; \"\n+                      \"eth.dst = eth.src; eth.src = %s; \"\n                       \"icmp4.type = 11; /* Time exceeded */ \"\n                       \"icmp4.code = 0; /* TTL exceeded in transit */ \"\n-                      \"%s ; ip.ttl = 254; \"\n+                      \"ip4.dst = ip4.src; ip4.src = %s; ip.ttl = 254; \"\n                       \"outport = %s; flags.loopback = 1; output; };\",\n-                      ds_cstr(&ip_ds), op->json_key);\n+                      op->lrp_networks.ea_s,\n+                      op->lrp_networks.ipv4_addrs[i].addr_s, op->json_key);\n+\n         ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 31,\n                       ds_cstr(match), ds_cstr(actions), lflow_ref,\n                       WITH_CTRL_METER(copp_meter_get(COPP_ICMP4_ERR,\n                                                      op->od->nbr->copp,\n                                                      meter_groups)),\n                       WITH_HINT(&op->nbrp->header_));\n-\n     }\n-    ds_destroy(&ip_ds);\n     ds_clear(match);\n     ds_clear(actions);\n \n@@ -16994,15 +16989,19 @@ build_lrouter_ipv4_default_ttl_expired_flows(\n                   \"inport == %s && ip4 && \"\n                   \"ip.ttl == {0, 1} && !ip.later_frag\",\n                   op->json_key);\n+    if (lrp_is_l3dgw(op)) {\n+        ds_put_format(match, \" && is_chassis_resident(%s)\",\n+                      op->cr_port->json_key);\n+    }\n     ds_put_format(actions,\n                   \"icmp4 {\"\n-                  \"eth.dst <-> eth.src; \"\n+                  \"eth.dst = eth.src; eth.src = %s; \"\n                   \"icmp4.type = 11; /* Time exceeded */ \"\n                   \"icmp4.code = 0; /* TTL exceeded in transit */ \"\n                   \"ip4.dst = ip4.src; ip4.src = %s; ip.ttl = 254; \"\n-                   \"outport = %s; flags.loopback = 1; output; };\",\n-                   op->lrp_networks.ipv4_addrs[0].addr_s,\n-                   op->json_key);\n+                  \"outport = %s; flags.loopback = 1; output; };\",\n+                  op->lrp_networks.ea_s, op->lrp_networks.ipv4_addrs[0].addr_s,\n+                  op->json_key);\n     ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 30,\n                   ds_cstr(match), ds_cstr(actions), lflow_ref,\n                   WITH_CTRL_METER(copp_meter_get(COPP_ICMP4_ERR,\n@@ -17025,19 +17024,9 @@ build_lrouter_ipv6_default_ttl_expired_flows(\n         return;\n     }\n \n-    struct ds ip_ds = DS_EMPTY_INITIALIZER;\n     for (size_t i = 0; i < op->lrp_networks.n_ipv6_addrs - 1; i++) {\n         ds_clear(match);\n         ds_clear(actions);\n-        ds_clear(&ip_ds);\n-        if (lrp_is_l3dgw(op)) {\n-            ds_put_cstr(&ip_ds, \"ip6.dst <-> ip6.src\");\n-            ds_put_format(match, \"is_chassis_resident(%s) && \",\n-                          op->cr_port->json_key);\n-        } else {\n-            ds_put_format(&ip_ds, \"ip6.dst = ip6.src; ip6.src = %s\",\n-                          op->lrp_networks.ipv6_addrs[i].addr_s);\n-        }\n         ds_put_format(match,\n                       \"inport == %s && ip6 && \"\n                       \"ip6.src == %s/%d && \"\n@@ -17045,14 +17034,20 @@ build_lrouter_ipv6_default_ttl_expired_flows(\n                       op->json_key,\n                       op->lrp_networks.ipv6_addrs[i].network_s,\n                       op->lrp_networks.ipv6_addrs[i].plen);\n+        if (lrp_is_l3dgw(op)) {\n+            ds_put_format(match, \" && is_chassis_resident(%s)\",\n+                          op->cr_port->json_key);\n+        }\n         ds_put_format(actions,\n                       \"icmp6 {\"\n-                      \"eth.dst <-> eth.src; \"\n-                      \"%s ; ip.ttl = 254; \"\n+                      \"eth.dst = eth.src; eth.src = %s; \"\n+                      \"ip6.dst = ip6.src; ip6.src = %s; ip.ttl = 254; \"\n                       \"icmp6.type = 3; /* Time exceeded */ \"\n                       \"icmp6.code = 0; /* TTL exceeded in transit */ \"\n                       \"outport = %s; flags.loopback = 1; output; };\",\n-                      ds_cstr(&ip_ds), op->json_key);\n+                      op->lrp_networks.ea_s,\n+                      op->lrp_networks.ipv6_addrs[i].addr_s, op->json_key);\n+\n         ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 31,\n                       ds_cstr(match), ds_cstr(actions), lflow_ref,\n                       WITH_CTRL_METER(copp_meter_get(COPP_ICMP6_ERR,\n@@ -17060,7 +17055,6 @@ build_lrouter_ipv6_default_ttl_expired_flows(\n                                                      meter_groups)),\n                       WITH_HINT(&op->nbrp->header_));\n     }\n-    ds_destroy(&ip_ds);\n     ds_clear(match);\n     ds_clear(actions);\n \n@@ -17071,14 +17065,18 @@ build_lrouter_ipv6_default_ttl_expired_flows(\n                   \"inport == %s && ip6 && \"\n                   \"ip.ttl == {0, 1} && !ip.later_frag\",\n                   op->json_key);\n+    if (lrp_is_l3dgw(op)) {\n+        ds_put_format(match, \" && is_chassis_resident(%s)\",\n+                      op->cr_port->json_key);\n+    }\n     ds_put_format(actions,\n                   \"icmp6 {\"\n-                  \"eth.dst <-> eth.src; \"\n+                  \"eth.dst = eth.src; eth.src = %s; \"\n                   \"ip6.dst = ip6.src; ip6.src = %s; \"\n                   \"ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ \"\n                   \"icmp6.code = 0; /* TTL exceeded in transit */ \"\n                   \"outport = %s; flags.loopback = 1; output; };\",\n-                  op->lrp_networks.ipv6_addrs[0].addr_s,\n+                  op->lrp_networks.ea_s, op->lrp_networks.ipv6_addrs[0].addr_s,\n                   op->json_key);\n     ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 30,\n                   ds_cstr(match), ds_cstr(actions), lflow_ref,\ndiff --git a/tests/ovn-northd.at b/tests/ovn-northd.at\nindex 2edcfc2cb..45e648e49 100644\n--- a/tests/ovn-northd.at\n+++ b/tests/ovn-northd.at\n@@ -8608,14 +8608,14 @@ AT_CHECK([grep -e 'lr_in_ip_input    ' lrflows | grep -e 'igmp' -e 'mld' -e 'ip.\n   table=??(lr_in_ip_input     ), priority=120  , match=((mldv1 || mldv2) && ip.ttl == 1), action=(next;)\n   table=??(lr_in_ip_input     ), priority=120  , match=(igmp && ip.ttl == 1), action=(next;)\n   table=??(lr_in_ip_input     ), priority=29   , match=(ip.ttl == {0, 1}), action=(drop;)\n-  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lrp1\" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 10.10.10.1; ip.ttl = 254; outport = \"lrp1\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lrp1\" && ip6 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst <-> eth.src; ip6.dst = ip6.src; ip6.src = 1010::1; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lrp1\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lrp2\" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 20.20.20.1; ip.ttl = 254; outport = \"lrp2\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lrp2\" && ip6 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst <-> eth.src; ip6.dst = ip6.src; ip6.src = 2020::1; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lrp2\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lrp1\" && ip4 && ip4.src == 10.10.10.0/24 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 10.10.10.1 ; ip.ttl = 254; outport = \"lrp1\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lrp1\" && ip6 && ip6.src == 1010::/64 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst <-> eth.src; ip6.dst = ip6.src; ip6.src = 1010::1 ; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lrp1\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lrp2\" && ip4 && ip4.src == 20.20.20.0/24 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 20.20.20.1 ; ip.ttl = 254; outport = \"lrp2\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lrp2\" && ip6 && ip6.src == 2020::/64 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst <-> eth.src; ip6.dst = ip6.src; ip6.src = 2020::1 ; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lrp2\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lrp1\" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst = eth.src; eth.src = 00:00:00:00:00:01; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 10.10.10.1; ip.ttl = 254; outport = \"lrp1\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lrp1\" && ip6 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst = eth.src; eth.src = 00:00:00:00:00:01; ip6.dst = ip6.src; ip6.src = 1010::1; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lrp1\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lrp2\" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst = eth.src; eth.src = 00:00:00:00:00:02; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 20.20.20.1; ip.ttl = 254; outport = \"lrp2\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lrp2\" && ip6 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst = eth.src; eth.src = 00:00:00:00:00:02; ip6.dst = ip6.src; ip6.src = 2020::1; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lrp2\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lrp1\" && ip4 && ip4.src == 10.10.10.0/24 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst = eth.src; eth.src = 00:00:00:00:00:01; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 10.10.10.1; ip.ttl = 254; outport = \"lrp1\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lrp1\" && ip6 && ip6.src == 1010::/64 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst = eth.src; eth.src = 00:00:00:00:00:01; ip6.dst = ip6.src; ip6.src = 1010::1; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lrp1\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lrp2\" && ip4 && ip4.src == 20.20.20.0/24 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst = eth.src; eth.src = 00:00:00:00:00:02; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 20.20.20.1; ip.ttl = 254; outport = \"lrp2\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lrp2\" && ip6 && ip6.src == 2020::/64 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst = eth.src; eth.src = 00:00:00:00:00:02; ip6.dst = ip6.src; ip6.src = 2020::1; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lrp2\"; flags.loopback = 1; output; };)\n   table=??(lr_in_ip_input     ), priority=32   , match=(ip.ttl == {0, 1} && !ip.later_frag && (ip4.mcast || ip6.mcast)), action=(drop;)\n ])\n \n@@ -8635,6 +8635,73 @@ OVN_CLEANUP_NORTHD\n AT_CLEANUP\n ])\n \n+OVN_FOR_EACH_NORTHD_NO_HV([\n+AT_SETUP([TTL exceeded -- l3dgw port uses correct source IP])\n+AT_KEYWORDS([ttl-exceeded l3dgw])\n+ovn_start\n+\n+check ovn-nbctl lr-add lr0\n+check ovn-nbctl ls-add sw0\n+check ovn-nbctl ls-add public\n+\n+check ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24 2001:db8::1/64\n+check ovn-nbctl lsp-add-router-port sw0 sw0-lr0 lr0-sw0\n+\n+check ovn-nbctl lrp-add lr0 lr0-public 00:00:00:00:ff:02 172.168.0.10/24 2001:db8:1::1/64\n+check ovn-nbctl lsp-add-router-port public public-lr0 lr0-public\n+\n+check ovn-sbctl chassis-add gw1 geneve 127.0.0.1\n+check ovn-nbctl lrp-set-gateway-chassis lr0-public gw1\n+\n+check ovn-nbctl --wait=sb sync\n+\n+ovn-sbctl dump-flows lr0 > lr0flows\n+AT_CAPTURE_FILE([lr0flows])\n+\n+dnl The priority-31 TTL expired flow for the l3dgw port must use explicit\n+dnl ip4.src assignment (the router port IP), not ip4.dst <-> ip4.src swap.\n+AT_CHECK([grep 'priority=31.*lr0-public.*ip4.*ip.ttl' lr0flows | ovn_strip_lflows], [0], [dnl\n+  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lr0-public\" && ip4 && ip4.src == 172.168.0.0/24 && ip.ttl == {0, 1} && !ip.later_frag && is_chassis_resident(\"cr-lr0-public\")), action=(icmp4 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:02; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 172.168.0.10; ip.ttl = 254; outport = \"lr0-public\"; flags.loopback = 1; output; };)\n+])\n+\n+dnl Non-l3dgw port should also use explicit assignment (unchanged behavior).\n+AT_CHECK([grep 'priority=31.*lr0-sw0.*ip4.*ip.ttl' lr0flows | ovn_strip_lflows], [0], [dnl\n+  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lr0-sw0\" && ip4 && ip4.src == 10.0.0.0/24 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:01; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 254; outport = \"lr0-sw0\"; flags.loopback = 1; output; };)\n+])\n+\n+dnl IPv6: l3dgw port must use explicit ip6.src assignment, not swap.\n+AT_CHECK([grep 'priority=31.*lr0-public.*ip6.*ip.ttl' lr0flows | ovn_strip_lflows], [0], [dnl\n+  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lr0-public\" && ip6 && ip6.src == 2001:db8:1::/64 && ip.ttl == {0, 1} && !ip.later_frag && is_chassis_resident(\"cr-lr0-public\")), action=(icmp6 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = 2001:db8:1::1; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lr0-public\"; flags.loopback = 1; output; };)\n+])\n+\n+dnl IPv6: non-l3dgw port (unchanged behavior).\n+AT_CHECK([grep 'priority=31.*lr0-sw0.*ip6.*ip.ttl' lr0flows | ovn_strip_lflows], [0], [dnl\n+  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lr0-sw0\" && ip6 && ip6.src == 2001:db8::/64 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:01; ip6.dst = ip6.src; ip6.src = 2001:db8::1; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lr0-sw0\"; flags.loopback = 1; output; };)\n+])\n+\n+AT_CHECK([grep 'priority=30.*lr0-public.*ip4.*ip.ttl' lr0flows | ovn_strip_lflows], [0], [dnl\n+  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-public\" && ip4 && ip.ttl == {0, 1} && !ip.later_frag && is_chassis_resident(\"cr-lr0-public\")), action=(icmp4 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:02; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 172.168.0.10; ip.ttl = 254; outport = \"lr0-public\"; flags.loopback = 1; output; };)\n+])\n+\n+dnl Non-l3dgw port should also use explicit assignment (unchanged behavior).\n+AT_CHECK([grep 'priority=30.*lr0-sw0.*ip4.*ip.ttl' lr0flows | ovn_strip_lflows], [0], [dnl\n+  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-sw0\" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:01; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 254; outport = \"lr0-sw0\"; flags.loopback = 1; output; };)\n+])\n+\n+dnl IPv6: l3dgw port must use explicit ip6.src assignment, not swap.\n+AT_CHECK([grep 'priority=30.*lr0-public.*ip6.*ip.ttl' lr0flows | ovn_strip_lflows], [0], [dnl\n+  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-public\" && ip6 && ip.ttl == {0, 1} && !ip.later_frag && is_chassis_resident(\"cr-lr0-public\")), action=(icmp6 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = 2001:db8:1::1; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lr0-public\"; flags.loopback = 1; output; };)\n+])\n+\n+dnl IPv6: non-l3dgw port (unchanged behavior).\n+AT_CHECK([grep 'priority=30.*lr0-sw0.*ip6.*ip.ttl' lr0flows | ovn_strip_lflows], [0], [dnl\n+  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-sw0\" && ip6 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:01; ip6.dst = ip6.src; ip6.src = 2001:db8::1; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lr0-sw0\"; flags.loopback = 1; output; };)\n+])\n+\n+OVN_CLEANUP_NORTHD\n+AT_CLEANUP\n+])\n+\n OVN_FOR_EACH_NORTHD_NO_HV([\n AT_SETUP([IP multicast flood without IGMP relay])\n AT_KEYWORDS([mcast_relay])\n@@ -14634,15 +14701,15 @@ AT_CHECK([grep \"lr_in_ip_input\" lr0flows | ovn_strip_lflows], [0], [dnl\n   table=??(lr_in_ip_input     ), priority=100  , match=(ip4.src_mcast ||ip4.src == 255.255.255.255 || ip4.src == 127.0.0.0/8 || ip4.dst == 127.0.0.0/8 || ip4.src == 0.0.0.0/8 || ip4.dst == 0.0.0.0/8), action=(drop;)\n   table=??(lr_in_ip_input     ), priority=120  , match=(inport == \"lr0-public\" && ip4.src == 172.168.0.100), action=(next;)\n   table=??(lr_in_ip_input     ), priority=29   , match=(ip.ttl == {0, 1}), action=(drop;)\n-  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-public\" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 172.168.0.10; ip.ttl = 254; outport = \"lr0-public\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-public\" && ip6 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst <-> eth.src; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lr0-public\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-sw0\" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 254; outport = \"lr0-sw0\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-sw0\" && ip6 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst <-> eth.src; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lr0-sw0\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-sw1\" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 254; outport = \"lr0-sw1\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-sw1\" && ip6 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst <-> eth.src; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff03; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lr0-sw1\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lr0-sw0\" && ip4 && ip4.src == 10.0.0.0/24 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 10.0.0.1 ; ip.ttl = 254; outport = \"lr0-sw0\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lr0-sw1\" && ip4 && ip4.src == 20.0.0.0/24 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 20.0.0.1 ; ip.ttl = 254; outport = \"lr0-sw1\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=31   , match=(is_chassis_resident(\"cr-lr0-public\") && inport == \"lr0-public\" && ip4 && ip4.src == 172.168.0.0/24 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst <-> ip4.src ; ip.ttl = 254; outport = \"lr0-public\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-public\" && ip4 && ip.ttl == {0, 1} && !ip.later_frag && is_chassis_resident(\"cr-lr0-public\")), action=(icmp4 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:02; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 172.168.0.10; ip.ttl = 254; outport = \"lr0-public\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-public\" && ip6 && ip.ttl == {0, 1} && !ip.later_frag && is_chassis_resident(\"cr-lr0-public\")), action=(icmp6 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lr0-public\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-sw0\" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:01; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 254; outport = \"lr0-sw0\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-sw0\" && ip6 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:01; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lr0-sw0\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-sw1\" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:03; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 254; outport = \"lr0-sw1\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-sw1\" && ip6 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:03; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff03; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lr0-sw1\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lr0-public\" && ip4 && ip4.src == 172.168.0.0/24 && ip.ttl == {0, 1} && !ip.later_frag && is_chassis_resident(\"cr-lr0-public\")), action=(icmp4 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:02; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 172.168.0.10; ip.ttl = 254; outport = \"lr0-public\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lr0-sw0\" && ip4 && ip4.src == 10.0.0.0/24 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:01; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 254; outport = \"lr0-sw0\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lr0-sw1\" && ip4 && ip4.src == 20.0.0.0/24 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:03; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 254; outport = \"lr0-sw1\"; flags.loopback = 1; output; };)\n   table=??(lr_in_ip_input     ), priority=32   , match=(ip.ttl == {0, 1} && !ip.later_frag && (ip4.mcast || ip6.mcast)), action=(drop;)\n   table=??(lr_in_ip_input     ), priority=50   , match=(eth.bcast), action=(drop;)\n   table=??(lr_in_ip_input     ), priority=60   , match=(ip4.dst == {10.0.0.1}), action=(drop;)\n@@ -14816,15 +14883,15 @@ AT_CHECK([grep \"lr_in_ip_input\" lr0flows | ovn_strip_lflows], [0], [dnl\n   table=??(lr_in_ip_input     ), priority=100  , match=(ip4.src_mcast ||ip4.src == 255.255.255.255 || ip4.src == 127.0.0.0/8 || ip4.dst == 127.0.0.0/8 || ip4.src == 0.0.0.0/8 || ip4.dst == 0.0.0.0/8), action=(drop;)\n   table=??(lr_in_ip_input     ), priority=120  , match=(inport == \"lr0-public\" && ip4.src == 172.168.0.100), action=(next;)\n   table=??(lr_in_ip_input     ), priority=29   , match=(ip.ttl == {0, 1}), action=(drop;)\n-  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-public\" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 172.168.0.10; ip.ttl = 254; outport = \"lr0-public\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-public\" && ip6 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst <-> eth.src; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lr0-public\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-sw0\" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 254; outport = \"lr0-sw0\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-sw0\" && ip6 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst <-> eth.src; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lr0-sw0\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-sw1\" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 254; outport = \"lr0-sw1\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-sw1\" && ip6 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst <-> eth.src; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff03; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lr0-sw1\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lr0-sw0\" && ip4 && ip4.src == 10.0.0.0/24 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 10.0.0.1 ; ip.ttl = 254; outport = \"lr0-sw0\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lr0-sw1\" && ip4 && ip4.src == 20.0.0.0/24 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 20.0.0.1 ; ip.ttl = 254; outport = \"lr0-sw1\"; flags.loopback = 1; output; };)\n-  table=??(lr_in_ip_input     ), priority=31   , match=(is_chassis_resident(\"cr-lr0-public\") && inport == \"lr0-public\" && ip4 && ip4.src == 172.168.0.0/24 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst <-> ip4.src ; ip.ttl = 254; outport = \"lr0-public\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-public\" && ip4 && ip.ttl == {0, 1} && !ip.later_frag && is_chassis_resident(\"cr-lr0-public\")), action=(icmp4 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:02; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 172.168.0.10; ip.ttl = 254; outport = \"lr0-public\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-public\" && ip6 && ip.ttl == {0, 1} && !ip.later_frag && is_chassis_resident(\"cr-lr0-public\")), action=(icmp6 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lr0-public\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-sw0\" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:01; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 254; outport = \"lr0-sw0\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-sw0\" && ip6 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:01; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lr0-sw0\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-sw1\" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:03; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 254; outport = \"lr0-sw1\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=30   , match=(inport == \"lr0-sw1\" && ip6 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:03; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff03; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = \"lr0-sw1\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lr0-public\" && ip4 && ip4.src == 172.168.0.0/24 && ip.ttl == {0, 1} && !ip.later_frag && is_chassis_resident(\"cr-lr0-public\")), action=(icmp4 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:02; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 172.168.0.10; ip.ttl = 254; outport = \"lr0-public\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lr0-sw0\" && ip4 && ip4.src == 10.0.0.0/24 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:01; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 254; outport = \"lr0-sw0\"; flags.loopback = 1; output; };)\n+  table=??(lr_in_ip_input     ), priority=31   , match=(inport == \"lr0-sw1\" && ip4 && ip4.src == 20.0.0.0/24 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst = eth.src; eth.src = 00:00:00:00:ff:03; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 254; outport = \"lr0-sw1\"; flags.loopback = 1; output; };)\n   table=??(lr_in_ip_input     ), priority=32   , match=(ip.ttl == {0, 1} && !ip.later_frag && (ip4.mcast || ip6.mcast)), action=(drop;)\n   table=??(lr_in_ip_input     ), priority=50   , match=(eth.bcast), action=(drop;)\n   table=??(lr_in_ip_input     ), priority=60   , match=(ip4.dst == {10.0.0.1}), action=(drop;)\n","prefixes":["ovs-dev","v3"]}