diff mbox series

[RFC,2/2] netconsole and networking co-existence

Message ID 2f87c420bc033f82b747c2790bcbd2982efb91de.1620039770.git.ian.ray@ge.com
State RFC
Delegated to: Ramon Fried
Headers show
Series netconsole and networking co-existence | expand

Commit Message

Ian Ray May 3, 2021, 11:55 a.m. UTC
The network stack does not appear to be designed to handle simultaneous
netconsole and network operations (such as ping, nfs, and tftp) because
of re-use of the netconsole output buffer.

* Add new net_send_udp_packet2, net_send_ip_packet2 APIs.

* Teach netconsole to use a private TX buffer.  This is needed in order
  to avoid overwriting the ICMP ECHO REQUEST if a ping is started while
  netconsole is active.

Signed-off-by: Ian Ray <ian.ray@ge.com>
---
 drivers/net/netconsole.c | 19 +++++++++++--------
 include/net.h            |  5 +++++
 net/arp.c                |  7 +++++--
 net/arp.h                |  1 +
 net/net.c                | 36 ++++++++++++++++++++++++++++--------
 net/ping.c               |  3 ++-
 6 files changed, 52 insertions(+), 19 deletions(-)
diff mbox series

Patch

diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index b6d2e22..ef65d75 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -27,6 +27,8 @@  static short nc_out_port; /* target output port */
 static short nc_in_port; /* source input port */
 static const char *output_packet; /* used by first send udp */
 static int output_packet_len;
+static uchar nc_pkt_buf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];
+static uchar *nc_tx_packet;
 
 static void nc_wait_arp_handler(uchar *pkt, unsigned dest,
 				 struct in_addr sip, unsigned src,
@@ -120,10 +122,10 @@  void nc_start(void)
 		/* send arp request */
 		uchar *pkt;
 		net_set_arp_handler(nc_wait_arp_handler);
-		pkt = (uchar *)net_tx_packet + net_eth_hdr_size() +
+		pkt = (uchar *)nc_tx_packet + net_eth_hdr_size() +
 			IP_UDP_HDR_SIZE;
 		memcpy(pkt, output_packet, output_packet_len);
-		net_send_udp_packet(nc_ether, nc_ip, nc_out_port, nc_in_port,
+		net_send_udp_packet2(nc_tx_packet, nc_ether, nc_ip, nc_out_port, nc_in_port,
 				    output_packet_len);
 	}
 }
@@ -173,8 +175,6 @@  static void nc_send_packet(const char *buf, int len)
 	struct eth_device *eth;
 #endif
 	uchar *pkt;
-	uchar *ether;
-	struct in_addr ip;
 
 	debug_cond(DEBUG_DEV_PKT, "output: \"%*.*s\"\n", len, len, buf);
 
@@ -198,11 +198,9 @@  static void nc_send_packet(const char *buf, int len)
 		return;
 	}
 
-	pkt = (uchar *)net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE;
+	pkt = (uchar *)nc_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE;
 	memcpy(pkt, buf, len);
-	ether = nc_ether;
-	ip = nc_ip;
-	net_send_udp_packet(ether, ip, nc_out_port, nc_in_port, len);
+	net_send_udp_packet2(nc_tx_packet, nc_ether, nc_ip, nc_out_port, nc_in_port, len);
 
 	net_down();
 }
@@ -218,6 +216,11 @@  static int nc_stdio_start(struct stdio_dev *dev)
 	if (retval != 0)
 		return retval;
 
+	if (nc_tx_packet == NULL) {
+		nc_tx_packet = &nc_pkt_buf[0] + (PKTALIGN - 1);
+		nc_tx_packet -= (ulong)nc_tx_packet % PKTALIGN;
+	}
+
 	/*
 	 * Initialize the static IP settings and buffer pointers
 	 * incase we call net_send_udp_packet before net_loop
diff --git a/include/net.h b/include/net.h
index cc6be60..74f7ce1 100644
--- a/include/net.h
+++ b/include/net.h
@@ -694,9 +694,14 @@  static inline void net_send_packet(uchar *pkt, int len)
  * @param sport Source UDP port
  * @param payload_len Length of data after the UDP header
  */
+int net_send_ip_packet2(uchar *pkt, uchar *ether, struct in_addr dest, int dport, int sport,
+		       int payload_len, int proto, u8 action, u32 tcp_seq_num,
+		       u32 tcp_ack_num);
 int net_send_ip_packet(uchar *ether, struct in_addr dest, int dport, int sport,
 		       int payload_len, int proto, u8 action, u32 tcp_seq_num,
 		       u32 tcp_ack_num);
+int net_send_udp_packet2(uchar *pkt, uchar *ether, struct in_addr dest, int dport,
+			int sport, int payload_len);
 int net_send_udp_packet(uchar *ether, struct in_addr dest, int dport,
 			int sport, int payload_len);
 
diff --git a/net/arp.c b/net/arp.c
index 1d06ed2..f19958f 100644
--- a/net/arp.c
+++ b/net/arp.c
@@ -35,6 +35,7 @@  struct in_addr net_arp_wait_packet_ip;
 static struct in_addr net_arp_wait_reply_ip;
 /* MAC address of waiting packet's destination */
 uchar	       *arp_wait_packet_ethaddr;
+uchar	       *arp_wait_tx_packet;
 int		arp_wait_tx_packet_size;
 ulong		arp_wait_timer_start;
 int		arp_wait_try;
@@ -47,6 +48,7 @@  void arp_init(void)
 	arp_wait_packet_ethaddr = NULL;
 	net_arp_wait_packet_ip.s_addr = 0;
 	net_arp_wait_reply_ip.s_addr = 0;
+	arp_wait_tx_packet = NULL;
 	arp_wait_tx_packet_size = 0;
 	arp_tx_packet = &arp_tx_packet_buf[0] + (PKTALIGN - 1);
 	arp_tx_packet -= (ulong)arp_tx_packet % PKTALIGN;
@@ -222,12 +224,13 @@  void arp_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len)
 
 			/* set the mac address in the waiting packet's header
 			   and transmit it */
-			memcpy(((struct ethernet_hdr *)net_tx_packet)->et_dest,
+			memcpy(((struct ethernet_hdr *)arp_wait_tx_packet)->et_dest,
 			       &arp->ar_sha, ARP_HLEN);
-			net_send_packet(net_tx_packet, arp_wait_tx_packet_size);
+			net_send_packet(arp_wait_tx_packet, arp_wait_tx_packet_size);
 
 			/* no arp request pending now */
 			net_arp_wait_packet_ip.s_addr = 0;
+			arp_wait_tx_packet = NULL;
 			arp_wait_tx_packet_size = 0;
 			arp_wait_packet_ethaddr = NULL;
 		}
diff --git a/net/arp.h b/net/arp.h
index 25b3c00..8154ebc 100644
--- a/net/arp.h
+++ b/net/arp.h
@@ -17,6 +17,7 @@ 
 extern struct in_addr net_arp_wait_packet_ip;
 /* MAC address of waiting packet's destination */
 extern uchar *arp_wait_packet_ethaddr;
+extern uchar *arp_wait_tx_packet;
 extern int arp_wait_tx_packet_size;
 extern ulong arp_wait_timer_start;
 extern int arp_wait_try;
diff --git a/net/net.c b/net/net.c
index 45d4f19..b1dba80 100644
--- a/net/net.c
+++ b/net/net.c
@@ -855,17 +855,38 @@  int net_send_udp_packet(uchar *ether, struct in_addr dest, int dport, int sport,
 				  IPPROTO_UDP, 0, 0, 0);
 }
 
+int net_send_udp_packet2(uchar *pkt, uchar *ether, struct in_addr dest, int dport, int sport,
+		int payload_len)
+{
+	return net_send_ip_packet2(pkt, ether, dest, dport, sport, payload_len,
+				  IPPROTO_UDP, 0, 0, 0);
+}
+
+/// Sends net_tx_packet
+
 int net_send_ip_packet(uchar *ether, struct in_addr dest, int dport, int sport,
 		       int payload_len, int proto, u8 action, u32 tcp_seq_num,
 		       u32 tcp_ack_num)
 {
-	uchar *pkt;
+	return net_send_ip_packet2(net_tx_packet, ether, dest, dport, sport,
+				  payload_len,
+				  proto, action, tcp_seq_num, tcp_ack_num);
+}
+
+/// Global variables / state.
+///  - Uses const net_bcast_ethaddr if destination is broadcast address
+///  - net_set_ether() checks net_our_vlan
+///  - If ether is null, fills net_arp_wait_packet_ip and does ARP
+
+int net_send_ip_packet2(uchar *pkt, uchar *ether, struct in_addr dest, int dport, int sport,
+		       int payload_len, int proto, u8 action, u32 tcp_seq_num,
+		       u32 tcp_ack_num)
+{
 	int eth_hdr_size;
 	int pkt_hdr_size;
 
-	/* make sure the net_tx_packet is initialized (net_init() was called) */
-	assert(net_tx_packet != NULL);
-	if (net_tx_packet == NULL)
+	assert(pkt != NULL);
+	if (pkt == NULL)
 		return -1;
 
 	/* convert to new style broadcast */
@@ -876,8 +897,6 @@  int net_send_ip_packet(uchar *ether, struct in_addr dest, int dport, int sport,
 	if (dest.s_addr == 0xFFFFFFFF)
 		ether = (uchar *)net_bcast_ethaddr;
 
-	pkt = (uchar *)net_tx_packet;
-
 	eth_hdr_size = net_set_ether(pkt, ether, PROT_IP);
 
 	switch (proto) {
@@ -898,7 +917,8 @@  int net_send_ip_packet(uchar *ether, struct in_addr dest, int dport, int sport,
 		net_arp_wait_packet_ip = dest;
 		arp_wait_packet_ethaddr = ether;
 
-		/* size of the waiting packet */
+		/* waiting packet */
+		arp_wait_tx_packet = pkt;
 		arp_wait_tx_packet_size = pkt_hdr_size + payload_len;
 
 		/* and do the ARP request */
@@ -909,7 +929,7 @@  int net_send_ip_packet(uchar *ether, struct in_addr dest, int dport, int sport,
 	} else {
 		debug_cond(DEBUG_DEV_PKT, "sending UDP to %pI4/%pM\n",
 			   &dest, ether);
-		net_send_packet(net_tx_packet, pkt_hdr_size + payload_len);
+		net_send_packet(pkt, pkt_hdr_size + payload_len);
 		return 0;	/* transmitted */
 	}
 }
diff --git a/net/ping.c b/net/ping.c
index 2c92806..74c4726 100644
--- a/net/ping.c
+++ b/net/ping.c
@@ -52,7 +52,8 @@  static int ping_send(void)
 
 	set_icmp_header(pkt, net_ping_ip);
 
-	/* size of the waiting packet */
+	/* waiting packet */
+	arp_wait_tx_packet = net_tx_packet;
 	arp_wait_tx_packet_size = eth_hdr_size + IP_ICMP_HDR_SIZE;
 
 	/* and do the ARP request */