From 5a5510805c8e60422d2bb7ef74b340da346f32d3 Mon Sep 17 00:00:00 2001 From: Tao Date: Tue, 1 Aug 2023 14:39:54 +0200 Subject: [PATCH] resolve route instability issue by tracking if an incming offloading rule has been installed to arriving port --- include/dp_flow.h | 4 +++ src/dp_cntrack.c | 35 ++++++++++++++++------ src/rte_flow/dp_rte_flow_traffic_forward.c | 10 ++++++- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/include/dp_flow.h b/include/dp_flow.h index 8b76b3098..73333733a 100644 --- a/include/dp_flow.h +++ b/include/dp_flow.h @@ -117,6 +117,10 @@ struct flow_value { uint8_t orig : 4; uint8_t reply : 4; } offload_flags; + struct { + uint8_t pf0 : 4; + uint8_t pf1 : 4; + } incoming_flow_offloaded_flag; struct dp_ref ref_count; union { enum dp_flow_tcp_state tcp_state; diff --git a/src/dp_cntrack.c b/src/dp_cntrack.c index 1ec86ed9f..06b3f4ed7 100644 --- a/src/dp_cntrack.c +++ b/src/dp_cntrack.c @@ -70,35 +70,52 @@ static __rte_always_inline void dp_cntrack_init_flow_offload_flags(struct flow_v } -static __rte_always_inline void dp_cntrack_change_flow_offload_flags(struct flow_value *flow_val, struct dp_flow *df) +static __rte_always_inline void dp_cntrack_change_flow_offload_flags(struct rte_mbuf *m, struct flow_value *flow_val, struct dp_flow *df) { + bool offload_check = false; + if (!offload_mode_enabled) return; + if (df->flags.flow_type == DP_FLOW_TYPE_INCOMING) { + if (m->port == dp_port_get_pf0_id()) + offload_check = flow_val->incoming_flow_offloaded_flag.pf0; + else + offload_check = flow_val->incoming_flow_offloaded_flag.pf1; + } + if (df->flags.dir == DP_FLOW_DIR_ORG) { if (flow_val->offload_flags.orig == DP_FLOW_NON_OFFLOAD) flow_val->offload_flags.orig = DP_FLOW_OFFLOAD_INSTALL; - else if (flow_val->offload_flags.orig == DP_FLOW_OFFLOAD_INSTALL) + else if (flow_val->offload_flags.orig == DP_FLOW_OFFLOAD_INSTALL) { + /* Despite the incoming flow is offloaded to one of the pf ports, pkts can arrive on another one */ + /* So we need to check if the incoming flow is offloaded on the current port, if not, we hold the change of offload flags and do another offloading */ + if (df->flags.flow_type == DP_FLOW_TYPE_INCOMING && !offload_check) + return; flow_val->offload_flags.orig = DP_FLOW_OFFLOADED; + } } else if (df->flags.dir == DP_FLOW_DIR_REPLY) { if (flow_val->offload_flags.reply == DP_FLOW_NON_OFFLOAD) flow_val->offload_flags.reply = DP_FLOW_OFFLOAD_INSTALL; - else if (flow_val->offload_flags.reply == DP_FLOW_OFFLOAD_INSTALL) + else if (flow_val->offload_flags.reply == DP_FLOW_OFFLOAD_INSTALL) { + if (df->flags.flow_type == DP_FLOW_TYPE_INCOMING && !offload_check) + return; flow_val->offload_flags.reply = DP_FLOW_OFFLOADED; + } } } -static __rte_always_inline void dp_cntrack_set_timeout_tcp_flow(struct flow_value *flow_val, struct dp_flow *df) +static __rte_always_inline void dp_cntrack_set_timeout_tcp_flow(struct flow_value *flow_val, struct dp_flow *df, struct rte_mbuf *m) { if (flow_val->l4_state.tcp_state == DP_FLOW_TCP_STATE_ESTABLISHED) { flow_val->timeout_value = DP_FLOW_TCP_EXTENDED_TIMEOUT; - dp_cntrack_change_flow_offload_flags(flow_val, df); + dp_cntrack_change_flow_offload_flags(m, flow_val, df); } else if (flow_val->l4_state.tcp_state == DP_FLOW_TCP_STATE_FINWAIT || flow_val->l4_state.tcp_state == DP_FLOW_TCP_STATE_RST_FIN) { - dp_cntrack_change_flow_offload_flags(flow_val, df); + dp_cntrack_change_flow_offload_flags(m, flow_val, df); flow_val->timeout_value = flow_timeout; } else flow_val->timeout_value = flow_timeout; @@ -192,7 +209,7 @@ static __rte_always_inline void dp_set_flow_offload_flag(struct rte_mbuf *m, str if (flow_val->nf_info.nat_type == DP_FLOW_NAT_TYPE_NETWORK_NEIGH || flow_val->nf_info.nat_type == DP_FLOW_LB_TYPE_FORWARD || flow_val->nf_info.nat_type == DP_FLOW_LB_TYPE_LOCAL_NEIGH_TRAFFIC) { - dp_cntrack_change_flow_offload_flags(flow_val, df); + dp_cntrack_change_flow_offload_flags(m, flow_val, df); } else { // recirc pkt shall not change flow's state because its ancestor has already done @@ -201,7 +218,7 @@ static __rte_always_inline void dp_set_flow_offload_flag(struct rte_mbuf *m, str // when to offload reply pkt of a tcp flow is determined in dp_cntrack_set_timeout_tcp_flow if (df->l4_type != IPPROTO_TCP) - dp_cntrack_change_flow_offload_flags(flow_val, df); + dp_cntrack_change_flow_offload_flags(m, flow_val, df); } } @@ -266,7 +283,7 @@ int dp_cntrack_handle(struct rte_node *node, struct rte_mbuf *m, struct dp_flow if (df->l4_type == IPPROTO_TCP && !dp_get_pkt_mark(m)->flags.is_recirc) { tcp_hdr = (struct rte_tcp_hdr *) (ipv4_hdr + 1); dp_cntrack_tcp_state(flow_val, tcp_hdr); - dp_cntrack_set_timeout_tcp_flow(flow_val, df); + dp_cntrack_set_timeout_tcp_flow(flow_val, df, m); } df->conntrack = flow_val; dp_cntrack_set_pkt_offload_decision(df); diff --git a/src/rte_flow/dp_rte_flow_traffic_forward.c b/src/rte_flow/dp_rte_flow_traffic_forward.c index a5d429075..73681663c 100644 --- a/src/rte_flow/dp_rte_flow_traffic_forward.c +++ b/src/rte_flow/dp_rte_flow_traffic_forward.c @@ -306,7 +306,15 @@ static __rte_always_inline int dp_offload_handle_tunnel_encap_traffic(struct rte static __rte_always_inline int dp_offload_handle_tunnel_decap_traffic(struct rte_mbuf *m, struct dp_flow *df) { - bool cross_pf_port = m->port == dp_port_get_pf0_id() ? false : true; + bool cross_pf_port; + + if (m->port == dp_port_get_pf0_id()) { + cross_pf_port = false; + df->conntrack->incoming_flow_offloaded_flag.pf0 = true; + } else { + cross_pf_port = true; + df->conntrack->incoming_flow_offloaded_flag.pf1 = true; + } struct rte_flow_attr attr; int hairpin_pattern_cnt = 0;