From patchwork Mon Apr 15 12:14:13 2024
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Martin Kalcok
ct_commit_to_zone(dnat);
ct_commit_to_zone(snat);
+ Commit the flow to the specific zone in the connection tracker.
+ Similar to the ct_commit
action, this action requires
+ previous call to ct_next
to initialize connection
+ tracking state.
+
+ If you want processing to continue in the next table, you must
+ execute the next
action after
+ ct_commit_to_zone
.
+
+ Note that this action is meaningful only in the Logical Router + Datapath as the Logical Switch Datapath does not use separate + connection tracking zones. Using this action in Logical Switch + Datapath falls back to committing the flow into the switch's + default zone. +
+ct_dnat;
ct_dnat(IP);
lr_out_snat
, to
+ effectively match on various CT states.
+ lr_out_undnat
for Gateway
@@ -5068,6 +5075,18 @@ nd_ns {
ip4.src == A && outport
+ == GW
, this flow matches on ip4.dst ==
+ A && inport == GW
. A CT state is
+ initiated for this traffic so that the following table,
+ lr_out_post_snat
, can identify whether the traffic flow was
+ initiated from the internal or external network.
+
+ 1
has actions
next;
.
@@ -5079,6 +5098,16 @@ nd_ns {
Packets reaching this table are processed according to the flows below:
ct.new
), is committed to the SNAT CT zone.
+ This ensures that replies returning from the SNATed network do not
+ have their source address translated. For details about match rules
+ and priority see section "Egress Table 3: SNAT on Distributed
+ Routers".
+ 1
) and action next;
.
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index be006fb32..3c9d9309b 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -1107,7 +1107,8 @@ ovn_start
#
# DR is connected to S1 and CR is connected to S2
-check ovn-sbctl chassis-add gw1 geneve 127.0.0.1
+check ovn-sbctl chassis-add gw1 geneve 127.0.0.1 \
+ -- set chassis gw1 other_config:ct-commit-to-zone="true"
check ovn-nbctl lr-add DR
check ovn-nbctl lrp-add DR DR-S1 02:ac:10:01:00:01 172.16.1.1/24
@@ -1155,15 +1156,24 @@ AT_CAPTURE_FILE([crflows])
AT_CHECK([grep -e "lr_out_snat" drflows | ovn_strip_lflows], [0], [dnl
table=??(lr_out_snat ), priority=0 , match=(1), action=(next;)
table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
+ table=??(lr_out_snat ), priority=161 , match=(ip && ip4.dst == 50.0.0.11 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.src == $allowed_range), action=(ct_snat;)
table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.dst == $allowed_range && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.1);)
])
+AT_CHECK([grep -e "lr_out_post_snat" drflows | ovn_strip_lflows], [0], [dnl
+ table=??(lr_out_post_snat ), priority=0 , match=(1), action=(next;)
+ table=??(lr_out_post_snat ), priority=161 , match=(ip && ip4.dst == 50.0.0.11 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.src == $allowed_range && ct.new), action=(ct_commit_to_zone(snat); next; )
+])
+
AT_CHECK([grep -e "lr_out_snat" crflows | ovn_strip_lflows], [0], [dnl
table=??(lr_out_snat ), priority=0 , match=(1), action=(next;)
table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $allowed_range && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.1);)
])
+AT_CHECK([grep -e "lr_out_post_snat" crflows | ovn_strip_lflows], [0], [dnl
+ table=??(lr_out_post_snat ), priority=0 , match=(1), action=(next;)
+])
# SNAT with DISALLOWED_IPs
check ovn-nbctl lr-nat-del DR snat 50.0.0.11
@@ -1185,10 +1195,16 @@ AT_CAPTURE_FILE([crflows2])
AT_CHECK([grep -e "lr_out_snat" drflows2 | ovn_strip_lflows], [0], [dnl
table=??(lr_out_snat ), priority=0 , match=(1), action=(next;)
table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
+ table=??(lr_out_snat ), priority=161 , match=(ip && ip4.dst == 50.0.0.11 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1")), action=(ct_snat;)
table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.1);)
table=??(lr_out_snat ), priority=163 , match=(ip && ip4.src == 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.dst == $disallowed_range), action=(next;)
])
+AT_CHECK([grep -e "lr_out_post_snat" drflows2 | ovn_strip_lflows], [0], [dnl
+ table=??(lr_out_post_snat ), priority=0 , match=(1), action=(next;)
+ table=??(lr_out_post_snat ), priority=161 , match=(ip && ip4.dst == 50.0.0.11 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ct.new), action=(ct_commit_to_zone(snat); next; )
+])
+
AT_CHECK([grep -e "lr_out_snat" crflows2 | ovn_strip_lflows], [0], [dnl
table=??(lr_out_snat ), priority=0 , match=(1), action=(next;)
table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
@@ -1196,6 +1212,10 @@ AT_CHECK([grep -e "lr_out_snat" crflows2 | ovn_strip_lflows], [0], [dnl
table=??(lr_out_snat ), priority=35 , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $disallowed_range), action=(next;)
])
+AT_CHECK([grep -e "lr_out_post_snat" crflows2 | ovn_strip_lflows], [0], [dnl
+ table=??(lr_out_post_snat ), priority=0 , match=(1), action=(next;)
+])
+
# Stateful FIP with ALLOWED_IPs
check ovn-nbctl lr-nat-del DR snat 50.0.0.11
check ovn-nbctl lr-nat-del CR snat 50.0.0.11
@@ -1217,12 +1237,20 @@ AT_CHECK([grep -e "lr_out_snat" drflows3 | ovn_strip_lflows], [0], [dnl
table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.dst == $allowed_range && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.2);)
])
+AT_CHECK([grep -e "lr_out_post_snat" drflows3 | ovn_strip_lflows], [0], [dnl
+ table=??(lr_out_post_snat ), priority=0 , match=(1), action=(next;)
+])
+
AT_CHECK([grep -e "lr_out_snat" crflows3 | ovn_strip_lflows], [0], [dnl
table=??(lr_out_snat ), priority=0 , match=(1), action=(next;)
table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $allowed_range && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.2);)
])
+AT_CHECK([grep -e "lr_out_post_snat" crflows3 | ovn_strip_lflows], [0], [dnl
+ table=??(lr_out_post_snat ), priority=0 , match=(1), action=(next;)
+])
+
# Stateful FIP with DISALLOWED_IPs
ovn-nbctl lr-nat-del DR dnat_and_snat 172.16.1.2
ovn-nbctl lr-nat-del CR dnat_and_snat 172.16.1.2
@@ -1279,7 +1307,7 @@ AT_CHECK([grep -e "lr_out_snat" crflows5 | ovn_strip_lflows], [0], [dnl
table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $allowed_range), action=(ip4.src=172.16.1.2; next;)
])
-# Stateful FIP with DISALLOWED_IPs
+# Stateless FIP with DISALLOWED_IPs
ovn-nbctl lr-nat-del DR dnat_and_snat 172.16.1.2
ovn-nbctl lr-nat-del CR dnat_and_snat 172.16.1.2
@@ -5521,7 +5549,8 @@ AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
check ovn-sbctl chassis-add gw1 geneve 127.0.0.1 \
-- set chassis gw1 other_config:ct-no-masked-label="true" \
- -- set chassis gw1 other_config:ovn-ct-lb-related="true"
+ -- set chassis gw1 other_config:ovn-ct-lb-related="true" \
+ -- set chassis gw1 other_config:ct-commit-to-zone="true"
# Create a distributed gw port on lr0
check ovn-nbctl ls-add public
@@ -5622,16 +5651,26 @@ AT_CHECK([grep "lr_out_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
table=??(lr_out_post_undnat ), priority=0 , match=(1), action=(next;)
+ table=??(lr_out_post_undnat ), priority=70 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat; )
+ table=??(lr_out_post_undnat ), priority=70 , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat; )
])
AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
table=??(lr_out_snat ), priority=0 , match=(1), action=(next;)
table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
+ table=??(lr_out_snat ), priority=153 , match=(ip && ip4.dst == 10.0.0.0/24 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
table=??(lr_out_snat ), priority=153 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.10);)
+ table=??(lr_out_snat ), priority=161 , match=(ip && ip4.dst == 10.0.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.30);)
table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.20);)
])
+AT_CHECK([grep "lr_out_post_snat" lr0flows | ovn_strip_lflows], [0], [dnl
+ table=??(lr_out_post_snat ), priority=0 , match=(1), action=(next;)
+ table=??(lr_out_post_snat ), priority=153 , match=(ip && ip4.dst == 10.0.0.0/24 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") && ct.new), action=(ct_commit_to_zone(snat); next; )
+ table=??(lr_out_post_snat ), priority=161 , match=(ip && ip4.dst == 10.0.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") && ct.new), action=(ct_commit_to_zone(snat); next; )
+])
+
# Associate load balancer to lr0
check ovn-nbctl lb-add lb0 172.168.0.100:8082 "10.0.0.50:82,10.0.0.60:82"
@@ -5770,16 +5809,26 @@ AT_CHECK([grep "lr_out_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
AT_CHECK([grep "lr_out_post_undnat" lr0flows | ovn_strip_lflows], [0], [dnl
table=??(lr_out_post_undnat ), priority=0 , match=(1), action=(next;)
+ table=??(lr_out_post_undnat ), priority=70 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat; )
+ table=??(lr_out_post_undnat ), priority=70 , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat; )
])
AT_CHECK([grep "lr_out_snat" lr0flows | ovn_strip_lflows], [0], [dnl
table=??(lr_out_snat ), priority=0 , match=(1), action=(next;)
table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;)
+ table=??(lr_out_snat ), priority=153 , match=(ip && ip4.dst == 10.0.0.0/24 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
table=??(lr_out_snat ), priority=153 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.10);)
+ table=??(lr_out_snat ), priority=161 , match=(ip && ip4.dst == 10.0.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.30);)
table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.20);)
])
+AT_CHECK([grep "lr_out_post_snat" lr0flows | ovn_strip_lflows], [0], [dnl
+ table=??(lr_out_post_snat ), priority=0 , match=(1), action=(next;)
+ table=??(lr_out_post_snat ), priority=153 , match=(ip && ip4.dst == 10.0.0.0/24 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") && ct.new), action=(ct_commit_to_zone(snat); next; )
+ table=??(lr_out_post_snat ), priority=161 , match=(ip && ip4.dst == 10.0.0.10 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public") && ct.new), action=(ct_commit_to_zone(snat); next; )
+])
+
# Make the logical router as Gateway router
check ovn-nbctl clear logical_router_port lr0-public gateway_chassis
check ovn-nbctl set logical_router lr0 options:chassis=gw1
@@ -7606,9 +7655,14 @@ ovn_start
# Validate SNAT, DNAT and DNAT_AND_SNAT behavior with multiple
# distributed gateway LRPs.
-check ovn-sbctl chassis-add gw1 geneve 127.0.0.1
-check ovn-sbctl chassis-add gw2 geneve 128.0.0.1
-check ovn-sbctl chassis-add gw3 geneve 129.0.0.1
+check ovn-sbctl chassis-add gw1 geneve 127.0.0.1 \
+ -- set chassis gw1 other_config:ct-commit-to-zone="true"
+
+check ovn-sbctl chassis-add gw2 geneve 128.0.0.1 \
+ -- set chassis gw2 other_config:ct-commit-to-zone="true"
+
+check ovn-sbctl chassis-add gw3 geneve 129.0.0.1 \
+ -- set chassis gw3 other_config:ct-commit-to-zone="true"
check ovn-nbctl lr-add DR
check ovn-nbctl lrp-add DR DR-S1 02:ac:10:01:00:01 172.16.1.1/24
@@ -7673,11 +7727,21 @@ AT_CHECK([grep lr_in_unsnat lrflows | grep ct_snat | ovn_strip_lflows], [0], [dn
])
AT_CHECK([grep lr_out_snat lrflows | grep ct_snat | ovn_strip_lflows], [0], [dnl
+ table=??(lr_out_snat ), priority=161 , match=(ip && ip4.dst == 20.0.0.10 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1")), action=(ct_snat;)
+ table=??(lr_out_snat ), priority=161 , match=(ip && ip4.dst == 20.0.0.10 && inport == "DR-S2" && is_chassis_resident("cr-DR-S2")), action=(ct_snat;)
+ table=??(lr_out_snat ), priority=161 , match=(ip && ip4.dst == 20.0.0.10 && inport == "DR-S3" && is_chassis_resident("cr-DR-S3")), action=(ct_snat;)
table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 20.0.0.10 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.10);)
table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 20.0.0.10 && outport == "DR-S2" && is_chassis_resident("cr-DR-S2") && (!ct.trk || !ct.rpl)), action=(ct_snat(10.0.0.10);)
table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 20.0.0.10 && outport == "DR-S3" && is_chassis_resident("cr-DR-S3") && (!ct.trk || !ct.rpl)), action=(ct_snat(192.168.0.10);)
])
+AT_CHECK([grep lr_out_post_snat lrflows | ovn_strip_lflows], [0], [dnl
+ table=??(lr_out_post_snat ), priority=0 , match=(1), action=(next;)
+ table=??(lr_out_post_snat ), priority=161 , match=(ip && ip4.dst == 20.0.0.10 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ct.new), action=(ct_commit_to_zone(snat); next; )
+ table=??(lr_out_post_snat ), priority=161 , match=(ip && ip4.dst == 20.0.0.10 && inport == "DR-S2" && is_chassis_resident("cr-DR-S2") && ct.new), action=(ct_commit_to_zone(snat); next; )
+ table=??(lr_out_post_snat ), priority=161 , match=(ip && ip4.dst == 20.0.0.10 && inport == "DR-S3" && is_chassis_resident("cr-DR-S3") && ct.new), action=(ct_commit_to_zone(snat); next; )
+])
+
check ovn-nbctl --wait=sb lr-nat-del DR snat 20.0.0.10
AT_CHECK([ovn-sbctl dump-flows DR | grep -e lr_in_unsnat -e lr_out_snat | grep ct_snat | wc -l], [0], [0
])
diff --git a/tests/system-ovn.at b/tests/system-ovn.at
index c699f7960..68adfa4e6 100644
--- a/tests/system-ovn.at
+++ b/tests/system-ovn.at
@@ -3574,6 +3574,39 @@ NS_CHECK_EXEC([foo1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.1 | FORMAT_PING], \
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])
+# test_connectivity_from_ext takes parameters 'vm' and 'ip'. It tests
+# icmp, udp and tcp connectivity from external network to the 'vm' on
+# the specified 'ip'.
+test_connectivity_from_ext() {
+ local vm=$1; shift
+ local ip=$1; shift
+
+ # Start listening daemons for UDP and TCP connections
+ NETNS_DAEMONIZE($vm, [nc -l -u 1234], [nc-$vm-$ip-udp.pid])
+ NETNS_DAEMONIZE($vm, [nc -l -k 1235], [nc-$vm-$ip-tcp.pid])
+
+ # Ensure that vm can be pinged on the specified IP
+ NS_CHECK_EXEC([alice1], [ping -q -c 3 -i 0.3 -w 2 $ip | FORMAT_PING], \
+ [0], [dnl
+3 packets transmitted, 3 received, 0% packet loss, time 0ms
+])
+
+ # Perform two consecutive UDP connections to the specified IP
+ NS_CHECK_EXEC([alice1], [nc -u $ip 1234 -p 2000 -z])
+ NS_CHECK_EXEC([alice1], [nc -u $ip 1234 -p 2000 -z])
+
+ # Send data over TCP connection to the specified IP
+ NS_CHECK_EXEC([alice1], [echo "TCP test" | nc --send-only $ip 1235])
+}
+
+# Test access from external network to the internal IP of a VM that
+# has also configured DNAT
+test_connectivity_from_ext foo1 192.168.1.2
+
+# Test access from external network to the internal IP of a VM that
+# does not have DNAT
+test_connectivity_from_ext bar1 192.168.2.2
+
OVS_WAIT_UNTIL([
total_pkts=$(cat ext-net.tcpdump | wc -l)
test "${total_pkts}" = "3"
@@ -3740,6 +3773,39 @@ sed -e 's/zone=[[0-9]]*/zone=