From 7f51898c1b170e0036e6931a17ada46e2b4fd52e Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 31 Jul 2012 06:06:41 +0000 Subject: net: Make netconsole src and dest ports configurable It is desirable to use different port numbers for sending and receiving packets with netconsole in the case where you have more than one device on the local subnet with netconsole enabled for broadcast. When they use the same port for both, any output from one will look like input to the other. This is typlically not desirable. This patch allows the input and output ports to be specified separately in the environment. Signed-off-by: Joe Hershberger Cc: Mike Frysinger Acked-by: Mike Frysinger --- drivers/net/netconsole.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'drivers/net/netconsole.c') diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 14243b8a92..86f5301141 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -36,7 +36,8 @@ static int output_recursion; static int net_timeout; static uchar nc_ether[6]; /* server enet address */ static IPaddr_t nc_ip; /* server ip */ -static short nc_port; /* source/target port */ +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; @@ -71,7 +72,7 @@ void NcStart(void) net_set_arp_handler(nc_wait_arp_handler); pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE; memcpy(pkt, output_packet, output_packet_len); - NetSendUDPPacket(nc_ether, nc_ip, nc_port, nc_port, + NetSendUDPPacket(nc_ether, nc_ip, nc_out_port, nc_in_port, output_packet_len); } } @@ -80,7 +81,7 @@ int nc_input_packet(uchar *pkt, unsigned dest, unsigned src, unsigned len) { int end, chunk; - if (dest != nc_port || !len) + if (dest != nc_in_port || !len) return 0; /* not for us */ debug_cond(DEBUG_DEV_PKT, "input: \"%*.*s\"\n", len, len, pkt); @@ -139,7 +140,7 @@ static void nc_send_packet(const char *buf, int len) memcpy(pkt, buf, len); ether = nc_ether; ip = nc_ip; - NetSendUDPPacket(ether, ip, nc_port, nc_port, len); + NetSendUDPPacket(ether, ip, nc_out_port, nc_in_port, len); if (inited) eth_halt(); @@ -148,20 +149,30 @@ static void nc_send_packet(const char *buf, int len) static int nc_start(void) { int netmask, our_ip; + char *p; - nc_port = 6666; /* default port */ + nc_out_port = 6666; /* default port */ + nc_in_port = nc_out_port; if (getenv("ncip")) { - char *p; nc_ip = getenv_IPaddr("ncip"); if (!nc_ip) return -1; /* ncip is 0.0.0.0 */ p = strchr(getenv("ncip"), ':'); - if (p != NULL) - nc_port = simple_strtoul(p + 1, NULL, 10); + if (p != NULL) { + nc_out_port = simple_strtoul(p + 1, NULL, 10); + nc_in_port = nc_out_port; + } } else - nc_ip = ~0; /* ncip is not set */ + nc_ip = ~0; /* ncip is not set, so broadcast */ + + p = getenv("ncoutport"); + if (p != NULL) + nc_out_port = simple_strtoul(p, NULL, 10); + p = getenv("ncinport"); + if (p != NULL) + nc_in_port = simple_strtoul(p, NULL, 10); our_ip = getenv_IPaddr("ipaddr"); netmask = getenv_IPaddr("netmask"); -- cgit v1.2.3 From 2c8fe5120f8da013cbd789be2f10cce880972836 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 31 Jul 2012 06:09:17 +0000 Subject: net: Make the netconsole buffer size configurable Allow a board to configure a larger buffer for netconsole, but leave the default. Signed-off-by: Joe Hershberger Cc: Mike Frysinger Acked-by: Mike Frysinger --- doc/README.NetConsole | 2 ++ drivers/net/netconsole.c | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/net/netconsole.c') diff --git a/doc/README.NetConsole b/doc/README.NetConsole index 070e86a6f7..af7fc6043a 100644 --- a/doc/README.NetConsole +++ b/doc/README.NetConsole @@ -6,6 +6,8 @@ serial and network input/output devices by adjusting the 'stdin' and set either of these variables to "nc". Input and output can be switched independently. +CONFIG_NETCONSOLE_BUFFER_SIZE - Override the default buffer size + We use an environment variable 'ncip' to set the IP address and the port of the destination. The format is :. If is omitted, the value of 6666 is used. If the env var doesn't exist, the diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 86f5301141..8fcf31c4e9 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -28,7 +28,11 @@ DECLARE_GLOBAL_DATA_PTR; -static char input_buffer[512]; +#ifndef CONFIG_NETCONSOLE_BUFFER_SIZE +#define CONFIG_NETCONSOLE_BUFFER_SIZE 512 +#endif + +static char input_buffer[CONFIG_NETCONSOLE_BUFFER_SIZE]; static int input_size; /* char count in input buffer */ static int input_offset; /* offset to valid chars in input buffer */ static int input_recursion; @@ -214,7 +218,7 @@ static void nc_puts(const char *s) len = strlen(s); while (len) { - int send_len = min(len, 512); + int send_len = min(len, sizeof(input_buffer)); nc_send_packet(s, send_len); len -= send_len; s += send_len; -- cgit v1.2.3 From f8be7d659c45720edb91503d2a480fc198e7ee9d Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Fri, 3 Aug 2012 10:59:08 +0000 Subject: net: Improve the speed of netconsole Previously u-boot would initialize the network interface for every network operation and then shut it down again. This makes sense for most operations where the network in not known to be needed soon after the operation is complete. In the case of netconsole, it will use the network for every interaction with the shell or every printf. This means that the network is being reinitialized very often. On many devices, this intialization is very slow. This patch checks for consecutive netconsole actions and leaves the ethernet hardware initialized between them. It will still behave the same old way for all other network operations and any time another network operation happens between netconsole operations. Signed-off-by: Joe Hershberger Cc: Stefano Babic Acked-by: Stefano Babic --- common/cmd_bootm.c | 17 +++++++++++++++++ drivers/net/netconsole.c | 22 ++++++++++++++++++---- include/net.h | 42 +++++++++++++++++++++++++++++++++++++++++- net/eth.c | 8 ++------ net/net.c | 26 ++++++++++++++++++++------ 5 files changed, 98 insertions(+), 17 deletions(-) (limited to 'drivers/net/netconsole.c') diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index 45e726af8b..83fa5d7bd8 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -564,6 +564,13 @@ int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc, break; case BOOTM_STATE_OS_GO: disable_interrupts(); +#ifdef CONFIG_NETCONSOLE + /* + * Stop the ethernet stack if NetConsole could have + * left it up + */ + eth_halt(); +#endif arch_preboot_os(); boot_fn(BOOTM_STATE_OS_GO, argc, argv, &images); break; @@ -622,6 +629,11 @@ int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) */ iflag = disable_interrupts(); +#ifdef CONFIG_NETCONSOLE + /* Stop the ethernet stack if NetConsole could have left it up */ + eth_halt(); +#endif + #if defined(CONFIG_CMD_USB) /* * turn off USB to prevent the host controller from writing to the @@ -1599,6 +1611,11 @@ static int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) */ disable_interrupts(); +#ifdef CONFIG_NETCONSOLE + /* Stop the ethernet stack if NetConsole could have left it up */ + eth_halt(); +#endif + #if defined(CONFIG_CMD_USB) /* * turn off USB to prevent the host controller from writing to the diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 8fcf31c4e9..da82aa94ca 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -44,6 +44,11 @@ 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; +/* + * Start with a default last protocol. + * We are only interested in NETCONS or not. + */ +enum proto_t net_loop_last_protocol = BOOTP; static void nc_wait_arp_handler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, @@ -136,8 +141,13 @@ static void nc_send_packet(const char *buf, int len) } if (eth->state != ETH_STATE_ACTIVE) { - if (eth_init(gd->bd) < 0) - return; + if (eth_is_on_demand_init()) { + if (eth_init(gd->bd) < 0) + return; + eth_set_last_protocol(NETCONS); + } else + eth_init_state_only(gd->bd); + inited = 1; } pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE; @@ -146,8 +156,12 @@ static void nc_send_packet(const char *buf, int len) ip = nc_ip; NetSendUDPPacket(ether, ip, nc_out_port, nc_in_port, len); - if (inited) - eth_halt(); + if (inited) { + if (eth_is_on_demand_init()) + eth_halt(); + else + eth_halt_state_only(); + } } static int nc_start(void) diff --git a/include/net.h b/include/net.h index 6d2d6cd849..e193b7b60b 100644 --- a/include/net.h +++ b/include/net.h @@ -102,7 +102,14 @@ extern int eth_register(struct eth_device* dev);/* Register network device */ extern int eth_unregister(struct eth_device *dev);/* Remove network device */ extern void eth_try_another(int first_restart); /* Change the device */ extern void eth_set_current(void); /* set nterface to ethcur var */ -extern struct eth_device *eth_get_dev(void); /* get the current device MAC */ +/* get the current device MAC */ +static inline __attribute__((always_inline)) +struct eth_device *eth_get_dev(void) +{ + extern struct eth_device *eth_current; + + return eth_current; +} extern struct eth_device *eth_get_dev_by_name(const char *devname); extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */ extern int eth_get_dev_index(void); /* get the device index */ @@ -151,6 +158,19 @@ extern int eth_rx(void); /* Check for received packets */ extern void eth_halt(void); /* stop SCC */ extern char *eth_get_name(void); /* get name of current device */ +/* Set active state */ +static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis) +{ + eth_get_dev()->state = ETH_STATE_ACTIVE; + + return 0; +} +/* Set passive state */ +static inline __attribute__((always_inline)) void eth_halt_state_only(void) +{ + eth_get_dev()->state = ETH_STATE_PASSIVE; +} + /* * Set the hardware address for an ethernet interface based on 'eth%daddr' * environment variable (or just 'ethaddr' if eth_number is 0). @@ -532,6 +552,26 @@ void NcStart(void); int nc_input_packet(uchar *pkt, unsigned dest, unsigned src, unsigned len); #endif +static inline __attribute__((always_inline)) int eth_is_on_demand_init(void) +{ +#ifdef CONFIG_NETCONSOLE + extern enum proto_t net_loop_last_protocol; + + return net_loop_last_protocol != NETCONS; +#else + return 1; +#endif +} + +static inline void eth_set_last_protocol(int protocol) +{ +#ifdef CONFIG_NETCONSOLE + extern enum proto_t net_loop_last_protocol; + + net_loop_last_protocol = protocol; +#endif +} + /* * Check if autoload is enabled. If so, use either NFS or TFTP to download * the boot file. diff --git a/net/eth.c b/net/eth.c index bb4d95be8e..49458c8db9 100644 --- a/net/eth.c +++ b/net/eth.c @@ -121,12 +121,8 @@ static struct { static unsigned int eth_rcv_current, eth_rcv_last; #endif -static struct eth_device *eth_devices, *eth_current; - -struct eth_device *eth_get_dev(void) -{ - return eth_current; -} +static struct eth_device *eth_devices; +struct eth_device *eth_current; struct eth_device *eth_get_dev_by_name(const char *devname) { diff --git a/net/net.c b/net/net.c index f4404342f7..a89946ebe0 100644 --- a/net/net.c +++ b/net/net.c @@ -315,12 +315,15 @@ int NetLoop(enum proto_t protocol) bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start"); net_init(); - eth_halt(); - eth_set_current(); - if (eth_init(bd) < 0) { + if (eth_is_on_demand_init() || protocol != NETCONS) { eth_halt(); - return -1; - } + eth_set_current(); + if (eth_init(bd) < 0) { + eth_halt(); + return -1; + } + } else + eth_init_state_only(bd); restart: net_set_state(NETLOOP_CONTINUE); @@ -460,6 +463,9 @@ restart: net_cleanup_loop(); eth_halt(); + /* Invalidate the last protocol */ + eth_set_last_protocol(BOOTP); + puts("\nAbort\n"); /* include a debug print as well incase the debug messages are directed to stderr */ @@ -517,13 +523,21 @@ restart: sprintf(buf, "%lX", (unsigned long)load_addr); setenv("fileaddr", buf); } - eth_halt(); + if (protocol != NETCONS) + eth_halt(); + else + eth_halt_state_only(); + + eth_set_last_protocol(protocol); + ret = NetBootFileXferSize; debug_cond(DEBUG_INT_STATE, "--- NetLoop Success!\n"); goto done; case NETLOOP_FAIL: net_cleanup_loop(); + /* Invalidate the last protocol */ + eth_set_last_protocol(BOOTP); debug_cond(DEBUG_INT_STATE, "--- NetLoop Fail!\n"); goto done; -- cgit v1.2.3 From e827fec2b24d4412eabed3cf0080a08a0a7d148c Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 18 Sep 2012 10:01:31 +0000 Subject: net: Allow netconsole settings to change after nc_start Refresh the netconsole settings from the env before each packet instead of only on netconsole init. Signed-off-by: Joe Hershberger --- drivers/net/netconsole.c | 96 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 65 insertions(+), 31 deletions(-) (limited to 'drivers/net/netconsole.c') diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index da82aa94ca..63ce73c818 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -69,8 +69,69 @@ static void nc_timeout(void) net_set_state(NETLOOP_SUCCESS); } +static int is_broadcast(IPaddr_t ip) +{ + static IPaddr_t netmask; + static IPaddr_t our_ip; + static int env_changed_id; + int env_id = get_env_id(); + + /* update only when the environment has changed */ + if (env_changed_id != env_id) { + netmask = getenv_IPaddr("netmask"); + our_ip = getenv_IPaddr("ipaddr"); + + env_changed_id = env_id; + } + + return (ip == ~0 || /* 255.255.255.255 */ + ((netmask & our_ip) == (netmask & ip) && /* on the same net */ + (netmask | ip) == ~0)); /* broadcast to our net */ +} + +static int refresh_settings_from_env(void) +{ + const char *p; + static int env_changed_id; + int env_id = get_env_id(); + + /* update only when the environment has changed */ + if (env_changed_id != env_id) { + if (getenv("ncip")) { + nc_ip = getenv_IPaddr("ncip"); + if (!nc_ip) + return -1; /* ncip is 0.0.0.0 */ + p = strchr(getenv("ncip"), ':'); + if (p != NULL) { + nc_out_port = simple_strtoul(p + 1, NULL, 10); + nc_in_port = nc_out_port; + } + } else + nc_ip = ~0; /* ncip is not set, so broadcast */ + + p = getenv("ncoutport"); + if (p != NULL) + nc_out_port = simple_strtoul(p, NULL, 10); + p = getenv("ncinport"); + if (p != NULL) + nc_in_port = simple_strtoul(p, NULL, 10); + + if (is_broadcast(nc_ip)) + /* broadcast MAC address */ + memset(nc_ether, 0xff, sizeof(nc_ether)); + else + /* force arp request */ + memset(nc_ether, 0, sizeof(nc_ether)); + } + return 0; +} + +/** + * Called from NetLoop in net/net.c before each packet + */ void NcStart(void) { + refresh_settings_from_env(); if (!output_packet_len || memcmp(nc_ether, NetEtherNullAddr, 6)) { /* going to check for input packet */ net_set_udp_handler(nc_handler); @@ -166,41 +227,14 @@ static void nc_send_packet(const char *buf, int len) static int nc_start(void) { - int netmask, our_ip; - char *p; + int retval; nc_out_port = 6666; /* default port */ nc_in_port = nc_out_port; - if (getenv("ncip")) { - - nc_ip = getenv_IPaddr("ncip"); - if (!nc_ip) - return -1; /* ncip is 0.0.0.0 */ - p = strchr(getenv("ncip"), ':'); - if (p != NULL) { - nc_out_port = simple_strtoul(p + 1, NULL, 10); - nc_in_port = nc_out_port; - } - } else - nc_ip = ~0; /* ncip is not set, so broadcast */ - - p = getenv("ncoutport"); - if (p != NULL) - nc_out_port = simple_strtoul(p, NULL, 10); - p = getenv("ncinport"); - if (p != NULL) - nc_in_port = simple_strtoul(p, NULL, 10); - - our_ip = getenv_IPaddr("ipaddr"); - netmask = getenv_IPaddr("netmask"); - - if (nc_ip == ~0 || /* 255.255.255.255 */ - ((netmask & our_ip) == (netmask & nc_ip) && /* on the same net */ - (netmask | nc_ip) == ~0)) /* broadcast to our net */ - memset(nc_ether, 0xff, sizeof(nc_ether)); - else - memset(nc_ether, 0, sizeof(nc_ether)); /* force arp request */ + retval = refresh_settings_from_env(); + if (retval != 0) + return retval; /* * Initialize the static IP settings and buffer pointers -- cgit v1.2.3 From 8a0eccb1056b313b45ab62e3aac400f339aa71b4 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 18 Sep 2012 10:01:32 +0000 Subject: net: Filter incoming netconsole packets by IP Check the incoming packets' source IP address... if ncip isn't set to a broadcast address, only listen to the client at ncip. Signed-off-by: Joe Hershberger --- drivers/net/netconsole.c | 8 ++++++-- include/net.h | 3 ++- net/net.c | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/net/netconsole.c') diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 63ce73c818..dd7032af56 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -147,13 +147,17 @@ void NcStart(void) } } -int nc_input_packet(uchar *pkt, unsigned dest, unsigned src, unsigned len) +int nc_input_packet(uchar *pkt, IPaddr_t src_ip, unsigned dest_port, + unsigned src_port, unsigned len) { int end, chunk; - if (dest != nc_in_port || !len) + if (dest_port != nc_in_port || !len) return 0; /* not for us */ + if (src_ip != nc_ip && !is_broadcast(nc_ip)) + return 0; /* not from our client */ + debug_cond(DEBUG_DEV_PKT, "input: \"%*.*s\"\n", len, len, pkt); if (input_size == sizeof(input_buffer)) diff --git a/include/net.h b/include/net.h index e193b7b60b..35393366d3 100644 --- a/include/net.h +++ b/include/net.h @@ -549,7 +549,8 @@ extern void NetReceive(uchar *, int); #ifdef CONFIG_NETCONSOLE void NcStart(void); -int nc_input_packet(uchar *pkt, unsigned dest, unsigned src, unsigned len); +int nc_input_packet(uchar *pkt, IPaddr_t src_ip, unsigned dest_port, + unsigned src_port, unsigned len); #endif static inline __attribute__((always_inline)) int eth_is_on_demand_init(void) diff --git a/net/net.c b/net/net.c index a89946ebe0..809fb14c79 100644 --- a/net/net.c +++ b/net/net.c @@ -1161,6 +1161,7 @@ NetReceive(uchar *inpkt, int len) #ifdef CONFIG_NETCONSOLE nc_input_packet((uchar *)ip + IP_UDP_HDR_SIZE, + ntohl(ip->ip_src), ntohs(ip->udp_dst), ntohs(ip->udp_src), ntohs(ip->udp_len) - UDP_HDR_SIZE); -- cgit v1.2.3