Skip to content

Commit 551e3d9

Browse files
LorenzoBianconiblp
authored andcommitted
OVN: fix DVR Floating IP support
When DVR is enabled FIP traffic need to be forwarded directly using external connection to the underlay network and not be distributed through geneve tunnels. Fix this adding new logical flows to take care of distributed DNAT/SNAT Acked-by: Mark Michelson <mmichels@redhat.com> Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com> Signed-off-by: Ben Pfaff <blp@ovn.org>
1 parent b31c760 commit 551e3d9

File tree

2 files changed

+156
-0
lines changed

2 files changed

+156
-0
lines changed

northd/ovn-northd.8.xml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1861,6 +1861,37 @@ output;
18611861
</p>
18621862

18631863
<ul>
1864+
<li>
1865+
<p>
1866+
For distributed logical routers where one of the logical router
1867+
ports specifies a <code>redirect-chassis</code>, a priority-400
1868+
logical flow for each ip source/destination couple that matches the
1869+
<code>dnat_and_snat</code> NAT rules configured. These flows will
1870+
allow to properly forward traffic to the external connections if
1871+
available and avoid sending it through the tunnel.
1872+
Assuming the two following NAT rules have been configured:
1873+
</p>
1874+
1875+
<pre>
1876+
external_ip{0,1} = <var>EIP{0,1}</var>;
1877+
external_mac{0,1} = <var>MAC{0,1}</var>;
1878+
logical_ip{0,1} = <var>LIP{0,1}</var>;
1879+
</pre>
1880+
1881+
<p>
1882+
the following action will be applied:
1883+
</p>
1884+
1885+
<pre>
1886+
eth.dst = <var>MAC0</var>;
1887+
eth.src = <var>MAC1</var>;
1888+
reg0 = ip4.dst;
1889+
reg1 = <var>EIP1</var>;
1890+
outport = <code>redirect-chassis-port</code>;
1891+
<code>REGBIT_DISTRIBUTED_NAT = 1; next;</code>.
1892+
</pre>
1893+
</li>
1894+
18641895
<li>
18651896
<p>
18661897
For distributed logical routers where one of the logical router
@@ -1957,6 +1988,12 @@ next;
19571988

19581989
<ul>
19591990
<li>
1991+
<p>
1992+
For distributed logical routers where one of the logical router
1993+
ports specifies a <code>redirect-chassis</code>, a priority-400
1994+
logical flow with match <code>REGBIT_DISTRIBUTED_NAT == 1</code>
1995+
has action <code>next;</code>
1996+
</p>
19601997
<p>
19611998
For distributed logical routers where one of the logical router
19621999
ports specifies a <code>redirect-chassis</code>, a priority-200
@@ -2045,6 +2082,11 @@ next;
20452082
</p>
20462083

20472084
<ul>
2085+
<li>
2086+
A priority-300 logical flow with match
2087+
<code>REGBIT_DISTRIBUTED_NAT == 1</code> has action
2088+
<code>next;</code>
2089+
</li>
20482090
<li>
20492091
A priority-200 logical flow with match
20502092
<code>REGBIT_NAT_REDIRECT == 1</code> has actions
@@ -2354,6 +2396,15 @@ nd_ns {
23542396

23552397
<ul>
23562398
<li>
2399+
<p>
2400+
For each <code>dnat_and_snat</code> NAT rule couple in the
2401+
OVN Northbound database on a distributed router,
2402+
a priority-200 logical with match
2403+
<code>ip4.dst == <var>external_ip0</var> &amp;&amp;
2404+
ip4.src == <var>external_ip1</var></code>, has action
2405+
<code>next;</code>
2406+
</p>
2407+
23572408
<p>
23582409
For each NAT rule in the OVN Northbound database on a
23592410
distributed router, a priority-100 logical flow with match

northd/ovn-northd.c

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ enum ovn_stage {
181181
* logical router dropping packets with source IP address equals
182182
* one of the logical router's own IP addresses. */
183183
#define REGBIT_EGRESS_LOOPBACK "reg9[1]"
184+
#define REGBIT_DISTRIBUTED_NAT "reg9[2]"
184185

185186
/* Returns an "enum ovn_stage" built from the arguments. */
186187
static enum ovn_stage
@@ -5009,6 +5010,66 @@ find_lrp_member_ip(const struct ovn_port *op, const char *ip_s)
50095010
return NULL;
50105011
}
50115012

5013+
static void
5014+
add_distributed_nat_routes(struct hmap *lflows, const struct ovn_port *op)
5015+
{
5016+
struct ds actions = DS_EMPTY_INITIALIZER;
5017+
struct ds match = DS_EMPTY_INITIALIZER;
5018+
5019+
if (!op->od->l3dgw_port) {
5020+
return;
5021+
}
5022+
5023+
if (!op->peer || !op->peer->od->nbs) {
5024+
return;
5025+
}
5026+
5027+
for (size_t i = 0; i < op->od->nbr->n_nat; i++) {
5028+
const struct nbrec_nat *nat = op->od->nbr->nat[i];
5029+
bool found = false;
5030+
5031+
if (strcmp(nat->type, "dnat_and_snat") ||
5032+
!nat->external_mac || !nat->external_ip) {
5033+
continue;
5034+
}
5035+
5036+
const struct ovn_datapath *peer_dp = op->peer->od;
5037+
for (size_t j = 0; j < peer_dp->nbs->n_ports; j++) {
5038+
if (!strcmp(peer_dp->nbs->ports[j]->name, nat->logical_port)) {
5039+
found = true;
5040+
break;
5041+
}
5042+
}
5043+
if (!found) {
5044+
continue;
5045+
}
5046+
5047+
for (size_t j = 0; j < op->od->nbr->n_nat; j++) {
5048+
const struct nbrec_nat *nat2 = op->od->nbr->nat[j];
5049+
5050+
if (nat == nat2 || strcmp(nat2->type, "dnat_and_snat") ||
5051+
!nat2->external_mac || !nat2->external_ip)
5052+
continue;
5053+
5054+
ds_put_format(&match, "inport == %s && "
5055+
"ip4.src == %s && ip4.dst == %s",
5056+
op->json_key, nat->logical_ip, nat2->external_ip);
5057+
ds_put_format(&actions, "outport = %s; "
5058+
"eth.src = %s; eth.dst = %s; "
5059+
"reg0 = ip4.dst; reg1 = %s; "
5060+
REGBIT_DISTRIBUTED_NAT" = 1; "
5061+
REGBIT_NAT_REDIRECT" = 0; next;",
5062+
op->od->l3dgw_port->json_key,
5063+
op->od->l3dgw_port->lrp_networks.ea_s,
5064+
nat2->external_mac, nat->external_ip);
5065+
ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_ROUTING, 400,
5066+
ds_cstr(&match), ds_cstr(&actions));
5067+
ds_clear(&match);
5068+
ds_clear(&actions);
5069+
}
5070+
}
5071+
}
5072+
50125073
static void
50135074
add_route(struct hmap *lflows, const struct ovn_port *op,
50145075
const char *lrp_addr_s, const char *network_s, int plen,
@@ -6392,6 +6453,41 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
63926453
* ingress pipeline with inport = outport. */
63936454
if (od->l3dgw_port) {
63946455
/* Distributed router. */
6456+
if (!strcmp(nat->type, "dnat_and_snat") &&
6457+
nat->external_mac && nat->external_ip) {
6458+
for (int j = 0; j < od->nbr->n_nat; j++) {
6459+
const struct nbrec_nat *nat2 = od->nbr->nat[j];
6460+
6461+
if (nat2 == nat ||
6462+
strcmp(nat2->type, "dnat_and_snat") ||
6463+
!nat2->external_mac || !nat2->external_ip) {
6464+
continue;
6465+
}
6466+
6467+
ds_clear(&match);
6468+
ds_put_format(&match, "is_chassis_resident(\"%s\") && "
6469+
"ip4.src == %s && ip4.dst == %s",
6470+
nat->logical_port, nat2->external_ip,
6471+
nat->external_ip);
6472+
ds_clear(&actions);
6473+
ds_put_format(&actions,
6474+
"inport = outport; outport = \"\"; "
6475+
"flags = 0; flags.loopback = 1; "
6476+
REGBIT_EGRESS_LOOPBACK" = 1; "
6477+
"next(pipeline=ingress, table=0); ");
6478+
ovn_lflow_add(lflows, od, S_ROUTER_OUT_EGR_LOOP, 300,
6479+
ds_cstr(&match), ds_cstr(&actions));
6480+
6481+
ds_clear(&match);
6482+
ds_put_format(&match,
6483+
"ip4.src == %s && ip4.dst == %s",
6484+
nat2->external_ip, nat->external_ip);
6485+
ovn_lflow_add(lflows, od, S_ROUTER_OUT_EGR_LOOP, 200,
6486+
ds_cstr(&match), "next;");
6487+
ds_clear(&match);
6488+
}
6489+
}
6490+
63956491
ds_clear(&match);
63966492
ds_put_format(&match, "ip4.dst == %s && outport == %s",
63976493
nat->external_ip,
@@ -6463,6 +6559,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
64636559
ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 50,
64646560
"ip", "flags.loopback = 1; ct_dnat;");
64656561
} else {
6562+
ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 400,
6563+
REGBIT_DISTRIBUTED_NAT" == 1", "next;");
6564+
64666565
/* For NAT on a distributed router, add flows to Ingress
64676566
* IP Routing table, Ingress ARP Resolution table, and
64686567
* Ingress Gateway Redirect Table that are not specific to a
@@ -6698,6 +6797,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
66986797
continue;
66996798
}
67006799

6800+
/* create logical flows for DVR floating IPs */
6801+
add_distributed_nat_routes(lflows, op);
6802+
67016803
for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
67026804
add_route(lflows, op, op->lrp_networks.ipv4_addrs[i].addr_s,
67036805
op->lrp_networks.ipv4_addrs[i].network_s,
@@ -6938,6 +7040,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
69387040
continue;
69397041
}
69407042
if (od->l3dgw_port && od->l3redirect_port) {
7043+
ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 300,
7044+
REGBIT_DISTRIBUTED_NAT" == 1", "next;");
7045+
69417046
/* For traffic with outport == l3dgw_port, if the
69427047
* packet did not match any higher priority redirect
69437048
* rule, then the traffic is redirected to the central

0 commit comments

Comments
 (0)