From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: passt.top; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=Jxn6/CLB; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by passt.top (Postfix) with ESMTPS id 656CA5A0274 for ; Thu, 27 Nov 2025 01:53:25 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1764204804; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=JVrxSLCT+Ed+qFRh7djMyrGXOD8WKZ/we9sEA86qF2w=; b=Jxn6/CLB3gcNieV5mLQ8DJNtQKw0x7ze7JKwEDq/zCQmanZed4y1HNBY0lk63P+lZMeOh9 /mzdEtyxbzJEEKda4fWJOAz/tXdWB8q3T5rfDq8E1SCgeneczi2OODhHmQGTTnedJkZsf7 OhAOohz0xw2uRo47ByWpdusHqQAlJdA= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-166-t45BSz84NR66qjeyl65MYw-1; Wed, 26 Nov 2025 19:53:21 -0500 X-MC-Unique: t45BSz84NR66qjeyl65MYw-1 X-Mimecast-MFC-AGG-ID: t45BSz84NR66qjeyl65MYw_1764204800 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id E8EDE180048E; Thu, 27 Nov 2025 00:53:19 +0000 (UTC) Received: from jmaloy-thinkpadp16vgen1.rmtcaqc.csb (unknown [10.22.65.198]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id D54601956056; Thu, 27 Nov 2025 00:53:17 +0000 (UTC) From: Jon Maloy To: sbrivio@redhat.com, dgibson@redhat.com, david@gibson.dropbear.id.au, jmaloy@redhat.com, passt-dev@passt.top Subject: [PATCH] arp/ndp: don't send messages on uninitialized tap interface Date: Wed, 26 Nov 2025 19:53:16 -0500 Message-ID: <20251127005316.3015592-1-jmaloy@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: hDnmnqHTRBpJX7x3TdiB1YC4VME7WBhXW2fgBTA5w_o_1764204800 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit content-type: text/plain; charset="US-ASCII"; x-default=true Message-ID-Hash: TK6E72CX3S4QHZQDOEVEHBZN4UMIGPAE X-Message-ID-Hash: TK6E72CX3S4QHZQDOEVEHBZN4UMIGPAE X-MailFrom: jmaloy@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: When running pasta without --config-net, the tap interface is opened and assigned a valid file descriptor, but intentionally not brought up in the namespace. This is the expected behavior when the user wants to configure the namespace manually. However, in PASTA mode the code is attempting to send ARP announcements and NDP messages (initial requests and unsolicited NAs) based solely on whether c->fd_tap is valid, without checking if the interface actually is up and ready to transmit. This results in send failures, and when debug is activated (pasta -d) we see error printouts for these early messages. We now add new function tap_is_ready() which checks both conditions: - Whether fd_tap is valid (all modes) - Whether the tap interface is up (pasta mode only). In this mode, we use the existing c->pasta_conf_ns flag, which indicates whether pasta_ns_conf() configured and brought up the interface. This test is simple, and good enough for now. We update all functions that send unsolicited ARP/NDP messages to check with the new function before making any send attempt. This eliminates spurious send errors when starting pasta without --config-net, while preserving correct behavior when the interface is properly initialized. Signed-off-by: Jon Maloy --- arp.c | 3 +++ ndp.c | 5 +++-- tap.c | 27 +++++++++++++++++++++++++++ tap.h | 1 + 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/arp.c b/arp.c index 33b03cf..bb042e9 100644 --- a/arp.c +++ b/arp.c @@ -168,6 +168,9 @@ void arp_announce(const struct ctx *c, struct in_addr *ip, struct arpmsg am; } __attribute__((__packed__)) msg; + if (!tap_is_ready(c)) + return; + /* Ethernet header */ msg.eh.h_proto = htons(ETH_P_ARP); memcpy(msg.eh.h_dest, MAC_BROADCAST, sizeof(msg.eh.h_dest)); diff --git a/ndp.c b/ndp.c index a33239d..eb9e313 100644 --- a/ndp.c +++ b/ndp.c @@ -227,7 +227,8 @@ static void ndp_na(const struct ctx *c, const struct in6_addr *dst, */ void ndp_unsolicited_na(const struct ctx *c, const struct in6_addr *addr) { - ndp_na(c, &in6addr_ll_all_nodes, addr); + if (tap_is_ready(c)) + ndp_na(c, &in6addr_ll_all_nodes, addr); } /** @@ -411,7 +412,7 @@ void ndp_timer(const struct ctx *c, const struct timespec *now) time_t max_rtr_adv_interval = DEFAULT_MAX_RTR_ADV_INTERVAL; time_t min_rtr_adv_interval, interval; - if (c->fd_tap < 0 || c->no_ra || now->tv_sec < next_ra) + if (!tap_is_ready(c) || c->no_ra || now->tv_sec < next_ra) return; /* We must advertise before the route's lifetime expires */ diff --git a/tap.c b/tap.c index bb139d6..44b0644 100644 --- a/tap.c +++ b/tap.c @@ -1339,6 +1339,30 @@ static void tap_sock_unix_init(const struct ctx *c) epoll_add(c->epollfd, EPOLLIN | EPOLLET, ref); } +/** + * tap_is_ready() - Check if tap interface is ready to send packets + * @c: Execution context + * + * For pasta mode, checks if the tap interface is up. + * For other modes, just checks if fd_tap is valid. + * + * Return: true if ready, false otherwise + */ +bool tap_is_ready(const struct ctx *c) +{ + if (c->fd_tap < 0) + return false; + + if (c->mode == MODE_PASTA) { + /* If pasta_conf_ns is set, the interface was configured and + * brought up during initialization. If not, it's still down. + */ + return c->pasta_conf_ns; + } + + return true; +} + /** * tap_start_connection() - start a new connection * @c: Execution context @@ -1362,6 +1386,9 @@ static void tap_start_connection(const struct ctx *c) epoll_add(c->epollfd, EPOLLIN | EPOLLRDHUP, ref); + if (!tap_is_ready(c)) + return; + if (c->ifi4) arp_send_init_req(c); if (c->ifi6 && !c->no_ndp) diff --git a/tap.h b/tap.h index 1864173..ee22a9d 100644 --- a/tap.h +++ b/tap.h @@ -109,6 +109,7 @@ size_t tap_send_frames(const struct ctx *c, const struct iovec *iov, size_t bufs_per_frame, size_t nframes); void eth_update_mac(struct ethhdr *eh, const unsigned char *eth_d, const unsigned char *eth_s); +bool tap_is_ready(const struct ctx *c); void tap_listen_handler(struct ctx *c, uint32_t events); void tap_handler_pasta(struct ctx *c, uint32_t events, const struct timespec *now); -- 2.51.1