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 &amp;&amp; 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 &amp;&amp; flags.network_id ==
> +          <var>I</var> &amp;&amp; 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

Reply via email to