LwIP and multiple network interfaces

E Shattow e at freeshell.de
Sat Jan 4 04:05:18 CET 2025


On 1/3/25 09:58, E Shattow wrote:
> 
> 
> On 1/3/25 02:03, Jerome Forissier wrote:
>>
>>
>> On 1/3/25 02:52, E Shattow wrote:
>>>
>>>
>>> On 1/2/25 17:40, Tom Rini wrote:
>>>> On Thu, Jan 02, 2025 at 05:34:57PM -0800, E Shattow wrote:
>>>>
>>>>> Tom sorry about sending this reply twice, struggle here is with 
>>>>> Thunderbird
>>>>> mail UI sometimes hiding "Reply All" and it missed the mail list 
>>>>> first time
>>>>> around.
>>>>
>>>> No problem.
>>>>
>>>>> On 1/2/25 14:47, Tom Rini wrote:
>>>>>> On Thu, Jan 02, 2025 at 02:26:06PM -0800, E Shattow wrote:
>>>>>>> Problem: 'dhcp' must be ran twice when the network cable is 
>>>>>>> plugged into a
>>>>>>> port other than the first network port.
>>>>>>>
>>>>>>> Network cable plugged into bottom (first) Ethernet port:
>>>>>>> 1. Power on
>>>>>>> 2. StarFive # dhcp
>>>>>>>
>>>>>>> ethernet at 16030000 Waiting for PHY auto negotiation to 
>>>>>>> complete....... done
>>>>>>> DHCP client bound to address 192.168.2.51 (3678 ms)
>>>>>>>
>>>>>>>
>>>>>>> Network cable plugged into top (second) Ethernet port:
>>>>>>> 1. Power on
>>>>>>> 2. StarFive # dhcp
>>>>>>> ethernet at 16030000 Waiting for PHY auto negotiation to 
>>>>>>> complete.........
>>>>>>> TIMEOUT !
>>>>>>> phy_startup() failed: -110
>>>>>>> FAILED: -110
>>>>>>> ethernet at 16040000 Waiting for PHY auto negotiation to 
>>>>>>> complete...... done
>>>>>>> ethernet at 16030000 Waiting for PHY auto negotiation to 
>>>>>>> complete.........
>>>>>>> TIMEOUT !
>>>>>>> phy_startup() failed: -110
>>>>>>> FAILED: -110
>>>>>>> Could not start ethernet at 16030000
>>>>>>> 3. StarFive # dhcp
>>>>>>> DHCP client bound to address 192.168.2.77 (31 ms)
>>>>>>
>>>>>> What happens when you set ethact to 1 first?
>>>>>>
>>>>>
>>>>>
>>>>> '1' literal does not seem to do something so I guess it is meant 
>>>>> the id of
>>>>> the first ethernet interface:
>>>>
>>>> Yes, I misspoke sorry.
>>>>
>>>>>   From power-on:
>>>>>
>>>>> ...
>>>>> starfive_7110_pcie pcie at 2b000000: Starfive PCIe bus probed.
>>>>> starfive_7110_pcie pcie at 2c000000: Starfive PCIe bus probed.
>>>>> In:    serial at 10000000
>>>>> Out:   serial at 10000000
>>>>> Err:   serial at 10000000
>>>>> Net:   eth0: ethernet at 16030000, eth1: ethernet at 16040000
>>>>> starting USB...
>>>>> No USB controllers found
>>>>> Working FDT set to ff700a10
>>>>> StarFive # env print ethact
>>>>> ## Error: "ethact" not defined
>>>>> StarFive # env set ethact 1
>>>>> StarFive # dhcp
>>>>> ethernet at 16030000 Waiting for PHY auto negotiation to 
>>>>> complete.........
>>>>> TIMEOUT !
>>>>> phy_startup() failed: -110
>>>>> FAILED: -110
>>>>> ethernet at 16040000 Waiting for PHY auto negotiation to 
>>>>> complete...... done
>>>>> EQOS_DMA_MODE_SWR stuck
>>>>> FAILED: -110
>>>>> Could not start ethernet at 16030000
>>>>>
>>>>> Again, from power-on:
>>>>>
>>>>> starfive_7110_pcie pcie at 2b000000: Starfive PCIe bus probed.
>>>>> starfive_7110_pcie pcie at 2c000000: Starfive PCIe bus probed.
>>>>> In:    serial at 10000000
>>>>> Out:   serial at 10000000
>>>>> Err:   serial at 10000000
>>>>> Net:   eth0: ethernet at 16030000, eth1: ethernet at 16040000
>>>>> starting USB...
>>>>> No USB controllers found
>>>>> Working FDT set to ff700a10
>>>>> StarFive # env print ethact
>>>>> ## Error: "ethact" not defined
>>>>> StarFive # env set ethact ethernet at 16040000
>>>>> StarFive # dhcp
>>>>> ethernet at 16040000 Waiting for PHY auto negotiation to 
>>>>> complete...... done
>>>>> DHCP client bound to address 192.168.2.77 (149 ms)
>>>>
>>>> So then yes, the second interface works when ethact is set to use that
>>>> directly. This is the same behavior as the legacy stack I believe.
>>>>
>>>
>>> Legacy stack does actually rotate and complete successfully when 
>>> ethact environment variable does not exist and (eventually) configure 
>>> the second interface though. Here with LwIP the procedure fails.
>>>
>>> Notice that here it starts with ethernet at 16030000, then rotates to 
>>> ethernet at 16040000 unsuccessfully, and back again to ethernet at 16030000 
>>> before (again) failing and giving up. There is a network cable 
>>> plugged into 'ethernet at 16040000' port and if we try the command again 
>>> the environment variable ethact retained 'ethact=ethernet at 16040000' 
>>> from the failed procedure so you're right it works as it should... 
>>> except that it totally failed to do what was expected the first time.
>>
>> That's unexpected indeed.
>>
>>> Is this exposing a problem with this board network driver and 
>>> behavior or is it something with LwIP ?
>> Hard to tell at this point. One thing I know for sure is that lwIP 
>> expects
>> eth_set_current() (called from do_dhcp()) to actually pick a valid
>> interface if there is one. So it should definitely select 
>> ethernet at 16040000
>> in your scenario. Adding debug prints to eth_set_current(),
>> eth_current_changed() etc. should help.
>>
>> Thanks,
> 
> StarFive # dhcp
> !!! eth_set_current(): entered function
> !!! eth_set_current(): conditional 1
> !!! eth_set_current(): conditional 2
> !!! eth_set_current(): conditional 5
> !!! eth_current_changed(): entered function
> !!! eth_current_changed(): conditional 2
> !!! eth_current_changed(): conditional 3
> !!! eth_current_changed(): leaving function
> !!! eth_set_current(): leaving function
> ethernet at 16030000 Waiting for PHY auto negotiation to complete......... 
> TIMEOUT !
> phy_startup() failed: -110
> FAILED: -110
> !!! eth_current_changed(): entered function
> !!! eth_current_changed(): conditional 2
> !!! eth_current_changed(): conditional 3
> !!! eth_current_changed(): leaving function
> ethernet at 16040000 Waiting for PHY auto negotiation to complete...... done
> ethernet at 16030000 Waiting for PHY auto negotiation to complete......... 
> TIMEOUT !
> phy_startup() failed: -110
> FAILED: -110
> Could not start ethernet at 16030000
> StarFive #
> 
> For reference the modified functions:
> 
> void eth_current_changed(void)
> {
>          char *act = env_get("ethact");
>          char *ethrotate;
> 
> printf("!!! eth_current_changed(): entered function\n");
>          /*
>           * The call to eth_get_dev() below has a side effect of rotating
>           * ethernet device if uc_priv->current == NULL. This is not what
>           * we want when 'ethrotate' variable is 'no'.
>           */
>          ethrotate = env_get("ethrotate");
>          if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
>          {
> printf("!!! eth_current_changed(): conditional 1\n");
>                  return;
>          }
> 
>          /* update current ethernet name */
>          if (eth_get_dev()) {
> printf("!!! eth_current_changed(): conditional 2\n");
>                  if (act == NULL || strcmp(act, eth_get_name()) != 0)
>                  {
> printf("!!! eth_current_changed(): conditional 3\n");
>                          env_set("ethact", eth_get_name());
>                  }
>          }
>          /*
>           * remove the variable completely if there is no active
>           * interface
>           */
>          else if (act != NULL)
>          {
> printf("!!! eth_current_changed(): conditional 4\n");
>                  env_set("ethact", NULL);
>          }
> printf("!!! eth_current_changed(): leaving function\n");
> }
> 
> void eth_set_current(void)
> {
>          static char *act;
>          static int  env_changed_id;
>          int     env_id;
> 
> printf("!!! eth_set_current(): entered function\n");
>          env_id = env_get_id();
>          if ((act == NULL) || (env_changed_id != env_id)) {
> printf("!!! eth_set_current(): conditional 1\n");
>                  act = env_get("ethact");
>                  env_changed_id = env_id;
>          }
> 
>          if (act == NULL) {
> printf("!!! eth_set_current(): conditional 2\n");
>                  char *ethprime = env_get("ethprime");
>                  void *dev = NULL;
> 
>                  if (ethprime)
>                  {
> printf("!!! eth_set_current(): conditional 3\n");
>                          dev = eth_get_dev_by_name(ethprime);
>                  }
>                  if (dev)
>                  {
> printf("!!! eth_set_current(): conditional 4\n");
>                          eth_set_dev(dev);
>                  }
>                  else
>                  {
> printf("!!! eth_set_current(): conditional 5\n");
>                          eth_set_dev(NULL);
>                  }
>          } else {
> printf("!!! eth_set_current(): conditional 6\n");
>                  eth_set_dev(eth_get_dev_by_name(act));
>          }
> 
>          eth_current_changed();
> printf("!!! eth_set_current(): leaving function\n");
> }
> 
> Hopefully this is enough to make sense of it? Let me know, thanks!
> 
> -E

Postscript I've narrowed it down a bit to 
net/lwip/net-lwip.c:new_netif() where returning from eth_init() the 
eth_get_dev() is the second interface (with network cable plugged in) 
but variable reference udev is still the first interface (with no 
network cable) when the call to lwip_init() is made. So lwip_init() 
tries and fails on the first interface even though we already know from 
eth_init() which interface is valid and ready.

So that is what is happening but I don't know what you would want to do 
to fix this?

-E


More information about the U-Boot mailing list