diff mbox series

[ovs-dev] ovn-trace: implement chk_lb_hairpin_reply and ct_snat_to_vip actions

Message ID 91ab11c91b827e09c4f5f43e1ad20a05d3f918a4.1656595260.git.lorenzo.bianconi@redhat.com
State Accepted
Headers show
Series [ovs-dev] ovn-trace: implement chk_lb_hairpin_reply and ct_snat_to_vip actions | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_ovn-kubernetes success github build: passed
ovsrobot/github-robot-_Build_and_Test fail github build: failed

Commit Message

Lorenzo Bianconi June 30, 2022, 1:22 p.m. UTC
Add chk_lb_hairpin_reply and ct_snat_to_vip implementations for ovn-trace
utility in order to simulate hairpin traffic

Rreported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2099311
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
---
 tests/ovn-northd.at   |   8 ---
 utilities/ovn-trace.c | 126 ++++++++++++++++++++++++++++++++----------
 2 files changed, 97 insertions(+), 37 deletions(-)

Comments

Mark Michelson July 1, 2022, 6:40 p.m. UTC | #1
Thanks for this Lorenzo,

Acked-by: Mark Michelson <mmichels@redhat.com>

On 6/30/22 09:22, Lorenzo Bianconi wrote:
> Add chk_lb_hairpin_reply and ct_snat_to_vip implementations for ovn-trace
> utility in order to simulate hairpin traffic
> 
> Rreported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2099311
> Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
> ---
>   tests/ovn-northd.at   |   8 ---
>   utilities/ovn-trace.c | 126 ++++++++++++++++++++++++++++++++----------
>   2 files changed, 97 insertions(+), 37 deletions(-)
> 
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> index fe97bedad..2f293bfc8 100644
> --- a/tests/ovn-northd.at
> +++ b/tests/ovn-northd.at
> @@ -2936,7 +2936,6 @@ AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
>   ct_lb_mark {
>       ct_lb_mark {
>           reg0[[6]] = 0;
> -        *** chk_lb_hairpin_reply action not implemented;
>           reg0[[12]] = 0;
>           ct_lb_mark /* default (use --ct to customize) */ {
>               output("lsp2");
> @@ -2952,7 +2951,6 @@ AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
>   ct_lb_mark {
>       ct_lb_mark {
>           reg0[[6]] = 0;
> -        *** chk_lb_hairpin_reply action not implemented;
>           reg0[[12]] = 0;
>           ct_lb_mark /* default (use --ct to customize) */ {
>               output("lsp2");
> @@ -2974,7 +2972,6 @@ AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
>   ct_lb_mark {
>       ct_lb_mark {
>           reg0[[6]] = 0;
> -        *** chk_lb_hairpin_reply action not implemented;
>           reg0[[12]] = 0;
>           ct_lb_mark /* default (use --ct to customize) */ {
>               output("lsp2");
> @@ -2990,7 +2987,6 @@ AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
>   ct_lb_mark {
>       ct_lb_mark {
>           reg0[[6]] = 0;
> -        *** chk_lb_hairpin_reply action not implemented;
>           reg0[[12]] = 0;
>           ct_lb_mark /* default (use --ct to customize) */ {
>               output("lsp2");
> @@ -3092,7 +3088,6 @@ AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
>   ct_lb_mark {
>       ct_lb_mark {
>           reg0[[6]] = 0;
> -        *** chk_lb_hairpin_reply action not implemented;
>           reg0[[12]] = 0;
>           ct_lb_mark /* default (use --ct to customize) */ {
>               output("lsp2");
> @@ -3108,7 +3103,6 @@ AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
>   ct_lb_mark {
>       ct_lb_mark {
>           reg0[[6]] = 0;
> -        *** chk_lb_hairpin_reply action not implemented;
>           reg0[[12]] = 0;
>           ct_lb_mark /* default (use --ct to customize) */ {
>               output("lsp2");
> @@ -3130,7 +3124,6 @@ AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
>   ct_lb_mark {
>       ct_lb_mark {
>           reg0[[6]] = 0;
> -        *** chk_lb_hairpin_reply action not implemented;
>           reg0[[12]] = 0;
>           ct_lb_mark /* default (use --ct to customize) */ {
>               output("lsp2");
> @@ -3146,7 +3139,6 @@ AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
>   ct_lb_mark {
>       ct_lb_mark {
>           reg0[[6]] = 0;
> -        *** chk_lb_hairpin_reply action not implemented;
>           reg0[[12]] = 0;
>           ct_lb_mark /* default (use --ct to customize) */ {
>               output("lsp2");
> diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
> index c4110de0a..baf489202 100644
> --- a/utilities/ovn-trace.c
> +++ b/utilities/ovn-trace.c
> @@ -2488,10 +2488,13 @@ execute_ct_lb(const struct ovnact_ct_lb *ct_lb,
>   
>           if (dst) {
>               if (family == AF_INET6) {
> +                ct_lb_flow.ct_ipv6_dst = ct_lb_flow.ipv6_dst;
>                   ct_lb_flow.ipv6_dst = dst->ipv6;
>               } else {
> +                ct_lb_flow.ct_nw_dst = ct_lb_flow.nw_dst;
>                   ct_lb_flow.nw_dst = dst->ipv4;
>               }
> +            ct_lb_flow.ct_tp_dst = ct_lb_flow.tp_dst;
>               if (dst->port) {
>                   ct_lb_flow.tp_dst = htons(dst->port);
>               }
> @@ -2588,15 +2591,65 @@ execute_ovnfield_load(const struct ovnact_load *load,
>       }
>   }
>   
> +static bool
> +get_lb_vip_data(struct flow *uflow, struct in6_addr *vip,
> +                char **vip_str, uint16_t *port)
> +{
> +    int family;
> +
> +    const struct sbrec_load_balancer *sbdb;
> +    SBREC_LOAD_BALANCER_FOR_EACH (sbdb, ovnsb_idl) {
> +        struct smap_node *node;
> +        SMAP_FOR_EACH (node, &sbdb->vips) {
> +            if (!ip_address_and_port_from_lb_key(node->key, vip_str,
> +                                                 port, &family)) {
> +                continue;
> +            }
> +
> +            if (family == AF_INET) {
> +                ovs_be32 vip4;
> +                ip_parse(*vip_str, &vip4);
> +                in6_addr_set_mapped_ipv4(vip, vip4);
> +                if (vip4 == uflow->ct_nw_dst) {
> +                    return true;
> +                }
> +            } else {
> +                ipv6_parse(*vip_str, vip);
> +                if (ipv6_addr_equals(vip, &uflow->ct_ipv6_dst)) {
> +                    return true;
> +                }
> +            }
> +            free(*vip_str);
> +        }
> +    }
> +
> +    return false;
> +}
> +
>   static void
>   execute_chk_lb_hairpin(const struct ovnact_result *dl, struct flow *uflow,
> -                       struct ovs_list *super)
> +                       struct ovs_list *super, bool dir_orig)
>   {
> -    int family = (uflow->dl_type == htons(ETH_TYPE_IP) ? AF_INET
> -                  : uflow->dl_type == htons(ETH_TYPE_IPV6) ? AF_INET6
> -                  : AF_UNSPEC);
> +    struct mf_subfield sf = expr_resolve_field(&dl->dst);
> +    union mf_subvalue sv = { .u8_val = 0 };
> +    struct in6_addr vip;
> +    uint16_t vip_port;
>       uint8_t res = 0;
> -    if (family != AF_UNSPEC && uflow->ct_state & CS_DST_NAT) {
> +    char *vip_str;
> +
> +    if (!get_lb_vip_data(uflow, &vip, &vip_str, &vip_port)) {
> +        goto out;
> +    }
> +    free(vip_str);
> +
> +    int family = (uflow->dl_type == htons(ETH_TYPE_IP) ? AF_INET
> +                 : uflow->dl_type == htons(ETH_TYPE_IPV6) ? AF_INET6
> +                 : AF_UNSPEC);
> +    if (family == AF_UNSPEC) {
> +        goto out;
> +    }
> +
> +    if (uflow->ct_state & CS_DST_NAT) {
>           if (family == AF_INET) {
>               res = (uflow->nw_src == uflow->nw_dst) ? 1 : 0;
>           } else {
> @@ -2604,8 +2657,14 @@ execute_chk_lb_hairpin(const struct ovnact_result *dl, struct flow *uflow,
>           }
>       }
>   
> -    struct mf_subfield sf = expr_resolve_field(&dl->dst);
> -    union mf_subvalue sv = { .u8_val = res };
> +    if (dir_orig) {
> +        res &= (vip_port == ntohs(uflow->ct_tp_dst));
> +    } else {
> +        res &= (vip_port == ntohs(uflow->tp_dst));
> +    }
> +
> +    sv.u8_val = res;
> +out:
>       mf_write_subfield_flow(&sf, &sv, uflow);
>   
>       struct ds s = DS_EMPTY_INITIALIZER;
> @@ -2616,27 +2675,35 @@ execute_chk_lb_hairpin(const struct ovnact_result *dl, struct flow *uflow,
>   }
>   
>   static void
> -execute_chk_lb_hairpin_reply(const struct ovnact_result *dl,
> -                             struct flow *uflow,
> -                             struct ovs_list *super)
> +execute_ct_snat_to_vip(struct flow *uflow, struct ovs_list *super)
>   {
> -    struct mf_subfield sf = expr_resolve_field(&dl->dst);
> -    union mf_subvalue sv = { .u8_val = 0 };
> -    mf_write_subfield_flow(&sf, &sv, uflow);
> -    ovntrace_node_append(super, OVNTRACE_NODE_ERROR,
> -                         "*** chk_lb_hairpin_reply action not implemented");
> -    struct ds s = DS_EMPTY_INITIALIZER;
> -    expr_field_format(&dl->dst, &s);
> -    ovntrace_node_append(super, OVNTRACE_NODE_MODIFY,
> -                         "%s = 0", ds_cstr(&s));
> -    ds_destroy(&s);
> -}
> +    struct in6_addr vip;
> +    uint16_t vip_port;
> +    char *vip_str;
>   
> -static void
> -execute_ct_snat_to_vip(struct flow *uflow OVS_UNUSED, struct ovs_list *super)
> -{
> -    ovntrace_node_append(super, OVNTRACE_NODE_ERROR,
> -                         "*** ct_snat_to_vip action not implemented");
> +    if (!get_lb_vip_data(uflow, &vip, &vip_str, &vip_port)) {
> +        return;
> +    }
> +
> +    if (IN6_IS_ADDR_V4MAPPED(&vip)) {
> +        ovs_be32 vip4 = in6_addr_get_mapped_ipv4(&vip);
> +        if (vip4 != uflow->ct_nw_dst) {
> +            goto out;
> +        }
> +    } else {
> +        if (!ipv6_addr_equals(&vip, &uflow->ct_ipv6_dst)) {
> +            goto out;
> +        }
> +    }
> +
> +    if (vip_port != ntohs(uflow->ct_tp_dst)) {
> +        goto out;
> +    }
> +
> +    ovntrace_node_append(super, OVNTRACE_NODE_ACTION, "/* nat(src=%s) */",
> +                         vip_str);
> +out:
> +    free(vip_str);
>   }
>   
>   static bool
> @@ -3173,12 +3240,13 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
>               break;
>   
>           case OVNACT_CHK_LB_HAIRPIN:
> -            execute_chk_lb_hairpin(ovnact_get_CHK_LB_HAIRPIN(a), uflow, super);
> +            execute_chk_lb_hairpin(ovnact_get_CHK_LB_HAIRPIN(a), uflow, super,
> +                                   true);
>               break;
>   
>           case OVNACT_CHK_LB_HAIRPIN_REPLY:
> -            execute_chk_lb_hairpin_reply(ovnact_get_CHK_LB_HAIRPIN_REPLY(a),
> -                                         uflow, super);
> +            execute_chk_lb_hairpin(ovnact_get_CHK_LB_HAIRPIN_REPLY(a), uflow,
> +                                   super, false);
>               break;
>           case OVNACT_CT_SNAT_TO_VIP:
>               execute_ct_snat_to_vip(uflow, super);
>
Numan Siddique July 19, 2022, 5:22 p.m. UTC | #2
On Fri, Jul 1, 2022 at 1:41 PM Mark Michelson <mmichels@redhat.com> wrote:
>
> Thanks for this Lorenzo,
>
> Acked-by: Mark Michelson <mmichels@redhat.com>

Thanks.  I applied this patch to the main branch.

Numan

>
> On 6/30/22 09:22, Lorenzo Bianconi wrote:
> > Add chk_lb_hairpin_reply and ct_snat_to_vip implementations for ovn-trace
> > utility in order to simulate hairpin traffic
> >
> > Rreported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2099311
> > Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
> > ---
> >   tests/ovn-northd.at   |   8 ---
> >   utilities/ovn-trace.c | 126 ++++++++++++++++++++++++++++++++----------
> >   2 files changed, 97 insertions(+), 37 deletions(-)
> >
> > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> > index fe97bedad..2f293bfc8 100644
> > --- a/tests/ovn-northd.at
> > +++ b/tests/ovn-northd.at
> > @@ -2936,7 +2936,6 @@ AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
> >   ct_lb_mark {
> >       ct_lb_mark {
> >           reg0[[6]] = 0;
> > -        *** chk_lb_hairpin_reply action not implemented;
> >           reg0[[12]] = 0;
> >           ct_lb_mark /* default (use --ct to customize) */ {
> >               output("lsp2");
> > @@ -2952,7 +2951,6 @@ AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
> >   ct_lb_mark {
> >       ct_lb_mark {
> >           reg0[[6]] = 0;
> > -        *** chk_lb_hairpin_reply action not implemented;
> >           reg0[[12]] = 0;
> >           ct_lb_mark /* default (use --ct to customize) */ {
> >               output("lsp2");
> > @@ -2974,7 +2972,6 @@ AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
> >   ct_lb_mark {
> >       ct_lb_mark {
> >           reg0[[6]] = 0;
> > -        *** chk_lb_hairpin_reply action not implemented;
> >           reg0[[12]] = 0;
> >           ct_lb_mark /* default (use --ct to customize) */ {
> >               output("lsp2");
> > @@ -2990,7 +2987,6 @@ AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
> >   ct_lb_mark {
> >       ct_lb_mark {
> >           reg0[[6]] = 0;
> > -        *** chk_lb_hairpin_reply action not implemented;
> >           reg0[[12]] = 0;
> >           ct_lb_mark /* default (use --ct to customize) */ {
> >               output("lsp2");
> > @@ -3092,7 +3088,6 @@ AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
> >   ct_lb_mark {
> >       ct_lb_mark {
> >           reg0[[6]] = 0;
> > -        *** chk_lb_hairpin_reply action not implemented;
> >           reg0[[12]] = 0;
> >           ct_lb_mark /* default (use --ct to customize) */ {
> >               output("lsp2");
> > @@ -3108,7 +3103,6 @@ AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
> >   ct_lb_mark {
> >       ct_lb_mark {
> >           reg0[[6]] = 0;
> > -        *** chk_lb_hairpin_reply action not implemented;
> >           reg0[[12]] = 0;
> >           ct_lb_mark /* default (use --ct to customize) */ {
> >               output("lsp2");
> > @@ -3130,7 +3124,6 @@ AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
> >   ct_lb_mark {
> >       ct_lb_mark {
> >           reg0[[6]] = 0;
> > -        *** chk_lb_hairpin_reply action not implemented;
> >           reg0[[12]] = 0;
> >           ct_lb_mark /* default (use --ct to customize) */ {
> >               output("lsp2");
> > @@ -3146,7 +3139,6 @@ AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
> >   ct_lb_mark {
> >       ct_lb_mark {
> >           reg0[[6]] = 0;
> > -        *** chk_lb_hairpin_reply action not implemented;
> >           reg0[[12]] = 0;
> >           ct_lb_mark /* default (use --ct to customize) */ {
> >               output("lsp2");
> > diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
> > index c4110de0a..baf489202 100644
> > --- a/utilities/ovn-trace.c
> > +++ b/utilities/ovn-trace.c
> > @@ -2488,10 +2488,13 @@ execute_ct_lb(const struct ovnact_ct_lb *ct_lb,
> >
> >           if (dst) {
> >               if (family == AF_INET6) {
> > +                ct_lb_flow.ct_ipv6_dst = ct_lb_flow.ipv6_dst;
> >                   ct_lb_flow.ipv6_dst = dst->ipv6;
> >               } else {
> > +                ct_lb_flow.ct_nw_dst = ct_lb_flow.nw_dst;
> >                   ct_lb_flow.nw_dst = dst->ipv4;
> >               }
> > +            ct_lb_flow.ct_tp_dst = ct_lb_flow.tp_dst;
> >               if (dst->port) {
> >                   ct_lb_flow.tp_dst = htons(dst->port);
> >               }
> > @@ -2588,15 +2591,65 @@ execute_ovnfield_load(const struct ovnact_load *load,
> >       }
> >   }
> >
> > +static bool
> > +get_lb_vip_data(struct flow *uflow, struct in6_addr *vip,
> > +                char **vip_str, uint16_t *port)
> > +{
> > +    int family;
> > +
> > +    const struct sbrec_load_balancer *sbdb;
> > +    SBREC_LOAD_BALANCER_FOR_EACH (sbdb, ovnsb_idl) {
> > +        struct smap_node *node;
> > +        SMAP_FOR_EACH (node, &sbdb->vips) {
> > +            if (!ip_address_and_port_from_lb_key(node->key, vip_str,
> > +                                                 port, &family)) {
> > +                continue;
> > +            }
> > +
> > +            if (family == AF_INET) {
> > +                ovs_be32 vip4;
> > +                ip_parse(*vip_str, &vip4);
> > +                in6_addr_set_mapped_ipv4(vip, vip4);
> > +                if (vip4 == uflow->ct_nw_dst) {
> > +                    return true;
> > +                }
> > +            } else {
> > +                ipv6_parse(*vip_str, vip);
> > +                if (ipv6_addr_equals(vip, &uflow->ct_ipv6_dst)) {
> > +                    return true;
> > +                }
> > +            }
> > +            free(*vip_str);
> > +        }
> > +    }
> > +
> > +    return false;
> > +}
> > +
> >   static void
> >   execute_chk_lb_hairpin(const struct ovnact_result *dl, struct flow *uflow,
> > -                       struct ovs_list *super)
> > +                       struct ovs_list *super, bool dir_orig)
> >   {
> > -    int family = (uflow->dl_type == htons(ETH_TYPE_IP) ? AF_INET
> > -                  : uflow->dl_type == htons(ETH_TYPE_IPV6) ? AF_INET6
> > -                  : AF_UNSPEC);
> > +    struct mf_subfield sf = expr_resolve_field(&dl->dst);
> > +    union mf_subvalue sv = { .u8_val = 0 };
> > +    struct in6_addr vip;
> > +    uint16_t vip_port;
> >       uint8_t res = 0;
> > -    if (family != AF_UNSPEC && uflow->ct_state & CS_DST_NAT) {
> > +    char *vip_str;
> > +
> > +    if (!get_lb_vip_data(uflow, &vip, &vip_str, &vip_port)) {
> > +        goto out;
> > +    }
> > +    free(vip_str);
> > +
> > +    int family = (uflow->dl_type == htons(ETH_TYPE_IP) ? AF_INET
> > +                 : uflow->dl_type == htons(ETH_TYPE_IPV6) ? AF_INET6
> > +                 : AF_UNSPEC);
> > +    if (family == AF_UNSPEC) {
> > +        goto out;
> > +    }
> > +
> > +    if (uflow->ct_state & CS_DST_NAT) {
> >           if (family == AF_INET) {
> >               res = (uflow->nw_src == uflow->nw_dst) ? 1 : 0;
> >           } else {
> > @@ -2604,8 +2657,14 @@ execute_chk_lb_hairpin(const struct ovnact_result *dl, struct flow *uflow,
> >           }
> >       }
> >
> > -    struct mf_subfield sf = expr_resolve_field(&dl->dst);
> > -    union mf_subvalue sv = { .u8_val = res };
> > +    if (dir_orig) {
> > +        res &= (vip_port == ntohs(uflow->ct_tp_dst));
> > +    } else {
> > +        res &= (vip_port == ntohs(uflow->tp_dst));
> > +    }
> > +
> > +    sv.u8_val = res;
> > +out:
> >       mf_write_subfield_flow(&sf, &sv, uflow);
> >
> >       struct ds s = DS_EMPTY_INITIALIZER;
> > @@ -2616,27 +2675,35 @@ execute_chk_lb_hairpin(const struct ovnact_result *dl, struct flow *uflow,
> >   }
> >
> >   static void
> > -execute_chk_lb_hairpin_reply(const struct ovnact_result *dl,
> > -                             struct flow *uflow,
> > -                             struct ovs_list *super)
> > +execute_ct_snat_to_vip(struct flow *uflow, struct ovs_list *super)
> >   {
> > -    struct mf_subfield sf = expr_resolve_field(&dl->dst);
> > -    union mf_subvalue sv = { .u8_val = 0 };
> > -    mf_write_subfield_flow(&sf, &sv, uflow);
> > -    ovntrace_node_append(super, OVNTRACE_NODE_ERROR,
> > -                         "*** chk_lb_hairpin_reply action not implemented");
> > -    struct ds s = DS_EMPTY_INITIALIZER;
> > -    expr_field_format(&dl->dst, &s);
> > -    ovntrace_node_append(super, OVNTRACE_NODE_MODIFY,
> > -                         "%s = 0", ds_cstr(&s));
> > -    ds_destroy(&s);
> > -}
> > +    struct in6_addr vip;
> > +    uint16_t vip_port;
> > +    char *vip_str;
> >
> > -static void
> > -execute_ct_snat_to_vip(struct flow *uflow OVS_UNUSED, struct ovs_list *super)
> > -{
> > -    ovntrace_node_append(super, OVNTRACE_NODE_ERROR,
> > -                         "*** ct_snat_to_vip action not implemented");
> > +    if (!get_lb_vip_data(uflow, &vip, &vip_str, &vip_port)) {
> > +        return;
> > +    }
> > +
> > +    if (IN6_IS_ADDR_V4MAPPED(&vip)) {
> > +        ovs_be32 vip4 = in6_addr_get_mapped_ipv4(&vip);
> > +        if (vip4 != uflow->ct_nw_dst) {
> > +            goto out;
> > +        }
> > +    } else {
> > +        if (!ipv6_addr_equals(&vip, &uflow->ct_ipv6_dst)) {
> > +            goto out;
> > +        }
> > +    }
> > +
> > +    if (vip_port != ntohs(uflow->ct_tp_dst)) {
> > +        goto out;
> > +    }
> > +
> > +    ovntrace_node_append(super, OVNTRACE_NODE_ACTION, "/* nat(src=%s) */",
> > +                         vip_str);
> > +out:
> > +    free(vip_str);
> >   }
> >
> >   static bool
> > @@ -3173,12 +3240,13 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
> >               break;
> >
> >           case OVNACT_CHK_LB_HAIRPIN:
> > -            execute_chk_lb_hairpin(ovnact_get_CHK_LB_HAIRPIN(a), uflow, super);
> > +            execute_chk_lb_hairpin(ovnact_get_CHK_LB_HAIRPIN(a), uflow, super,
> > +                                   true);
> >               break;
> >
> >           case OVNACT_CHK_LB_HAIRPIN_REPLY:
> > -            execute_chk_lb_hairpin_reply(ovnact_get_CHK_LB_HAIRPIN_REPLY(a),
> > -                                         uflow, super);
> > +            execute_chk_lb_hairpin(ovnact_get_CHK_LB_HAIRPIN_REPLY(a), uflow,
> > +                                   super, false);
> >               break;
> >           case OVNACT_CT_SNAT_TO_VIP:
> >               execute_ct_snat_to_vip(uflow, super);
> >
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
diff mbox series

Patch

diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index fe97bedad..2f293bfc8 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -2936,7 +2936,6 @@  AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
 ct_lb_mark {
     ct_lb_mark {
         reg0[[6]] = 0;
-        *** chk_lb_hairpin_reply action not implemented;
         reg0[[12]] = 0;
         ct_lb_mark /* default (use --ct to customize) */ {
             output("lsp2");
@@ -2952,7 +2951,6 @@  AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
 ct_lb_mark {
     ct_lb_mark {
         reg0[[6]] = 0;
-        *** chk_lb_hairpin_reply action not implemented;
         reg0[[12]] = 0;
         ct_lb_mark /* default (use --ct to customize) */ {
             output("lsp2");
@@ -2974,7 +2972,6 @@  AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
 ct_lb_mark {
     ct_lb_mark {
         reg0[[6]] = 0;
-        *** chk_lb_hairpin_reply action not implemented;
         reg0[[12]] = 0;
         ct_lb_mark /* default (use --ct to customize) */ {
             output("lsp2");
@@ -2990,7 +2987,6 @@  AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
 ct_lb_mark {
     ct_lb_mark {
         reg0[[6]] = 0;
-        *** chk_lb_hairpin_reply action not implemented;
         reg0[[12]] = 0;
         ct_lb_mark /* default (use --ct to customize) */ {
             output("lsp2");
@@ -3092,7 +3088,6 @@  AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
 ct_lb_mark {
     ct_lb_mark {
         reg0[[6]] = 0;
-        *** chk_lb_hairpin_reply action not implemented;
         reg0[[12]] = 0;
         ct_lb_mark /* default (use --ct to customize) */ {
             output("lsp2");
@@ -3108,7 +3103,6 @@  AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
 ct_lb_mark {
     ct_lb_mark {
         reg0[[6]] = 0;
-        *** chk_lb_hairpin_reply action not implemented;
         reg0[[12]] = 0;
         ct_lb_mark /* default (use --ct to customize) */ {
             output("lsp2");
@@ -3130,7 +3124,6 @@  AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
 ct_lb_mark {
     ct_lb_mark {
         reg0[[6]] = 0;
-        *** chk_lb_hairpin_reply action not implemented;
         reg0[[12]] = 0;
         ct_lb_mark /* default (use --ct to customize) */ {
             output("lsp2");
@@ -3146,7 +3139,6 @@  AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dn
 ct_lb_mark {
     ct_lb_mark {
         reg0[[6]] = 0;
-        *** chk_lb_hairpin_reply action not implemented;
         reg0[[12]] = 0;
         ct_lb_mark /* default (use --ct to customize) */ {
             output("lsp2");
diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
index c4110de0a..baf489202 100644
--- a/utilities/ovn-trace.c
+++ b/utilities/ovn-trace.c
@@ -2488,10 +2488,13 @@  execute_ct_lb(const struct ovnact_ct_lb *ct_lb,
 
         if (dst) {
             if (family == AF_INET6) {
+                ct_lb_flow.ct_ipv6_dst = ct_lb_flow.ipv6_dst;
                 ct_lb_flow.ipv6_dst = dst->ipv6;
             } else {
+                ct_lb_flow.ct_nw_dst = ct_lb_flow.nw_dst;
                 ct_lb_flow.nw_dst = dst->ipv4;
             }
+            ct_lb_flow.ct_tp_dst = ct_lb_flow.tp_dst;
             if (dst->port) {
                 ct_lb_flow.tp_dst = htons(dst->port);
             }
@@ -2588,15 +2591,65 @@  execute_ovnfield_load(const struct ovnact_load *load,
     }
 }
 
+static bool
+get_lb_vip_data(struct flow *uflow, struct in6_addr *vip,
+                char **vip_str, uint16_t *port)
+{
+    int family;
+
+    const struct sbrec_load_balancer *sbdb;
+    SBREC_LOAD_BALANCER_FOR_EACH (sbdb, ovnsb_idl) {
+        struct smap_node *node;
+        SMAP_FOR_EACH (node, &sbdb->vips) {
+            if (!ip_address_and_port_from_lb_key(node->key, vip_str,
+                                                 port, &family)) {
+                continue;
+            }
+
+            if (family == AF_INET) {
+                ovs_be32 vip4;
+                ip_parse(*vip_str, &vip4);
+                in6_addr_set_mapped_ipv4(vip, vip4);
+                if (vip4 == uflow->ct_nw_dst) {
+                    return true;
+                }
+            } else {
+                ipv6_parse(*vip_str, vip);
+                if (ipv6_addr_equals(vip, &uflow->ct_ipv6_dst)) {
+                    return true;
+                }
+            }
+            free(*vip_str);
+        }
+    }
+
+    return false;
+}
+
 static void
 execute_chk_lb_hairpin(const struct ovnact_result *dl, struct flow *uflow,
-                       struct ovs_list *super)
+                       struct ovs_list *super, bool dir_orig)
 {
-    int family = (uflow->dl_type == htons(ETH_TYPE_IP) ? AF_INET
-                  : uflow->dl_type == htons(ETH_TYPE_IPV6) ? AF_INET6
-                  : AF_UNSPEC);
+    struct mf_subfield sf = expr_resolve_field(&dl->dst);
+    union mf_subvalue sv = { .u8_val = 0 };
+    struct in6_addr vip;
+    uint16_t vip_port;
     uint8_t res = 0;
-    if (family != AF_UNSPEC && uflow->ct_state & CS_DST_NAT) {
+    char *vip_str;
+
+    if (!get_lb_vip_data(uflow, &vip, &vip_str, &vip_port)) {
+        goto out;
+    }
+    free(vip_str);
+
+    int family = (uflow->dl_type == htons(ETH_TYPE_IP) ? AF_INET
+                 : uflow->dl_type == htons(ETH_TYPE_IPV6) ? AF_INET6
+                 : AF_UNSPEC);
+    if (family == AF_UNSPEC) {
+        goto out;
+    }
+
+    if (uflow->ct_state & CS_DST_NAT) {
         if (family == AF_INET) {
             res = (uflow->nw_src == uflow->nw_dst) ? 1 : 0;
         } else {
@@ -2604,8 +2657,14 @@  execute_chk_lb_hairpin(const struct ovnact_result *dl, struct flow *uflow,
         }
     }
 
-    struct mf_subfield sf = expr_resolve_field(&dl->dst);
-    union mf_subvalue sv = { .u8_val = res };
+    if (dir_orig) {
+        res &= (vip_port == ntohs(uflow->ct_tp_dst));
+    } else {
+        res &= (vip_port == ntohs(uflow->tp_dst));
+    }
+
+    sv.u8_val = res;
+out:
     mf_write_subfield_flow(&sf, &sv, uflow);
 
     struct ds s = DS_EMPTY_INITIALIZER;
@@ -2616,27 +2675,35 @@  execute_chk_lb_hairpin(const struct ovnact_result *dl, struct flow *uflow,
 }
 
 static void
-execute_chk_lb_hairpin_reply(const struct ovnact_result *dl,
-                             struct flow *uflow,
-                             struct ovs_list *super)
+execute_ct_snat_to_vip(struct flow *uflow, struct ovs_list *super)
 {
-    struct mf_subfield sf = expr_resolve_field(&dl->dst);
-    union mf_subvalue sv = { .u8_val = 0 };
-    mf_write_subfield_flow(&sf, &sv, uflow);
-    ovntrace_node_append(super, OVNTRACE_NODE_ERROR,
-                         "*** chk_lb_hairpin_reply action not implemented");
-    struct ds s = DS_EMPTY_INITIALIZER;
-    expr_field_format(&dl->dst, &s);
-    ovntrace_node_append(super, OVNTRACE_NODE_MODIFY,
-                         "%s = 0", ds_cstr(&s));
-    ds_destroy(&s);
-}
+    struct in6_addr vip;
+    uint16_t vip_port;
+    char *vip_str;
 
-static void
-execute_ct_snat_to_vip(struct flow *uflow OVS_UNUSED, struct ovs_list *super)
-{
-    ovntrace_node_append(super, OVNTRACE_NODE_ERROR,
-                         "*** ct_snat_to_vip action not implemented");
+    if (!get_lb_vip_data(uflow, &vip, &vip_str, &vip_port)) {
+        return;
+    }
+
+    if (IN6_IS_ADDR_V4MAPPED(&vip)) {
+        ovs_be32 vip4 = in6_addr_get_mapped_ipv4(&vip);
+        if (vip4 != uflow->ct_nw_dst) {
+            goto out;
+        }
+    } else {
+        if (!ipv6_addr_equals(&vip, &uflow->ct_ipv6_dst)) {
+            goto out;
+        }
+    }
+
+    if (vip_port != ntohs(uflow->ct_tp_dst)) {
+        goto out;
+    }
+
+    ovntrace_node_append(super, OVNTRACE_NODE_ACTION, "/* nat(src=%s) */",
+                         vip_str);
+out:
+    free(vip_str);
 }
 
 static bool
@@ -3173,12 +3240,13 @@  trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
             break;
 
         case OVNACT_CHK_LB_HAIRPIN:
-            execute_chk_lb_hairpin(ovnact_get_CHK_LB_HAIRPIN(a), uflow, super);
+            execute_chk_lb_hairpin(ovnact_get_CHK_LB_HAIRPIN(a), uflow, super,
+                                   true);
             break;
 
         case OVNACT_CHK_LB_HAIRPIN_REPLY:
-            execute_chk_lb_hairpin_reply(ovnact_get_CHK_LB_HAIRPIN_REPLY(a),
-                                         uflow, super);
+            execute_chk_lb_hairpin(ovnact_get_CHK_LB_HAIRPIN_REPLY(a), uflow,
+                                   super, false);
             break;
         case OVNACT_CT_SNAT_TO_VIP:
             execute_ct_snat_to_vip(uflow, super);