From patchwork Thu Dec 15 03:49:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "wushaohua@chinatelecom.cn" X-Patchwork-Id: 1716002 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4NXdXy0cPxz23ym for ; Thu, 15 Dec 2022 14:50:09 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id D8A0860BF0; Thu, 15 Dec 2022 03:50:07 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org D8A0860BF0 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id yCKsyvFFQk67; Thu, 15 Dec 2022 03:50:06 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp3.osuosl.org (Postfix) with ESMTPS id C5AC960B44; Thu, 15 Dec 2022 03:50:05 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org C5AC960B44 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 87EBEC0032; Thu, 15 Dec 2022 03:50:05 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 39BE8C002D for ; Thu, 15 Dec 2022 03:50:04 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 0D3E281E54 for ; Thu, 15 Dec 2022 03:50:04 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 0D3E281E54 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id aCH0GCMKdHwg for ; Thu, 15 Dec 2022 03:50:02 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org C9DBC81E41 Received: from chinatelecom.cn (prt-mail.chinatelecom.cn [42.123.76.220]) by smtp1.osuosl.org (Postfix) with ESMTP id C9DBC81E41 for ; Thu, 15 Dec 2022 03:50:01 +0000 (UTC) HMM_SOURCE_IP: 172.18.0.218:60652.29286842 HMM_ATTACHE_NUM: 0000 HMM_SOURCE_TYPE: SMTP Received: from clientip-101.43.140.16 (unknown [172.18.0.218]) by chinatelecom.cn (HERMES) with SMTP id 791BB2800A4; Thu, 15 Dec 2022 11:49:53 +0800 (CST) X-189-SAVE-TO-SEND: +wushaohua@chinatelecom.cn Received: from ([101.43.140.16]) by app0025 with ESMTP id 3fe167603b5841a0a9858953749afba1 for dev@openvswitch.org; Thu, 15 Dec 2022 11:49:56 CST X-Transaction-ID: 3fe167603b5841a0a9858953749afba1 X-Real-From: wushaohua@chinatelecom.cn X-Receive-IP: 101.43.140.16 X-MEDUSA-Status: 0 From: wushaohua@chinatelecom.cn To: dev@openvswitch.org Date: Thu, 15 Dec 2022 11:49:51 +0800 Message-Id: <20221215034951.1754772-1-wushaohua@chinatelecom.cn> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221211032257.822854-1-wushaohua@chinatelecom.cn> References: <20221211032257.822854-1-wushaohua@chinatelecom.cn> MIME-Version: 1.0 Cc: ctyun-rd1-INF-Network@chinatelecom.cn Subject: [ovs-dev] [PATCH v2] conntrack: Fix icmp_id conflicts in snat X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: wushaohua The icmp_id maybe conflicts in snat Description: If multiple devices send icmp packets with the same icmp_id, the sip of the packets changes to the same source ip address after the snat operation, and the packets are sent to the same destination ip address. Only one ct entry is created.The data packets sent by other devices cannot be sent to the peer device ovs-appctl dpctl/dump-conntrack icmp,orig=(src=10.0.0.4,dst=10.0.0.2,id=500,type=8,code=0),reply=(src=10.0.0.2,dst=10.0.0.201,id=500,type=0,code=0) After fixing the problem: ovs-appctl dpctl/dump-conntrack icmp,orig=(src=10.0.0.3,dst=10.0.0.2,id=500,type=8,code=0),reply=(src=10.0.0.2,dst=10.0.0.201,id=501,type=0,code=0) icmp,orig=(src=10.0.0.1,dst=10.0.0.2,id=500,type=8,code=0),reply=(src=10.0.0.2,dst=10.0.0.201,id=500,type=0,code=0) icmp,orig=(src=10.0.0.7,dst=10.0.0.2,id=500,type=8,code=0),reply=(src=10.0.0.2,dst=10.0.0.201,id=505,type=0,code=0) icmp,orig=(src=10.0.0.4,dst=10.0.0.2,id=500,type=8,code=0),reply=(src=10.0.0.2,dst=10.0.0.201,id=502,type=0,code=0) icmp,orig=(src=10.0.0.5,dst=10.0.0.2,id=500,type=8,code=0),reply=(src=10.0.0.2,dst=10.0.0.201,id=503,type=0,code=0) icmp,orig=(src=10.0.0.6,dst=10.0.0.2,id=500,type=8,code=0),reply=(src=10.0.0.2,dst=10.0.0.201,id=504,type=0,code=0) Signed-off-by: wushaohua --- lib/conntrack.c | 51 +++++++++++++++++++++++++++++++++++++++++++------ lib/packets.c | 22 +++++++++++++++++++++ lib/packets.h | 2 ++ 3 files changed, 69 insertions(+), 6 deletions(-) diff --git a/lib/conntrack.c b/lib/conntrack.c index 550b2be9b..a5d3e6a3f 100644 --- a/lib/conntrack.c +++ b/lib/conntrack.c @@ -697,6 +697,24 @@ get_ip_proto(const struct dp_packet *pkt) return ip_proto; } +static bool +packet_is_icmpv4_info_message(const struct dp_packet *pkt) +{ + uint8_t ip_proto,icmp_type; + + ip_proto = get_ip_proto(pkt); + if (ip_proto == IPPROTO_ICMP) { + icmp_type = packet_get_icmp_type(pkt); + if (icmp_type == ICMP4_ECHO_REQUEST || + icmp_type == ICMP4_ECHO_REPLY || + icmp_type == ICMP4_TIMESTAMP || + icmp_type == ICMP4_TIMESTAMPREPLY || + icmp_type == ICMP4_INFOREQUEST || + icmp_type == ICMP4_INFOREPLY) + return true; + } + return false; +} static bool is_ftp_ctl(const enum ct_alg_ctl_type ct_alg_ctl) { @@ -773,6 +791,9 @@ pat_packet(struct dp_packet *pkt, const struct conn *conn) } else if (conn->key.nw_proto == IPPROTO_UDP) { struct udp_header *uh = dp_packet_l4(pkt); packet_set_udp_port(pkt, conn->rev_key.dst.port, uh->udp_dst); + } else if (packet_is_icmpv4_info_message(pkt) && + conn->key.nw_proto == IPPROTO_ICMP) { + packet_set_icmp_id(pkt, conn->rev_key.dst.icmp_id); } } else if (conn->nat_action & NAT_ACTION_DST) { if (conn->key.nw_proto == IPPROTO_TCP) { @@ -781,6 +802,9 @@ pat_packet(struct dp_packet *pkt, const struct conn *conn) } else if (conn->key.nw_proto == IPPROTO_UDP) { packet_set_udp_port(pkt, conn->rev_key.dst.port, conn->rev_key.src.port); + } else if (packet_is_icmpv4_info_message(pkt) && + conn->key.nw_proto == IPPROTO_ICMP) { + packet_set_icmp_id(pkt, conn->rev_key.src.icmp_id); } } } @@ -831,13 +855,19 @@ un_pat_packet(struct dp_packet *pkt, const struct conn *conn) } else if (conn->key.nw_proto == IPPROTO_UDP) { struct udp_header *uh = dp_packet_l4(pkt); packet_set_udp_port(pkt, uh->udp_src, conn->key.src.port); - } + } else if (packet_is_icmpv4_info_message(pkt) && + conn->key.nw_proto == IPPROTO_ICMP) { + packet_set_icmp_id(pkt, conn->key.src.icmp_id); + } } else if (conn->nat_action & NAT_ACTION_DST) { if (conn->key.nw_proto == IPPROTO_TCP) { packet_set_tcp_port(pkt, conn->key.dst.port, conn->key.src.port); } else if (conn->key.nw_proto == IPPROTO_UDP) { packet_set_udp_port(pkt, conn->key.dst.port, conn->key.src.port); - } + } else if (packet_is_icmpv4_info_message(pkt) && + conn->key.nw_proto == IPPROTO_ICMP) { + packet_set_icmp_id(pkt, conn->key.dst.icmp_id); + } } } @@ -2366,8 +2396,8 @@ store_addr_to_key(union ct_addr *addr, struct conn_key *key, static bool nat_get_unique_l4(struct conntrack *ct, struct conn *nat_conn, - ovs_be16 *port, uint16_t curr, uint16_t min, - uint16_t max) + ovs_be16 *port, ovs_be16 *peer_port, + uint16_t curr, uint16_t min, uint16_t max) { static const unsigned int max_attempts = 128; uint16_t range = max - min + 1; @@ -2388,6 +2418,9 @@ another_round: } *port = htons(curr); + if (peer_port) { + *peer_port = htons(curr); + } if (!conn_lookup(ct, &nat_conn->rev_key, time_msec(), NULL, NULL)) { return true; @@ -2401,6 +2434,9 @@ another_round: } *port = htons(orig); + if (peer_port) { + *peer_port = htons(orig); + } return false; } @@ -2434,7 +2470,8 @@ nat_get_unique_tuple(struct conntrack *ct, const struct conn *conn, uint32_t hash = nat_range_hash(conn, ct->hash_basis, nat_info); union ct_addr min_addr = {0}, max_addr = {0}, addr = {0}; bool pat_proto = conn->key.nw_proto == IPPROTO_TCP || - conn->key.nw_proto == IPPROTO_UDP; + conn->key.nw_proto == IPPROTO_UDP || + conn->key.nw_proto == IPPROTO_ICMP; uint16_t min_dport, max_dport, curr_dport; uint16_t min_sport, max_sport, curr_sport; @@ -2469,11 +2506,13 @@ nat_get_unique_tuple(struct conntrack *ct, const struct conn *conn, bool found = false; if (nat_info->nat_action & NAT_ACTION_DST_PORT) { found = nat_get_unique_l4(ct, nat_conn, &nat_conn->rev_key.src.port, - curr_dport, min_dport, max_dport); + NULL,curr_dport, min_dport, max_dport); } if (!found) { found = nat_get_unique_l4(ct, nat_conn, &nat_conn->rev_key.dst.port, + nat_conn->rev_key.nw_proto == IPPROTO_ICMP ? + &nat_conn->rev_key.src.port : NULL, curr_sport, min_sport, max_sport); } diff --git a/lib/packets.c b/lib/packets.c index 1dcd4a6fc..11d21d8c3 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -1441,6 +1441,28 @@ packet_set_icmp(struct dp_packet *packet, uint8_t type, uint8_t code) pkt_metadata_init_conn(&packet->md); } +/* Sets the ICMP id of the ICMP header contained in 'packet'. + * 'packet' must be a valid ICMP packet with its l4 offset properly + * populated. */ +void +packet_set_icmp_id(struct dp_packet *packet, ovs_be16 icmp_id) +{ + struct icmp_header *ih = dp_packet_l4(packet); + ovs_be16 orig_ic = ih->icmp_fields.echo.id; + + if (icmp_id != orig_ic) { + ih->icmp_fields.echo.id = icmp_id; + ih->icmp_csum = recalc_csum16(ih->icmp_csum, orig_ic, icmp_id); + } + pkt_metadata_init_conn(&packet->md); +} + +uint8_t +packet_get_icmp_type(const struct dp_packet *packet) +{ + struct icmp_header *ih = dp_packet_l4(packet); + return ih->icmp_type; +} /* Sets the IGMP type to IGMP_HOST_MEMBERSHIP_QUERY and populates the * v3 query header fields in 'packet'. 'packet' must be a valid IGMPv3 * query packet with its l4 offset properly populated. diff --git a/lib/packets.h b/lib/packets.h index 5bdf6e4bb..f30ace119 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -1602,6 +1602,8 @@ void packet_set_tcp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst); void packet_set_udp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst); void packet_set_sctp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst); void packet_set_icmp(struct dp_packet *, uint8_t type, uint8_t code); +void packet_set_icmp_id(struct dp_packet *, ovs_be16 icmp_id); +uint8_t packet_get_icmp_type(const struct dp_packet *packet); void packet_set_nd(struct dp_packet *, const struct in6_addr *target, const struct eth_addr sll, const struct eth_addr tll); void packet_set_nd_ext(struct dp_packet *packet,