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
