@@ -181,6 +181,7 @@ enum ovn_stage {
181
181
* logical router dropping packets with source IP address equals
182
182
* one of the logical router's own IP addresses. */
183
183
#define REGBIT_EGRESS_LOOPBACK "reg9[1]"
184
+ #define REGBIT_DISTRIBUTED_NAT "reg9[2]"
184
185
185
186
/* Returns an "enum ovn_stage" built from the arguments. */
186
187
static enum ovn_stage
@@ -5009,6 +5010,66 @@ find_lrp_member_ip(const struct ovn_port *op, const char *ip_s)
5009
5010
return NULL ;
5010
5011
}
5011
5012
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
+
5012
5073
static void
5013
5074
add_route (struct hmap * lflows , const struct ovn_port * op ,
5014
5075
const char * lrp_addr_s , const char * network_s , int plen ,
@@ -6392,6 +6453,41 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
6392
6453
* ingress pipeline with inport = outport. */
6393
6454
if (od -> l3dgw_port ) {
6394
6455
/* 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
+
6395
6491
ds_clear (& match );
6396
6492
ds_put_format (& match , "ip4.dst == %s && outport == %s" ,
6397
6493
nat -> external_ip ,
@@ -6463,6 +6559,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
6463
6559
ovn_lflow_add (lflows , od , S_ROUTER_IN_DNAT , 50 ,
6464
6560
"ip" , "flags.loopback = 1; ct_dnat;" );
6465
6561
} else {
6562
+ ovn_lflow_add (lflows , od , S_ROUTER_IN_ARP_RESOLVE , 400 ,
6563
+ REGBIT_DISTRIBUTED_NAT " == 1" , "next;" );
6564
+
6466
6565
/* For NAT on a distributed router, add flows to Ingress
6467
6566
* IP Routing table, Ingress ARP Resolution table, and
6468
6567
* Ingress Gateway Redirect Table that are not specific to a
@@ -6698,6 +6797,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
6698
6797
continue ;
6699
6798
}
6700
6799
6800
+ /* create logical flows for DVR floating IPs */
6801
+ add_distributed_nat_routes (lflows , op );
6802
+
6701
6803
for (int i = 0 ; i < op -> lrp_networks .n_ipv4_addrs ; i ++ ) {
6702
6804
add_route (lflows , op , op -> lrp_networks .ipv4_addrs [i ].addr_s ,
6703
6805
op -> lrp_networks .ipv4_addrs [i ].network_s ,
@@ -6938,6 +7040,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
6938
7040
continue ;
6939
7041
}
6940
7042
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
+
6941
7046
/* For traffic with outport == l3dgw_port, if the
6942
7047
* packet did not match any higher priority redirect
6943
7048
* rule, then the traffic is redirected to the central
0 commit comments