From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=none (p=none dis=none) header.from=njh.eu Received: from mail.notjusthosting.com (mail.notjusthosting.com [IPv6:2a01:4f8:a0:516f:1::1]) by passt.top (Postfix) with ESMTPS id BD3275A0271 for ; Sun, 07 Sep 2025 12:57:03 +0200 (CEST) Received: from dynamic-2a02-3100-19ff-3600-45c4-4833-9384-ec1a.310.pool.telefonica.de ([2a02:3100:19ff:3600:45c4:4833:9384:ec1a] helo=vlap) by mail.notjusthosting.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.89) (envelope-from ) id 1uvD4x-00070I-8X for passt-dev@passt.top; Sun, 07 Sep 2025 12:57:03 +0200 Date: Sun, 7 Sep 2025 12:57:02 +0200 From: Volker Diels-Grabsch To: passt-dev@passt.top Subject: Re: [PATCH] Send an initial ARP request to resolve the guest IP address Message-ID: References: <20250907104912.17917-1-v@njh.eu> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20250907104912.17917-1-v@njh.eu> Message-ID-Hash: K7PQDOKEISL2LTOMBKOB4C6E43ZVJXFV X-Message-ID-Hash: K7PQDOKEISL2LTOMBKOB4C6E43ZVJXFV X-MailFrom: v@njh.eu 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: Hi all, please ignore this one, it was sent by accident. I'll send the actual patch soon. Sorry for the noise. Best regards, Volker Volker Diels-Grabsch wrote: > When restarting passt while QEMU keeps running with a configured > "reconnect-ms" setting, the port forwardings will stop working until > the guest sends some outgoing network traffic. > > Reason: Although QEMU reconnects successfully to the unix domain > socket of the new passt process, that one no longer knows the guest's > MAC address and uses instead a broadcast MAC address. However, this > is ignored by the guest, at least if the guest runs Linux. Only after > the guest sends some network package on its own initiative, passt will > know the MAC address and will be able to establish forwarded > connections. > > This change fixes this issue by sending an ARP request to resolve the > guest's MAC address via its IP address, which we do know, right after > the unix domain socket (re)connection. > > The only case where the IP is "wrong" would be if the configuration > changed, and/or on the very first start right after qemu started. But > in those cases, we just wouldn't get an ARP response, and can't do > anything receive the guest's DHCP request - just as before. In other > words, in the worst case an ARP request would be harmless. > > Signed-off-by: Volker Diels-Grabsch > --- > arp.c | 34 ++++++++++++++++++++++++++++++++++ > arp.h | 1 + > tap.c | 15 +++++++++++++-- > 3 files changed, 48 insertions(+), 2 deletions(-) > > diff --git a/arp.c b/arp.c > index 44677ad..561581a 100644 > --- a/arp.c > +++ b/arp.c > @@ -112,3 +112,37 @@ int arp(const struct ctx *c, struct iov_tail *data) > > return 1; > } > + > +/** > + * send_initial_arp_req() - Send initial ARP request to retrieve guest MAC address > + * @c: Execution context > + */ > +void send_initial_arp_req(const struct ctx *c) > +{ > + struct { > + struct ethhdr eh; > + struct arphdr ah; > + struct arpmsg am; > + } __attribute__((__packed__)) req; > + > + /* Ethernet header */ > + req.eh.h_proto = htons(ETH_P_ARP); > + memcpy(req.eh.h_dest, c->guest_mac, sizeof(req.eh.h_dest)); > + memcpy(req.eh.h_source, c->our_tap_mac, sizeof(req.eh.h_source)); > + > + /* ARP header */ > + req.ah.ar_op = htons(ARPOP_REQUEST); > + req.ah.ar_hrd = htons(ARPHRD_ETHER); > + req.ah.ar_pro = htons(ETH_P_IP); > + req.ah.ar_hln = ETH_ALEN; > + req.ah.ar_pln = 4; > + > + /* ARP message */ > + memcpy(req.am.sha, c->our_tap_mac, sizeof(req.am.sha)); > + memcpy(req.am.sip, &c->ip4.our_tap_addr, sizeof(req.am.sip)); > + memcpy(req.am.tha, c->guest_mac, sizeof(req.am.tha)); > + memcpy(req.am.tip, &c->ip4.addr, sizeof(req.am.tip)); > + > + info("sending initial ARP request to retrieve guest MAC address after reconnect"); > + tap_send_single(c, &req, sizeof(req)); > +} > diff --git a/arp.h b/arp.h > index 86bcbf8..5490144 100644 > --- a/arp.h > +++ b/arp.h > @@ -21,5 +21,6 @@ struct arpmsg { > } __attribute__((__packed__)); > > int arp(const struct ctx *c, struct iov_tail *data); > +void send_initial_arp_req(const struct ctx *c); > > #endif /* ARP_H */ > diff --git a/tap.c b/tap.c > index 7ba6399..47dedd5 100644 > --- a/tap.c > +++ b/tap.c > @@ -1355,6 +1355,16 @@ static void tap_start_connection(const struct ctx *c) > ev.events = EPOLLIN | EPOLLRDHUP; > ev.data.u64 = ref.u64; > epoll_ctl(c->epollfd, EPOLL_CTL_ADD, c->fd_tap, &ev); > + > + switch (c->mode) { > + case MODE_PASST: > + send_initial_arp_req(c); > + break; > + case MODE_PASTA: > + break; > + case MODE_VU: > + break; > + } > } > > /** > @@ -1504,8 +1514,9 @@ void tap_backend_init(struct ctx *c) > tap_sock_unix_init(c); > > /* In passt mode, we don't know the guest's MAC address until it > - * sends us packets. Use the broadcast address so that our > - * first packets will reach it. > + * sends us packets (e.g. responds to our initial ARP request). > + * Until then, use the broadcast address so that our first > + * packets will reach it. > */ > memset(&c->guest_mac, 0xff, sizeof(c->guest_mac)); > break; > -- > 2.47.2 > -- .---<<<((()))>>>---. | [[||]] | '---<<<((()))>>>---'