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 <[email protected]>
---
 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);
-- 
2.36.1

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to