Reported-at: https://issues.redhat.com/browse/FDP-871
On 2/11/25 2:49 PM, Rosemarie O'Riorden wrote: > When a gateway router has a load balancer configured, the option > lb_force_snat_ip=routerip can be set so that OVN snats load balanced > packets to the source logical router port's IP address, that is, the > port chosen as "outport" in the lr_in_ip_routing stage. > > However, this was only designed to work when one network was configured > on the source logical router outport. When multiple networks are configured, > OVN's behavior was to simply choose the lexicographically first IP address for > snat. This lead to an incorrect address often being used for snat. > > To fix this, two main components have been added: > 1. A new flag, flags.network_id. It is 4 bits and stores an index. > 2. A new stage in the router ingress pipeline, lr_in_network_id. > > Now in the stage lr_in_network_id, OVN generates flows that assign > flags.network_id with an index. This index is then matched on later and the > network at that index will be chosen for snat. > > Two tests have been added to verify that: > 1. The correct network is chosen for snat. > 2. The new and updated flows with flags.network_id are correct. > > And tests that were broken by this new behavior have been updated. > > Signed-off-by: Rosemarie O'Riorden <[email protected]> > --- > include/ovn/logical-fields.h | 5 ++ > lib/logical-fields.c | 3 + > northd/northd.c | 141 +++++++++++++++++++---------- > northd/northd.h | 3 +- > northd/ovn-northd.8.xml | 17 ++-- > tests/ovn-northd.at | 169 +++++++++++++++++++++++++++++++---- > 6 files changed, 267 insertions(+), 71 deletions(-) > > diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h > index fbe73763e..73feb4b1b 100644 > --- a/include/ovn/logical-fields.h > +++ b/include/ovn/logical-fields.h > @@ -95,6 +95,8 @@ enum mff_log_flags_bits { > MLF_ICMP_SNAT_BIT = 17, > MLF_OVERRIDE_LOCAL_ONLY_BIT = 18, > MLF_FROM_CTRL_BIT = 19, > + MLF_NETWORK_ID_START_BIT = 28, > + MLF_NETWORK_ID_END_BIT = 31, > }; > > /* MFF_LOG_FLAGS_REG flag assignments */ > @@ -152,6 +154,9 @@ enum mff_log_flags { > MLF_ICMP_SNAT = (1 << MLF_ICMP_SNAT_BIT), > > MLF_OVERRIDE_LOCAL_ONLY = (1 << MLF_OVERRIDE_LOCAL_ONLY_BIT), > + > + MLF_NETWORK_ID = ((MLF_NETWORK_ID_END_BIT - MLF_NETWORK_ID_START_BIT + 1) > + << MLF_NETWORK_ID_START_BIT) - 1, > }; > > /* OVN logical fields > diff --git a/lib/logical-fields.c b/lib/logical-fields.c > index df1b4243c..84a5dec99 100644 > --- a/lib/logical-fields.c > +++ b/lib/logical-fields.c > @@ -139,6 +139,9 @@ ovn_init_symtab(struct shash *symtab) > flags_str); > snprintf(flags_str, sizeof flags_str, "flags[%d]", > MLF_RX_FROM_TUNNEL_BIT); > expr_symtab_add_subfield(symtab, "flags.tunnel_rx", NULL, flags_str); > + snprintf(flags_str, sizeof flags_str, "flags[%d..%d]", > + MLF_NETWORK_ID_START_BIT, MLF_NETWORK_ID_END_BIT); > + expr_symtab_add_subfield(symtab, "flags.network_id", NULL, flags_str); > > snprintf(flags_str, sizeof flags_str, "flags[%d]", MLF_FROM_CTRL_BIT); > expr_symtab_add_subfield(symtab, "flags.from_ctrl", NULL, flags_str); > diff --git a/northd/northd.c b/northd/northd.c > index 1097bb159..ea784766b 100644 > --- a/northd/northd.c > +++ b/northd/northd.c > @@ -13091,12 +13091,12 @@ build_lrouter_force_snat_flows_op(struct ovn_port > *op, > return; > } > > - if (op->lrp_networks.n_ipv4_addrs) { > + for (size_t i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { > ds_clear(match); > ds_clear(actions); > > ds_put_format(match, "inport == %s && ip4.dst == %s", > - op->json_key, op->lrp_networks.ipv4_addrs[0].addr_s); > + op->json_key, op->lrp_networks.ipv4_addrs[i].addr_s); > ovn_lflow_add(lflows, op->od, S_ROUTER_IN_UNSNAT, 110, > ds_cstr(match), "ct_snat;", lflow_ref); > > @@ -13105,53 +13105,46 @@ build_lrouter_force_snat_flows_op(struct ovn_port > *op, > /* Higher priority rules to force SNAT with the router port ip. > * This only takes effect when the packet has already been > * load balanced once. */ > - ds_put_format(match, "flags.force_snat_for_lb == 1 && ip4 && " > - "outport == %s", op->json_key); > + ds_put_format(match, "flags.force_snat_for_lb == 1 && " > + "flags.network_id == %"PRIuSIZE" && ip4 && " > + "outport == %s", i, op->json_key); > ds_put_format(actions, "ct_snat(%s);", > - op->lrp_networks.ipv4_addrs[0].addr_s); > + op->lrp_networks.ipv4_addrs[i].addr_s); > ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_SNAT, 110, > ds_cstr(match), ds_cstr(actions), > lflow_ref); > - if (op->lrp_networks.n_ipv4_addrs > 1) { > - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > - VLOG_WARN_RL(&rl, "Logical router port %s is configured with " > - "multiple IPv4 addresses. Only the first " > - "IP [%s] is considered as SNAT for load " > - "balancer", op->json_key, > - op->lrp_networks.ipv4_addrs[0].addr_s); > - } > } > > /* op->lrp_networks.ipv6_addrs will always have LLA and that will be > - * last in the list. So add the flows only if n_ipv6_addrs > 1. */ > + * last in the list. So add the flows only if n_ipv6_addrs > 1, and loop > + * n_ipv6_addrs - 1 times. */ > if (op->lrp_networks.n_ipv6_addrs > 1) { > - ds_clear(match); > - ds_clear(actions); > - > - ds_put_format(match, "inport == %s && ip6.dst == %s", > - op->json_key, op->lrp_networks.ipv6_addrs[0].addr_s); > - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_UNSNAT, 110, > - ds_cstr(match), "ct_snat;", lflow_ref); > + for (size_t i = 0; i < op->lrp_networks.n_ipv6_addrs - 1; i++) { > + ds_clear(match); > + ds_clear(actions); > > - ds_clear(match); > + ds_put_format(match, "inport == %s && ip6.dst == %s", > + op->json_key, > op->lrp_networks.ipv6_addrs[i].addr_s); > + ovn_lflow_add(lflows, op->od, S_ROUTER_IN_UNSNAT, 110, > + ds_cstr(match), "ct_snat;", lflow_ref); > + ds_clear(match); > > - /* Higher priority rules to force SNAT with the router port ip. > - * This only takes effect when the packet has already been > - * load balanced once. */ > - ds_put_format(match, "flags.force_snat_for_lb == 1 && ip6 && " > - "outport == %s", op->json_key); > - ds_put_format(actions, "ct_snat(%s);", > - op->lrp_networks.ipv6_addrs[0].addr_s); > - ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_SNAT, 110, > - ds_cstr(match), ds_cstr(actions), > - lflow_ref); > - if (op->lrp_networks.n_ipv6_addrs > 2) { > - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > - VLOG_WARN_RL(&rl, "Logical router port %s is configured with " > - "multiple IPv6 addresses. Only the first " > - "IP [%s] is considered as SNAT for load " > - "balancer", op->json_key, > - op->lrp_networks.ipv6_addrs[0].addr_s); > + /* Higher priority rules to force SNAT with the router port ip. > + * This only takes effect when the packet has already been > + * load balanced once. */ > + if (op->lrp_networks.n_ipv6_addrs == 1) { > + ds_put_format(match, "flags.force_snat_for_lb == 1 && ip6 && > " > + "outport == %s", op->json_key); > + } else if (op->lrp_networks.n_ipv6_addrs > 1) { > + ds_put_format(match, "flags.force_snat_for_lb == 1 && " > + "flags.network_id == %"PRIuSIZE" && ip6 && " > + "outport == %s", i, op->json_key); > + } > + ds_put_format(actions, "ct_snat(%s);", > + op->lrp_networks.ipv6_addrs[i].addr_s); > + ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_SNAT, 110, > + ds_cstr(match), ds_cstr(actions), > + lflow_ref); > } > } > } > @@ -15038,6 +15031,56 @@ build_arp_request_flows_for_lrouter( > lflow_ref); > } > > +static void > +build_lr_force_snat_network_id_flows( > + struct ovn_datapath *od, struct lflow_table *lflows, > + struct ds *match, struct ds *actions, struct lflow_ref > *lflow_ref) > +{ > + const struct ovn_port *op; > + HMAP_FOR_EACH (op, dp_node, &od->ports) { > + for (size_t i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { > + ds_clear(match); > + ds_clear(actions); > + > + ds_put_format(match, "flags.force_snat_for_lb == 1 && " > + "outport == %s && " REG_NEXT_HOP_IPV4 " == %s/%d", > + op->json_key, > op->lrp_networks.ipv4_addrs[i].addr_s, > + op->lrp_networks.ipv4_addrs[i].plen); > + > + ds_put_format(actions, "flags.network_id = %"PRIuSIZE"; ", i); > + ds_put_format(actions, "next;"); > + > + ovn_lflow_add(lflows, op->od, S_ROUTER_IN_NETWORK_ID, 110, > + ds_cstr(match), ds_cstr(actions), > + lflow_ref); > + } > + > + /* op->lrp_networks.ipv6_addrs will always have LLA and that will be > + * last in the list. So add the flows only if n_ipv6_addrs > 1, and > + * loop n_ipv6_addrs - 1 times. */ > + if (op->lrp_networks.n_ipv6_addrs > 1) { > + for (size_t i = 0; i < op->lrp_networks.n_ipv6_addrs - 1; i++) { > + ds_clear(match); > + ds_clear(actions); > + > + ds_put_format(match, "flags.force_snat_for_lb == 1 && " > + "outport == %s && " REG_NEXT_HOP_IPV6 " == > %s/%d", > + op->json_key, > op->lrp_networks.ipv6_addrs[i].addr_s, > + op->lrp_networks.ipv6_addrs[i].plen); > + > + ds_put_format(actions, "flags.network_id = %"PRIuSIZE"; ", > i); > + ds_put_format(actions, "next;"); > + > + ovn_lflow_add(lflows, op->od, S_ROUTER_IN_NETWORK_ID, 110, > + ds_cstr(match), ds_cstr(actions), > + lflow_ref); > + } > + } > + } > + ovn_lflow_add(lflows, od, S_ROUTER_IN_NETWORK_ID, 0, > + "1", "next;", lflow_ref); > +} > + > /* Logical router egress table DELIVERY: Delivery (priority 100-110). > * > * Priority 100 rules deliver packets to enabled logical ports. > @@ -17035,26 +17078,28 @@ build_lrouter_nat_defrag_and_lb( > /* Handle force SNAT options set in the gateway router. */ > if (od->is_gw_router) { > if (dnat_force_snat_ip) { > - if (lrnat_rec->dnat_force_snat_addrs.n_ipv4_addrs) { > + struct lport_addresses dn_addrs = > lrnat_rec->dnat_force_snat_addrs; > + for (size_t i = 0; i < dn_addrs.n_ipv4_addrs; i++) { > build_lrouter_force_snat_flows(lflows, od, "4", > - lrnat_rec->dnat_force_snat_addrs.ipv4_addrs[0].addr_s, > + lrnat_rec->dnat_force_snat_addrs.ipv4_addrs[i].addr_s, > "dnat", lflow_ref); > } > - if (lrnat_rec->dnat_force_snat_addrs.n_ipv6_addrs) { > + for (size_t i = 0; i < dn_addrs.n_ipv6_addrs; i++) { > build_lrouter_force_snat_flows(lflows, od, "6", > - lrnat_rec->dnat_force_snat_addrs.ipv6_addrs[0].addr_s, > + lrnat_rec->dnat_force_snat_addrs.ipv6_addrs[i].addr_s, > "dnat", lflow_ref); > } > } > if (lb_force_snat_ip) { > - if (lrnat_rec->lb_force_snat_addrs.n_ipv4_addrs) { > + struct lport_addresses lb_addrs = lrnat_rec->lb_force_snat_addrs; > + for (size_t i = 0; i < lb_addrs.n_ipv4_addrs; i++) { > build_lrouter_force_snat_flows(lflows, od, "4", > - lrnat_rec->lb_force_snat_addrs.ipv4_addrs[0].addr_s, > "lb", > + lrnat_rec->lb_force_snat_addrs.ipv4_addrs[i].addr_s, > "lb", > lflow_ref); > } > - if (lrnat_rec->lb_force_snat_addrs.n_ipv6_addrs) { > + for (size_t i = 0; i < lb_addrs.n_ipv6_addrs; i++) { > build_lrouter_force_snat_flows(lflows, od, "6", > - lrnat_rec->lb_force_snat_addrs.ipv6_addrs[0].addr_s, > "lb", > + lrnat_rec->lb_force_snat_addrs.ipv6_addrs[i].addr_s, > "lb", > lflow_ref); > } > } > @@ -17415,6 +17460,8 @@ build_lswitch_and_lrouter_iterate_by_lr(struct > ovn_datapath *od, > &lsi->actions, > lsi->meter_groups, > NULL); > + build_lr_force_snat_network_id_flows(od, lsi->lflows, &lsi->match, > + &lsi->actions, NULL); > build_misc_local_traffic_drop_flows_for_lrouter(od, lsi->lflows, NULL); > > build_lr_nat_defrag_and_lb_default_flows(od, lsi->lflows, NULL); > diff --git a/northd/northd.h b/northd/northd.h > index 1f29645c7..e89ab3c74 100644 > --- a/northd/northd.h > +++ b/northd/northd.h > @@ -537,7 +537,8 @@ enum ovn_stage { > PIPELINE_STAGE(ROUTER, IN, CHK_PKT_LEN, 21, "lr_in_chk_pkt_len") > \ > PIPELINE_STAGE(ROUTER, IN, LARGER_PKTS, 22, "lr_in_larger_pkts") > \ > PIPELINE_STAGE(ROUTER, IN, GW_REDIRECT, 23, "lr_in_gw_redirect") > \ > - PIPELINE_STAGE(ROUTER, IN, ARP_REQUEST, 24, "lr_in_arp_request") > \ > + PIPELINE_STAGE(ROUTER, IN, NETWORK_ID, 24, "lr_in_network_id") > \ > + PIPELINE_STAGE(ROUTER, IN, ARP_REQUEST, 25, "lr_in_arp_request") > \ > \ > /* Logical router egress stages. */ \ > PIPELINE_STAGE(ROUTER, OUT, CHECK_DNAT_LOCAL, 0, > \ > diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml > index 93b1a9135..e15b91f1f 100644 > --- a/northd/ovn-northd.8.xml > +++ b/northd/ovn-northd.8.xml > @@ -5256,18 +5256,19 @@ nd_ns { > table="Logical_Router"/>:lb_force_snat_ip=router_ip), then for > each logical router port <var>P</var> attached to the Gateway > router, a priority-110 flow matches > - <code>flags.force_snat_for_lb == 1 && outport == > <var>P</var> > - </code> with an action <code>ct_snat(<var>R</var>);</code> > - where <var>R</var> is the IP configured on the router port. > - If <code>R</code> is an IPv4 address then the match will also > - include <code>ip4</code> and if it is an IPv6 address, then the > - match will also include <code>ip6</code>. > + <code>flags.force_snat_for_lb == 1 && flags.network_id == > + <var>I</var> && outport == <var>P</var></code>, where > + <var>I</var> is the network index, with an action > + <code>ct_snat(<var>R</var>);</code> where <var>R</var> is the IP > + configured on the router port. If <code>R</code> is an IPv4 address > + then the match will also include <code>ip4</code> and if it is an > + IPv6 address, then the match will also include <code>ip6</code>. > </p> > > <p> > If the logical router port <var>P</var> is configured with multiple > - IPv4 and multiple IPv6 addresses, only the first IPv4 and first > IPv6 > - address is considered. > + IPv4 and multiple IPv6 addresses, the IPv4 and IPv6 address within > + the same network as the next-hop will be chosen. > </p> > </li> > > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at > index 64991ff75..777f3b95b 100644 > --- a/tests/ovn-northd.at > +++ b/tests/ovn-northd.at > @@ -4460,9 +4460,9 @@ AT_CHECK([grep "lr_in_dnat" lr0flows | > ovn_strip_lflows], [0], [dnl > > 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=110 , > match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"), > action=(ct_snat(172.168.0.100);) > - table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"), > action=(ct_snat(10.0.0.1);) > - table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw1"), > action=(ct_snat(20.0.0.1);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 0 && ip4 && > outport == "lr0-public"), action=(ct_snat(172.168.0.100);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 0 && ip4 && > outport == "lr0-sw0"), action=(ct_snat(10.0.0.1);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 0 && ip4 && > outport == "lr0-sw1"), action=(ct_snat(20.0.0.1);) > table=??(lr_out_snat ), priority=120 , match=(nd_ns), > action=(next;) > ]) > > @@ -4525,10 +4525,10 @@ AT_CHECK([grep "lr_in_dnat" lr0flows | > ovn_strip_lflows], [0], [dnl > > 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=110 , > match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"), > action=(ct_snat(172.168.0.100);) > - table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"), > action=(ct_snat(10.0.0.1);) > - table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw1"), > action=(ct_snat(20.0.0.1);) > - table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && ip6 && outport == "lr0-sw1"), > action=(ct_snat(bef0::1);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 0 && ip4 && > outport == "lr0-public"), action=(ct_snat(172.168.0.100);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 0 && ip4 && > outport == "lr0-sw0"), action=(ct_snat(10.0.0.1);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 0 && ip4 && > outport == "lr0-sw1"), action=(ct_snat(20.0.0.1);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 0 && ip6 && > outport == "lr0-sw1"), action=(ct_snat(bef0::1);) > table=??(lr_out_snat ), priority=120 , match=(nd_ns), > action=(next;) > ]) > > @@ -6235,8 +6235,8 @@ AT_CHECK([grep "lr_out_post_undnat" lr0flows | > ovn_strip_lflows], [0], [dnl > > 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=110 , > match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"), > action=(ct_snat(172.168.0.10);) > - table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"), > action=(ct_snat(10.0.0.1);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 0 && ip4 && > outport == "lr0-public"), action=(ct_snat(172.168.0.10);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 0 && ip4 && > outport == "lr0-sw0"), action=(ct_snat(10.0.0.1);) > table=??(lr_out_snat ), priority=120 , match=(nd_ns), > action=(next;) > table=??(lr_out_snat ), priority=25 , match=(ip && ip4.src == > 10.0.0.0/24 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.10);) > table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == > 10.0.0.10 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.30);) > @@ -6301,8 +6301,8 @@ AT_CHECK([grep "lr_out_post_undnat" lr0flows | > ovn_strip_lflows], [0], [dnl > > 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=110 , > match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"), > action=(ct_snat(172.168.0.10);) > - table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"), > action=(ct_snat(10.0.0.1);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 0 && ip4 && > outport == "lr0-public"), action=(ct_snat(172.168.0.10);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 0 && ip4 && > outport == "lr0-sw0"), action=(ct_snat(10.0.0.1);) > table=??(lr_out_snat ), priority=120 , match=(nd_ns), > action=(next;) > table=??(lr_out_snat ), priority=25 , match=(ip && ip4.src == > 10.0.0.0/24 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.10);) > table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == > 10.0.0.10 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.30);) > @@ -6379,10 +6379,10 @@ AT_CHECK([grep "lr_out_post_undnat" lr0flows | > ovn_strip_lflows], [0], [dnl > > 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=110 , > match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"), > action=(ct_snat(172.168.0.10);) > - table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"), > action=(ct_snat(10.0.0.1);) > - table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && ip6 && outport == "lr0-public"), > action=(ct_snat(def0::10);) > - table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && ip6 && outport == "lr0-sw0"), > action=(ct_snat(aef0::1);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 0 && ip4 && > outport == "lr0-public"), action=(ct_snat(172.168.0.10);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 0 && ip4 && > outport == "lr0-sw0"), action=(ct_snat(10.0.0.1);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 0 && ip6 && > outport == "lr0-public"), action=(ct_snat(def0::10);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 0 && ip6 && > outport == "lr0-sw0"), action=(ct_snat(aef0::1);) > table=??(lr_out_snat ), priority=120 , match=(nd_ns), > action=(next;) > table=??(lr_out_snat ), priority=25 , match=(ip && ip4.src == > 10.0.0.0/24 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.10);) > table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == > 10.0.0.10 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.30);) > @@ -15542,3 +15542,142 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > > AT_CLEANUP > ]) > + > +AT_SETUP([lb_force_snat_ip=routerip select correct network for snat]) > +AT_SKIP_IF([test $HAVE_SCAPY = no]) > +ovn_start > + > +check ovn-nbctl lr-add lr > +check ovn-nbctl set logical_router lr options:chassis=hv1 > +check ovn-nbctl set logical_router lr options:lb_force_snat_ip=router_ip > +check ovn-nbctl lrp-add lr lrp-client 02:00:00:00:00:02 1.1.1.1/24 > +check ovn-nbctl lrp-add lr lrp-server 02:00:00:00:00:03 1.1.2.1/24 > 1.2.1.1/24 \ > + 1.1.3.1/24 2.2.2.1/24 7.7.7.1/24 8.8.8.1/24 > +check ovn-nbctl ls-add ls-client > +check ovn-nbctl ls-add ls-server > +check ovn-nbctl lsp-add ls-client lsp-client-router > +check ovn-nbctl lsp-set-type lsp-client-router router > +check ovn-nbctl lsp-add ls-server lsp-server-router > +check ovn-nbctl lsp-set-type lsp-server-router router > +check ovn-nbctl set logical_switch_port lsp-client-router > options:router-port=lrp-client > +check ovn-nbctl set logical_switch_port lsp-server-router > options:router-port=lrp-server > +check ovn-nbctl lsp-add ls-client client > +check ovn-nbctl lsp-add ls-server server > +check ovn-nbctl lsp-set-addresses client "02:00:00:00:00:01 1.1.1.10" > +check ovn-nbctl lsp-set-addresses server "02:00:00:00:00:04 2.2.2.10" > +check ovn-nbctl lsp-set-addresses lsp-client-router router > +check ovn-nbctl lsp-set-addresses lsp-server-router router > +check ovn-nbctl lb-add lb 42.42.42.42:80 2.2.2.10:80 udp > +check ovn-nbctl lr-lb-add lr lb > + > +# Create a hypervisor and create OVS ports corresponding to logical ports. > +net_add n1 > +sim_add hv1 > +as hv1 > +ovs-vsctl add-br br-phys > +ovn_attach n1 br-phys 192.168.0.1 > + > +ovs-vsctl -- add-port br-int hv1-vif1 -- \ > + set interface hv1-vif1 external-ids:iface-id=client \ > + options:tx_pcap=hv1/client-tx.pcap \ > + options:rxq_pcap=hv1/client-rx.pcap > + > +ovs-vsctl -- add-port br-int hv1-vif2 -- \ > + set interface hv1-vif2 external-ids:iface-id=server \ > + options:tx_pcap=hv1/server-tx.pcap \ > + options:rxq_pcap=hv1/server-rx.pcap > + > +wait_for_ports_up > +check ovn-nbctl --wait=hv sync > + > +tx_src_mac="02:00:00:00:00:01" > +tx_dst_mac="02:00:00:00:00:02" > +tx_src_ip=1.1.1.10 > +tx_dst_ip=42.42.42.42 > +request=$(fmt_pkt "Ether(dst='${tx_dst_mac}', src='${tx_src_mac}')/ \ > + IP(src='${tx_src_ip}', dst='${tx_dst_ip}')/ \ > + UDP(sport=20001, dport=80)") > + > +as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $request > + > +rx_src_mac="02:00:00:00:00:03" > +rx_dst_mac="02:00:00:00:00:04" > +rx_src_ip=2.2.2.1 > +rx_dst_ip=2.2.2.10 > +expected=$(fmt_pkt "Ether(dst='${rx_dst_mac}', src='${rx_src_mac}')/ \ > + IP(src='${rx_src_ip}', dst='${rx_dst_ip}', ttl=0x3F)/ \ > + UDP(sport=20001, dport=80)") > + > +echo $expected > expected > +OVN_CHECK_PACKETS([hv1/server-tx.pcap], [expected]) > +AT_CLEANUP > + > +AT_SETUP([lb_force_snat_ip=routerip generate flags.network_id flows]) > +ovn_start > + > +check ovn-nbctl lr-add lr > +check ovn-nbctl set logical_router lr options:chassis=hv1 > +check ovn-nbctl set logical_router lr options:lb_force_snat_ip=router_ip > +check ovn-nbctl lrp-add lr lrp-client 02:00:00:00:00:02 1.1.1.1/24 ff01::01 > +check ovn-nbctl lrp-add lr lrp-server 02:00:00:00:00:03 1.1.2.1/24 > 7.7.7.1/24 8.8.8.1/24 \ > + ff01::02 ff01::03 ff01::06 > +check ovn-nbctl ls-add ls-client > +check ovn-nbctl ls-add ls-server > +check ovn-nbctl lsp-add ls-client lsp-client-router > +check ovn-nbctl lsp-set-type lsp-client-router router > +check ovn-nbctl lsp-add ls-server lsp-server-router > +check ovn-nbctl lsp-set-type lsp-server-router router > +check ovn-nbctl set logical_switch_port lsp-client-router > options:router-port=lrp-client > +check ovn-nbctl set logical_switch_port lsp-server-router > options:router-port=lrp-server > +check ovn-nbctl lsp-add ls-client client > +check ovn-nbctl lsp-add ls-server server > +check ovn-nbctl lsp-set-addresses client "02:00:00:00:00:01 1.1.1.10" > +check ovn-nbctl lsp-set-addresses server "02:00:00:00:00:04 2.2.2.10" > +check ovn-nbctl lsp-set-addresses lsp-client-router router > +check ovn-nbctl lsp-set-addresses lsp-server-router router > +check ovn-nbctl lb-add lb 42.42.42.42:80 2.2.2.10:80 udp > +check ovn-nbctl lr-lb-add lr lb > + > +# Create a hypervisor and create OVS ports corresponding to logical ports. > +net_add n1 > +sim_add hv1 > +as hv1 > +ovs-vsctl add-br br-phys > +ovn_attach n1 br-phys 192.168.0.1 > + > +ovs-vsctl add-port br-int hv1-vif1 -- \ > + set interface hv1-vif1 external-ids:iface-id=client \ > + options:tx_pcap=hv1/client-tx.pcap \ > + options:rxq_pcap=hv1/client-rx.pcap > + > +ovs-vsctl add-port br-int hv1-vif2 -- \ > + set interface hv1-vif2 external-ids:iface-id=server \ > + options:tx_pcap=hv1/server-tx.pcap \ > + options:rxq_pcap=hv1/server-rx.pcap > + > +#OVN_POPULATE_ARP > +wait_for_ports_up > +check ovn-nbctl --wait=hv sync > + > +ovn-sbctl dump-flows lr > lrflows > +AT_CAPTURE_FILE([lrflows]) > + > +AT_CHECK([grep -E flags.network_id lrflows | ovn_strip_lflows], [0], [dnl > + table=??(lr_in_network_id ), priority=110 , > match=(flags.force_snat_for_lb == 1 && outport == "lrp-client" && reg0 == > 1.1.1.1/24), action=(flags.network_id = 0; next;) > + table=??(lr_in_network_id ), priority=110 , > match=(flags.force_snat_for_lb == 1 && outport == "lrp-client" && xxreg0 == > ff01::1/128), action=(flags.network_id = 0; next;) > + table=??(lr_in_network_id ), priority=110 , > match=(flags.force_snat_for_lb == 1 && outport == "lrp-server" && reg0 == > 1.1.2.1/24), action=(flags.network_id = 0; next;) > + table=??(lr_in_network_id ), priority=110 , > match=(flags.force_snat_for_lb == 1 && outport == "lrp-server" && reg0 == > 7.7.7.1/24), action=(flags.network_id = 1; next;) > + table=??(lr_in_network_id ), priority=110 , > match=(flags.force_snat_for_lb == 1 && outport == "lrp-server" && reg0 == > 8.8.8.1/24), action=(flags.network_id = 2; next;) > + table=??(lr_in_network_id ), priority=110 , > match=(flags.force_snat_for_lb == 1 && outport == "lrp-server" && xxreg0 == > ff01::2/128), action=(flags.network_id = 0; next;) > + table=??(lr_in_network_id ), priority=110 , > match=(flags.force_snat_for_lb == 1 && outport == "lrp-server" && xxreg0 == > ff01::3/128), action=(flags.network_id = 1; next;) > + table=??(lr_in_network_id ), priority=110 , > match=(flags.force_snat_for_lb == 1 && outport == "lrp-server" && xxreg0 == > ff01::6/128), action=(flags.network_id = 2; next;) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 0 && ip4 && > outport == "lrp-client"), action=(ct_snat(1.1.1.1);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 0 && ip4 && > outport == "lrp-server"), action=(ct_snat(1.1.2.1);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 0 && ip6 && > outport == "lrp-client"), action=(ct_snat(ff01::1);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 0 && ip6 && > outport == "lrp-server"), action=(ct_snat(ff01::2);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 1 && ip4 && > outport == "lrp-server"), action=(ct_snat(7.7.7.1);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 1 && ip6 && > outport == "lrp-server"), action=(ct_snat(ff01::3);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 2 && ip4 && > outport == "lrp-server"), action=(ct_snat(8.8.8.1);) > + table=??(lr_out_snat ), priority=110 , > match=(flags.force_snat_for_lb == 1 && flags.network_id == 2 && ip6 && > outport == "lrp-server"), action=(ct_snat(ff01::6);) > +]) > +AT_CLEANUP -- Rosemarie O'Riorden [email protected] _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
