When a logical router port has multiple IP addresses from different networks,
northd generates multiple TTL exceeded flows. Previously, these flows had
identical match conditions but different actions (using different ICMP reply
source IPs), leading to non-deterministic behavior where replies could use
an incorrect source IP not belonging to the original packet's destination
network.
The fix adds source IP network matching to flow, ensuring that ICMP TTL exceeded
replies always originate from an IP in the same network as the source of the
original packet.
Additionally, the default TTL exceeded flow behavior has been unified for IPv4
and IPv6: previously, packets that didn't match any configured subnet were
dropped; now we trigger a reply using the first IP address configured on the
router port.
Fixes: c0321040c703 ("OVN: add ICMPv6 time exceeded support to OVN logical
router")
Fixes: 7f19374c5933 ("OVN: add ICMP time exceeded support to OVN logical
router")
Reported-at: https://issues.redhat.com/browse/FDP-2870
Signed-off-by: Alexandra Rukomoinikova <[email protected]>
---
northd/northd.c | 223 +++++++++++++++++++++++++++++---------------
tests/ovn-northd.at | 35 ++++---
tests/ovn.at | 32 ++++---
3 files changed, 193 insertions(+), 97 deletions(-)
diff --git a/northd/northd.c b/northd/northd.c
index 9c3fa8735..843c28216 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -16030,11 +16030,6 @@ build_misc_local_traffic_drop_flows_for_lrouter(
"(ip4.mcast || ip6.mcast)", debug_drop_action(),
lflow_ref);
- /* TTL discard */
- ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 30,
- "ip.ttl == {0, 1}", debug_drop_action(),
- lflow_ref);
-
/* Pass other traffic not already handled to the next table for
* routing. */
ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 0, "1", "next;",
@@ -16225,6 +16220,150 @@ build_dhcp_relay_flows_for_lrouter_port(struct
ovn_port *op,
free(server_ip_str);
}
+static void
+build_lrouter_ipv4_default_ttl_expired_flows(
+ struct ovn_port *op, struct lflow_table *lflows,
+ struct ds *match, struct ds *actions,
+ const struct shash *meter_groups,
+ struct lflow_ref *lflow_ref)
+{
+ if (!op->lrp_networks.n_ipv4_addrs) {
+ return;
+ }
+
+ struct ds ip_ds = DS_EMPTY_INITIALIZER;
+ for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
+ ds_clear(match);
+ ds_clear(actions);
+ ds_clear(&ip_ds);
+ if (lrp_is_l3dgw(op)) {
+ ds_put_cstr(&ip_ds, "ip4.dst <-> ip4.src");
+ } else {
+ ds_put_format(&ip_ds, "ip4.dst = ip4.src; ip4.src = %s",
+ op->lrp_networks.ipv4_addrs[i].addr_s);
+ }
+ ds_put_format(match,
+ "inport == %s && ip4 && "
+ "ip4.src == %s/%d && "
+ "ip.ttl == {0, 1} && !ip.later_frag",
+ op->json_key,
+ op->lrp_networks.ipv4_addrs[i].network_s,
+ op->lrp_networks.ipv4_addrs[i].plen);
+ ds_put_format(actions,
+ "icmp4 {"
+ "eth.dst <-> eth.src; "
+ "icmp4.type = 11; /* Time exceeded */ "
+ "icmp4.code = 0; /* TTL exceeded in transit */ "
+ "%s ; ip.ttl = 254; "
+ "outport = %s; flags.loopback = 1; output; };",
+ ds_cstr(&ip_ds), op->json_key);
+ ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT,
+ 31, ds_cstr(match), ds_cstr(actions), NULL,
+ copp_meter_get(COPP_ICMP4_ERR, op->od->nbr->copp,
+ meter_groups),
+ &op->nbrp->header_, lflow_ref);
+
+ }
+ ds_destroy(&ip_ds);
+ ds_clear(match);
+ ds_clear(actions);
+
+ /* Default flow for IPv4 packets with expired TTL (0 or 1).
+ * Generate ICMPv4 Time Exceeded reply using the first IPv4 address
+ * of the logical router port as source address. */
+ ds_put_format(match,
+ "inport == %s && ip4 && ip.ttl == {0, 1}",
+ op->json_key);
+ ds_put_format(actions,
+ "icmp4 {"
+ "eth.dst <-> eth.src; "
+ "icmp4.type = 11; /* Time exceeded */ "
+ "icmp4.code = 0; /* TTL exceeded in transit */ "
+ "ip4.dst = ip4.src; ip4.src = %s; ip.ttl = 254; "
+ "outport = %s; flags.loopback = 1; output; };",
+ op->lrp_networks.ipv4_addrs[0].addr_s,
+ op->json_key);
+ ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT,
+ 30, ds_cstr(match), ds_cstr(actions), NULL,
+ copp_meter_get(COPP_ICMP4_ERR,
+ op->od->nbr->copp,
+ meter_groups),
+ &op->nbrp->header_, lflow_ref);
+}
+
+static void
+build_lrouter_ipv6_default_ttl_expired_flows(
+ struct ovn_port *op, struct lflow_table *lflows,
+ struct ds *match, struct ds *actions,
+ const struct shash *meter_groups,
+ struct lflow_ref *lflow_ref)
+{
+ /* Early return if no IPv6 addresses are configured.
+ * Note: op->lrp_networks.ipv6_addrs will always have LLA and that
+ * will be last in the list. */
+ if (op->lrp_networks.n_ipv6_addrs < 1) {
+ return;
+ }
+
+ struct ds ip_ds = DS_EMPTY_INITIALIZER;
+ for (size_t i = 0; i < op->lrp_networks.n_ipv6_addrs - 1; i++) {
+ ds_clear(match);
+ ds_clear(actions);
+ ds_clear(&ip_ds);
+ if (lrp_is_l3dgw(op)) {
+ ds_put_cstr(&ip_ds, "ip6.dst <-> ip6.src");
+ } else {
+ ds_put_format(&ip_ds, "ip6.dst = ip6.src; ip6.src = %s",
+ op->lrp_networks.ipv6_addrs[i].addr_s);
+ }
+ ds_put_format(match,
+ "inport == %s && ip6 && "
+ "ip6.src == %s/%d && "
+ "ip.ttl == {0, 1} && !ip.later_frag",
+ op->json_key,
+ op->lrp_networks.ipv6_addrs[i].network_s,
+ op->lrp_networks.ipv6_addrs[i].plen);
+ ds_put_format(actions,
+ "icmp6 {"
+ "eth.dst <-> eth.src; "
+ "%s ; ip.ttl = 254; "
+ "icmp6.type = 3; /* Time exceeded */ "
+ "icmp6.code = 0; /* TTL exceeded in transit */ "
+ "outport = %s; flags.loopback = 1; output; };",
+ ds_cstr(&ip_ds), op->json_key);
+ ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT,
+ 31, ds_cstr(match), ds_cstr(actions), NULL,
+ copp_meter_get(COPP_ICMP6_ERR, op->od->nbr->copp,
+ meter_groups),
+ &op->nbrp->header_, lflow_ref);
+ }
+ ds_destroy(&ip_ds);
+ ds_clear(match);
+ ds_clear(actions);
+
+ /* Default flow for IPv6 packets with expired TTL (0 or 1).
+ * Generate ICMPv6 Time Exceeded reply using the first IPv6 address
+ * of the logical router port as source address. */
+ ds_put_format(match,
+ "inport == %s && ip6 && ip.ttl == {0, 1}",
+ op->json_key);
+ ds_put_format(actions,
+ "icmp6 {"
+ "eth.dst <-> eth.src; "
+ "ip6.dst = ip6.src; ip6.src = %s; "
+ "ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ "
+ "icmp6.code = 0; /* TTL exceeded in transit */ "
+ "outport = %s; flags.loopback = 1; output; };",
+ op->lrp_networks.ipv6_addrs[0].addr_s,
+ op->json_key);
+ ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT,
+ 30, ds_cstr(match), ds_cstr(actions), NULL,
+ copp_meter_get(COPP_ICMP6_ERR,
+ op->od->nbr->copp,
+ meter_groups),
+ &op->nbrp->header_, lflow_ref);
+}
+
static void
build_ipv6_input_flows_for_lrouter_port(
struct ovn_port *op, struct lflow_table *lflows,
@@ -16359,44 +16498,9 @@ build_ipv6_input_flows_for_lrouter_port(
}
/* ICMPv6 time exceeded */
- struct ds ip_ds = DS_EMPTY_INITIALIZER;
- for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) {
- /* skip link-local address */
- if (in6_is_lla(&op->lrp_networks.ipv6_addrs[i].network)) {
- continue;
- }
-
- ds_clear(match);
- ds_clear(actions);
- ds_clear(&ip_ds);
- if (lrp_is_l3dgw(op)) {
- ds_put_cstr(&ip_ds, "ip6.dst <-> ip6.src");
- } else {
- ds_put_format(&ip_ds, "ip6.dst = ip6.src; ip6.src = %s",
- op->lrp_networks.ipv6_addrs[i].addr_s);
- }
- ds_put_format(match,
- "inport == %s && ip6 && "
- "ip6.src == %s/%d && "
- "ip.ttl == {0, 1} && !ip.later_frag",
- op->json_key,
- op->lrp_networks.ipv6_addrs[i].network_s,
- op->lrp_networks.ipv6_addrs[i].plen);
- ds_put_format(actions,
- "icmp6 {"
- "eth.dst <-> eth.src; "
- "%s ; ip.ttl = 254; "
- "icmp6.type = 3; /* Time exceeded */ "
- "icmp6.code = 0; /* TTL exceeded in transit */ "
- "outport = %s; flags.loopback = 1; output; };",
- ds_cstr(&ip_ds), op->json_key);
- ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT,
- 31, ds_cstr(match), ds_cstr(actions), NULL,
- copp_meter_get(COPP_ICMP6_ERR, op->od->nbr->copp,
- meter_groups),
- &op->nbrp->header_, lflow_ref);
- }
- ds_destroy(&ip_ds);
+ build_lrouter_ipv6_default_ttl_expired_flows(op, lflows,
+ match, actions,
+ meter_groups, lflow_ref);
}
static void
@@ -16505,36 +16609,9 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
build_lrouter_bfd_flows(lflows, op, meter_groups, bfd_ports, lflow_ref);
/* ICMP time exceeded */
- struct ds ip_ds = DS_EMPTY_INITIALIZER;
- for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
- ds_clear(match);
- ds_clear(actions);
- ds_clear(&ip_ds);
- if (lrp_is_l3dgw(op)) {
- ds_put_cstr(&ip_ds, "ip4.dst <-> ip4.src");
- } else {
- ds_put_format(&ip_ds, "ip4.dst = ip4.src; ip4.src = %s",
- op->lrp_networks.ipv4_addrs[i].addr_s);
- }
- ds_put_format(match,
- "inport == %s && ip4 && "
- "ip.ttl == {0, 1} && !ip.later_frag", op->json_key);
- ds_put_format(actions,
- "icmp4 {"
- "eth.dst <-> eth.src; "
- "icmp4.type = 11; /* Time exceeded */ "
- "icmp4.code = 0; /* TTL exceeded in transit */ "
- "%s ; ip.ttl = 254; "
- "outport = %s; flags.loopback = 1; output; };",
- ds_cstr(&ip_ds), op->json_key);
- ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT,
- 31, ds_cstr(match), ds_cstr(actions), NULL,
- copp_meter_get(COPP_ICMP4_ERR, op->od->nbr->copp,
- meter_groups),
- &op->nbrp->header_, lflow_ref);
-
- }
- ds_destroy(&ip_ds);
+ build_lrouter_ipv4_default_ttl_expired_flows(op, lflows,
+ match, actions,
+ meter_groups, lflow_ref);
/* ARP reply. These flows reply to ARP requests for the router's own
* IP address. */
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index e3df8c9fc..2b2e1d4ad 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -8185,10 +8185,13 @@ dnl Flows to skip TTL == {0, 1} check for IGMP and MLD
packets.
AT_CHECK([grep -e 'lr_in_ip_input ' lrflows | grep -e 'igmp' -e 'mld' -e
'ip.ttl == {0, 1}' | ovn_strip_lflows], [0], [dnl
table=??(lr_in_ip_input ), priority=120 , match=((mldv1 || mldv2) &&
ip.ttl == 1), action=(next;)
table=??(lr_in_ip_input ), priority=120 , match=(igmp && ip.ttl == 1),
action=(next;)
- table=??(lr_in_ip_input ), priority=30 , match=(ip.ttl == {0, 1}),
action=(drop;)
- table=??(lr_in_ip_input ), priority=31 , 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; };)
+ table=??(lr_in_ip_input ), priority=30 , match=(inport == "lrp1" &&
ip4 && ip.ttl == {0, 1}), 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; };)
+ table=??(lr_in_ip_input ), priority=30 , match=(inport == "lrp1" &&
ip6 && ip.ttl == {0, 1}), 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; };)
+ table=??(lr_in_ip_input ), priority=30 , match=(inport == "lrp2" &&
ip4 && ip.ttl == {0, 1}), 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; };)
+ table=??(lr_in_ip_input ), priority=30 , match=(inport == "lrp2" &&
ip6 && ip.ttl == {0, 1}), 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; };)
+ 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; };)
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; };)
- table=??(lr_in_ip_input ), priority=31 , 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; };)
+ 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; };)
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; };)
table=??(lr_in_ip_input ), priority=32 , match=(ip.ttl == {0, 1} &&
!ip.later_frag && (ip4.mcast || ip6.mcast)), action=(drop;)
])
@@ -13925,10 +13928,15 @@ AT_CHECK([grep "lr_in_ip_input" lr0flows |
ovn_strip_lflows], [0], [dnl
table=??(lr_in_ip_input ), priority=100 , match=(ip4.src == {20.0.0.1,
20.0.0.255} && reg9[[0]] == 0), action=(drop;)
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;)
table=??(lr_in_ip_input ), priority=120 , match=(inport == "lr0-public"
&& ip4.src == 172.168.0.100), action=(next;)
- table=??(lr_in_ip_input ), priority=30 , match=(ip.ttl == {0, 1}),
action=(drop;)
- table=??(lr_in_ip_input ), priority=31 , 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 ; ip.ttl = 254; outport = "lr0-public";
flags.loopback = 1; output; };)
- table=??(lr_in_ip_input ), priority=31 , 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; };)
- table=??(lr_in_ip_input ), priority=31 , 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; };)
+ table=??(lr_in_ip_input ), priority=30 , match=(inport == "lr0-public"
&& ip4 && ip.ttl == {0, 1}), 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; };)
+ table=??(lr_in_ip_input ), priority=30 , match=(inport == "lr0-public"
&& ip6 && ip.ttl == {0, 1}), 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; };)
+ table=??(lr_in_ip_input ), priority=30 , match=(inport == "lr0-sw0" &&
ip4 && ip.ttl == {0, 1}), 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; };)
+ table=??(lr_in_ip_input ), priority=30 , match=(inport == "lr0-sw0" &&
ip6 && ip.ttl == {0, 1}), 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; };)
+ table=??(lr_in_ip_input ), priority=30 , match=(inport == "lr0-sw1" &&
ip4 && ip.ttl == {0, 1}), 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; };)
+ table=??(lr_in_ip_input ), priority=30 , match=(inport == "lr0-sw1" &&
ip6 && ip.ttl == {0, 1}), 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; };)
+ 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),
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; };)
+ 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; };)
+ 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; };)
table=??(lr_in_ip_input ), priority=32 , match=(ip.ttl == {0, 1} &&
!ip.later_frag && (ip4.mcast || ip6.mcast)), action=(drop;)
table=??(lr_in_ip_input ), priority=50 , match=(eth.bcast),
action=(drop;)
table=??(lr_in_ip_input ), priority=60 , match=(ip4.dst ==
{10.0.0.1}), action=(drop;)
@@ -14102,10 +14110,15 @@ AT_CHECK([grep "lr_in_ip_input" lr0flows |
ovn_strip_lflows], [0], [dnl
table=??(lr_in_ip_input ), priority=100 , match=(ip4.src == {20.0.0.1,
20.0.0.255} && reg9[[0]] == 0), action=(drop;)
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;)
table=??(lr_in_ip_input ), priority=120 , match=(inport == "lr0-public"
&& ip4.src == 172.168.0.100), action=(next;)
- table=??(lr_in_ip_input ), priority=30 , match=(ip.ttl == {0, 1}),
action=(drop;)
- table=??(lr_in_ip_input ), priority=31 , 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 ; ip.ttl = 254; outport = "lr0-public";
flags.loopback = 1; output; };)
- table=??(lr_in_ip_input ), priority=31 , 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; };)
- table=??(lr_in_ip_input ), priority=31 , 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; };)
+ table=??(lr_in_ip_input ), priority=30 , match=(inport == "lr0-public"
&& ip4 && ip.ttl == {0, 1}), 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; };)
+ table=??(lr_in_ip_input ), priority=30 , match=(inport == "lr0-public"
&& ip6 && ip.ttl == {0, 1}), 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; };)
+ table=??(lr_in_ip_input ), priority=30 , match=(inport == "lr0-sw0" &&
ip4 && ip.ttl == {0, 1}), 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; };)
+ table=??(lr_in_ip_input ), priority=30 , match=(inport == "lr0-sw0" &&
ip6 && ip.ttl == {0, 1}), 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; };)
+ table=??(lr_in_ip_input ), priority=30 , match=(inport == "lr0-sw1" &&
ip4 && ip.ttl == {0, 1}), 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; };)
+ table=??(lr_in_ip_input ), priority=30 , match=(inport == "lr0-sw1" &&
ip6 && ip.ttl == {0, 1}), 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; };)
+ 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),
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; };)
+ 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; };)
+ 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; };)
table=??(lr_in_ip_input ), priority=32 , match=(ip.ttl == {0, 1} &&
!ip.later_frag && (ip4.mcast || ip6.mcast)), action=(drop;)
table=??(lr_in_ip_input ), priority=50 , match=(eth.bcast),
action=(drop;)
table=??(lr_in_ip_input ), priority=60 , match=(ip4.dst ==
{10.0.0.1}), action=(drop;)
diff --git a/tests/ovn.at b/tests/ovn.at
index 58127f0d3..a06ee04b0 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -20498,7 +20498,7 @@ AT_SETUP([TTL exceeded])
AT_KEYWORDS([ttl-exceeded])
ovn_start
-# test_ip_packet INPORT HV ETH_SRC ETH_DST IPV4_SRC IPV4_DST IPV4_ROUTER
IP_CHKSUM EXP_IP_CHKSUM EXP_ICMP_CHKSUM SHOULD_REPLY
+# test_ip_packet INPORT HV ETH_SRC ETH_DST IPV4_SRC IPV4_DST IP_SRC_REPLY
IP_CHKSUM EXP_IP_CHKSUM EXP_ICMP_CHKSUM SHOULD_REPLY
#
# Causes a packet to be received on INPORT of the hypervisor HV. The packet is
an IPv4 packet with
# ETH_SRC, ETH_DST, IPV4_SRC, IPV4_DST, IP_CHKSUM as specified and TTL set to
1.
@@ -20508,10 +20508,10 @@ ovn_start
# INPORT is a lport number, e.g. 11 for vif11.
# HV is a hypervisor number
# ETH_SRC and ETH_DST are each 12 hex digits.
-# IPV4_SRC, IPV4_DST and IPV4_ROUTER are each 8 hex digits.
+# IPV4_SRC, IPV4_DST and IP_SRC_REPLY are each 8 hex digits.
# IP_CHKSUM, EXP_IP_CHSUM and EXP_ICMP_CHKSUM are each 4 hex digits
test_ip_packet() {
- local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv4_src=$5 ipv4_dst=$6
ip_router=$7 ip_chksum=$8
+ local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv4_src=$5 ipv4_dst=$6
ip_src_reply=$7 ip_chksum=$8
local exp_ip_chksum=$9 exp_icmp_chksum=${10}
shift 10
local should_reply=$1
@@ -20524,28 +20524,28 @@ test_ip_packet() {
local icmp_data=00000000
local
reply_icmp_payload=${icmp_type_code_response}${exp_icmp_chksum}${icmp_data}
if test $should_reply == yes; then
- local
reply=${eth_src}${eth_dst}08004500003000004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload}
+ local
reply=${eth_src}${eth_dst}08004500003000004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_src_reply}${ipv4_src}${reply_icmp_payload}
echo $reply$orig_pkt_in_reply >> vif$inport.expected
fi
as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
}
-# test_ip6_packet INPORT HV ETH_SRC ETH_DST IPV6_SRC IPV6_DST IPV6_ROUTER
EXP_ICMP_CHKSUM SHOULD_REPLY
+# test_ip6_packet INPORT HV ETH_SRC ETH_DST IPV6_SRC IPV6_DST IPV6_SRC_REPLY
EXP_ICMP_CHKSUM SHOULD_REPLY
#
# Causes a packet to be received on INPORT of the hypervisor HV. The packet is
an IPv6
# packet with ETH_SRC, ETH_DST, IPV6_SRC and IPV6_DST as specified.
# IPV6_ROUTER and EXP_ICMP_CHKSUM are the source IP and checksum of the icmpv6
ttl exceeded
# packet sent by OVN logical router
test_ip6_packet() {
- local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv6_src=$5 ipv6_dst=$6
ipv6_router=$7 exp_icmp_chksum=$8 should_reply=$9
+ local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv6_src=$5 ipv6_dst=$6
ipv6_src_reply=$7 exp_icmp_chksum=$8 should_reply=$9
shift 8
local ip6_hdr=6000000000151101${ipv6_src}${ipv6_dst}
local
packet=${eth_dst}${eth_src}86dd${ip6_hdr}dbb8303900155bac6b646f65206676676e6d66720a
if test $should_reply == yes; then
- local
reply=${eth_src}${eth_dst}86dd6000000000453afe${ipv6_router}${ipv6_src}0300${exp_icmp_chksum}00000000${ip6_hdr}dbb8303900155bac6b646f65206676676e6d66720a
+ local
reply=${eth_src}${eth_dst}86dd6000000000453afe${ipv6_src_reply}${ipv6_src}0300${exp_icmp_chksum}00000000${ip6_hdr}dbb8303900155bac6b646f65206676676e6d66720a
echo $reply >> vif$inport.expected
fi
@@ -20576,10 +20576,8 @@ done
check ovn-nbctl lr-add lr0
for i in 1 2; do
- check ovn-nbctl lrp-add lr0 lrp$i 00:00:00:00:ff:0$i 192.168.$i.254/24
2001:db8:$i::1/64
- check ovn-nbctl -- lsp-add sw$i lrp$i-attachment \
- -- set Logical_Switch_Port lrp$i-attachment type=router \
- options:router-port=lrp$i addresses='"00:00:00:00:ff:0'$i'
192.168.'$i'.254 2001:db8:'$i'::1"'
+ check ovn-nbctl lrp-add lr0 lrp$i 00:00:00:00:ff:0$i 172.31.$i.254/24
192.168.$i.254/24 2001:db8:$i::1/64 2002:db8:$i::1/64
+ check ovn-nbctl lsp-add-router-port sw$i lrp$i-attachment lrp$i
done
OVN_POPULATE_ARP
@@ -20587,20 +20585,28 @@ OVN_POPULATE_ARP
wait_for_ports_up
check ovn-nbctl --wait=hv sync
+# Test packet with source IP from router's networks
test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1)
$(ip_to_hex 192 168 2 1) $(ip_to_hex 192 168 1 254) 0000 f87c ea96 yes
test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011
20010db8000200000000000000000011 20010db8000100000000000000000001 1c22 yes
+test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 172 31 1 5)
$(ip_to_hex 192 168 2 1) $(ip_to_hex 172 31 1 254) 0000 218b ff1b yes
+test_ip6_packet 1 1 000000000001 00000000ff01 20020db8000100000000000000000011
20010db8000200000000000000000011 20020db8000100000000000000000001 1c1f yes
+
+# Test packet with source IP from external network - expect reply from first
router's IP
+test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 1 1 1 1) $(ip_to_hex
192 168 2 1) $(ip_to_hex 172 31 1 254) 0000 ccad aa3e yes
+test_ip6_packet 1 1 000000000001 00000000ff01 20030db8000100000000000000000011
20010db8000200000000000000000011 20010db8000100000000000000000001 1c1e yes
+
# Should not send ICMP for multicast
test_ip_packet 1 1 000000000001 01005e7f0001 $(ip_to_hex 192 168 1 1)
$(ip_to_hex 239 255 0 1) $(ip_to_hex 192 168 1 254) 0000 000000000 no
test_ip6_packet 1 1 000000000001 333300000001 20010db8000100000000000000000011
ff020000000000000000000000000001 20010db8000100000000000000000001 0000 no
OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [vif1.expected])
-# Confirm from debug log that we only see 2 packet-ins (no packet-ins for
+# Confirm from debug log that we only see 6 packet-ins (no packet-ins for
# multicasts). This is necessary because not seeing ICMP messages doesn't
# necessarily mean the packet-in didn't happen. It is possible that packet-in
# is processed but the ICMP message got dropped.
-AT_CHECK([grep -c packet-in hv1/ovn-controller.log], [0], [2
+AT_CHECK([grep -c packet-in hv1/ovn-controller.log], [0], [6
])
OVN_CLEANUP([hv1], [hv2])
--
2.48.1
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev