From patchwork Tue Aug 11 07:34:04 2020
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Numan Siddique
These flows reply to ARP requests or IPv6 neighbor solicitation
- for the virtual IP addresses configured in the router for DNAT
- or load balancing.
+ for the virtual IP addresses configured in the router for NAT
+ (both DNAT and SNAT) or load balancing.
- IPv4: For a configured DNAT IP address or a load balancer
- IPv4 VIP A, for each router port P with
- Ethernet address E, a priority-90 flow matches
- arp.op == 1 && arp.tpa == A
+ IPv4: For a configured NAT (both DNAT and SNAT) IP address or a
+ load balancer IPv4 VIP A, for each router port
+ P with Ethernet address E, a priority-90 flow
+ matches arp.op == 1 && arp.tpa == A
(ARP request) with the following actions:
- IPv6: For a configured DNAT IP address or a load balancer
- IPv6 VIP A, solicited node address S,
- for each router port P with
+ IPv6: For a configured NAT (both DNAT and SNAT) IP address or a
+ load balancer IPv6 VIP A, solicited node address
+ S, for each router port P with
Ethernet address E, a priority-90 flow matches
inport == P && nd_ns &&
ip6.dst == {A, S} &&
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index 99eb582c3..3b0272b00 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -8648,6 +8648,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
* per logical port but DNAT addresses can be handled per datapath
* for non gateway router ports.
*/
+ struct sset snat_ips = SSET_INITIALIZER(&snat_ips);
for (int i = 0; i < od->nbr->n_nat; i++) {
struct ovn_nat *nat_entry = &od->nat_entries[i];
const struct nbrec_nat *nat = nat_entry->nb;
@@ -8657,15 +8658,22 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
continue;
}
+ struct lport_addresses *ext_addrs = &nat_entry->ext_addrs;
+ char *ext_addr = nat_entry_is_v6(nat_entry) ?
+ ext_addrs->ipv6_addrs[0].addr_s :
+ ext_addrs->ipv4_addrs[0].addr_s;
+
if (!strcmp(nat->type, "snat")) {
- continue;
+ if (sset_contains(&snat_ips, ext_addr)) {
+ continue;
+ }
+ sset_add(&snat_ips, ext_addr);
}
/* Priority 91 and 92 flows are added for each gateway router
* port to handle the special cases. In case we get the packet
* on a regular port, just reply with the port's ETH address.
*/
- struct lport_addresses *ext_addrs = &nat_entry->ext_addrs;
if (nat_entry_is_v6(nat_entry)) {
build_lrouter_nd_flow(od, NULL, "nd_na",
ext_addrs->ipv6_addrs[0].addr_s,
@@ -8679,6 +8687,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
&nat->header_, lflows);
}
}
+ sset_destroy(&snat_ips);
+
/* Drop ARP packets (priority 85). ARP request packets for router's own
* IPs are handled with priority-90 flows.
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index 7872d5051..8344c7f5e 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -1572,6 +1572,8 @@ ovn-nbctl set logical_router lr options:chassis=ch
ovn-nbctl lr-nat-add lr dnat_and_snat 43.43.43.2 42.42.42.2
ovn-nbctl lr-nat-add lr dnat 43.43.43.3 42.42.42.3
ovn-nbctl lr-nat-add lr dnat_and_snat 43.43.43.4 42.42.42.4 ls-vm 00:00:00:00:00:02
+ovn-nbctl lr-nat-add lr snat 43.43.43.150 43.43.43.50
+ovn-nbctl lr-nat-add lr snat 43.43.43.150 43.43.43.51
ovn-nbctl --wait=sb sync
@@ -1594,6 +1596,9 @@ action=(xreg0[[0..47]] = 00:00:00:00:01:00; next;)
# Ingress router port ETH address is used for ARP reply/NA in lr_in_ip_input.
AT_CHECK([ovn-sbctl lflow-list | grep -E "lr_in_ip_input.*priority=90" | grep "arp\|nd" | sort], [0], [dnl
table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(arp.op == 1 && arp.tpa == 43.43.43.150), dnl
+action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 43.43.43.150; outport = inport; flags.loopback = 1; output;)
+ table=3 (lr_in_ip_input ), priority=90 , dnl
match=(arp.op == 1 && arp.tpa == 43.43.43.2), dnl
action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 43.43.43.2; outport = inport; flags.loopback = 1; output;)
table=3 (lr_in_ip_input ), priority=90 , dnl
@@ -1648,6 +1653,9 @@ action=(xreg0[[0..47]] = 00:00:00:00:01:00; next;)
# Priority 90 flows (per router).
AT_CHECK([ovn-sbctl lflow-list | grep -E "lr_in_ip_input.*priority=90" | grep "arp\|nd" | sort], [0], [dnl
table=3 (lr_in_ip_input ), priority=90 , dnl
+match=(arp.op == 1 && arp.tpa == 43.43.43.150), dnl
+action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 43.43.43.150; outport = inport; flags.loopback = 1; output;)
+ table=3 (lr_in_ip_input ), priority=90 , dnl
match=(arp.op == 1 && arp.tpa == 43.43.43.2), dnl
action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa; arp.spa = 43.43.43.2; outport = inport; flags.loopback = 1; output;)
table=3 (lr_in_ip_input ), priority=90 , dnl