Skip to content

Commit

Permalink
Multiport linux support
Browse files Browse the repository at this point in the history
- See doc/multiple_ports.rst for information on how to configure
  and run a mulitport configuration
- Verified on Raspberry Pi with additional USB ethernet interfaces
  • Loading branch information
olbjo committed Jan 20, 2021
1 parent 3a5aa1c commit 6a56f03
Show file tree
Hide file tree
Showing 26 changed files with 707 additions and 325 deletions.
39 changes: 34 additions & 5 deletions doc/multiple_ports.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ Multiple ports
==============
This section describes how to configure the p-net stack, sample application
and system for multiple network interfaces or ports.
So far, multiple port has only been tested using the linux port.


Terminology
Expand Down Expand Up @@ -92,12 +93,40 @@ Run ``ifconfig`` to check that the bridge is up and its network interfaces are a
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

Configuration of p-net stack and sample application (TBD)
Configuration of p-net stack and sample application
---------------------------------------------------------
To run p-net and the sample application with multiple ports a couple
of things need to be done:

* Reconfigure setting ``PNET_MAX_PORT`` to the actual number of physical ports available in the system.
For this example ``PNET_MAX_PORT`` shall be set to 2.

* TBD - update this document when multiport support is implemented
Reconfigure setting ``PNET_MAX_PORT`` to the actual number of physical ports available in the system.
For this example ``PNET_MAX_PORT`` shall be set to 2.

Example of initial log when starting the demo application with a multi port configuration::

pi@pndevice-pi:~/profinet/build $ sudo ./pn_dev -v
** Starting Profinet demo application **
Number of slots: 5 (incl slot for DAP module)
P-net log level: 0 (DEBUG=0, FATAL=4)
App verbosity level: 1
Nbr of ports: 2
Network interfaces: br0,eth0,eth1
Button1 file:
Button2 file:
Station name: rt-labs-dev
Management port: br0 C2:38:F3:A6:0A:66
Physical port [1]: eth0 B8:27:EB:67:14:8A
Physical port [2]: eth1 58:EF:68:B5:11:0F
Current hostname: pndevice-pi
Current IP address: 192.168.0.50
Current Netmask: 255.255.255.0
Current Gateway: 192.168.0.1
Storage directory: /home/pi/profinet/build

Update gsdml file
-----------------
The sample app gsdml file contains a commented out block that defines
a second physical port. In the sample application gsdml file, search for "IDS_P2"
and enable commented out lines as described in the gsdml file.

Note that you will have to the reload gsdml file in all tools you are using and
also the Automated RT tester any time the file is changed.
10 changes: 10 additions & 0 deletions sample_app/GSDML-V2.4-rtlabs-IODevice-20201211.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@
<MAUTypeItem Value="16"/>
</MAUTypeList>
</PortSubmoduleItem>
<!-- Enable to support additional port. (PNET_MAX_PORT == 2) -->
<!-- Add additional PortSubmoduleItems to support additional ports -->
<!--
<PortSubmoduleItem ID="IDS_P2" SubmoduleIdentNumber="0x00008002" SubslotNumber="32770" TextId="IDT_NAME_PS2" MaxPortRxDelay="350" MaxPortTxDelay="160">
<MAUTypeList>
<MAUTypeItem Value="16"/>
</MAUTypeList>
</PortSubmoduleItem>
-->
</SystemDefinedSubmoduleList>
</DeviceAccessPointItem>
</DeviceAccessPointList>
Expand Down Expand Up @@ -195,6 +204,7 @@
<Text TextId="IDT_CUSTOM_LOGBOOK_1" Value="Custom Logbook entry"/>
<Text TextId="IDT_NAME_IS" Value="I"/>
<Text TextId="IDT_NAME_PS1" Value="P1"/>
<Text TextId="IDT_NAME_PS2" Value="P2"/>
<!--module name-->
<Text TextId="TOK_TextId_Module_I8" Value="8 bits I"/>
<Text TextId="TOK_TextId_Module_O8" Value="8 bits O"/>
Expand Down
218 changes: 201 additions & 17 deletions sample_app/sampleapp_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,7 @@ static void ip_to_string (pnal_ipaddr_t ip, char * outputstring)
(uint8_t) (ip & 0xFF));
}

/**
* Convert MAC address to string
* @param mac In: MAC address
* @param outputstring Out: Resulting string buffer. Should have size
* PNAL_ETH_ADDRSTR_SIZE.
*/
static void mac_to_string (pnal_ethaddr_t mac, char * outputstring)
void app_mac_to_string (pnal_ethaddr_t mac, char * outputstring)
{
snprintf (
outputstring,
Expand Down Expand Up @@ -189,24 +183,20 @@ static const char * ioxs_to_string (pnet_ioxs_values_t ioxs)
}

void app_print_network_details (
pnal_ethaddr_t * p_macbuffer,
pnal_ipaddr_t ip,
pnal_ipaddr_t netmask,
pnal_ipaddr_t gateway)
{
char ip_string[PNAL_INET_ADDRSTR_SIZE]; /* Terminated string */
char netmask_string[PNAL_INET_ADDRSTR_SIZE]; /* Terminated string */
char gateway_string[PNAL_INET_ADDRSTR_SIZE]; /* Terminated string */
char mac_string[PNAL_ETH_ADDRSTR_SIZE]; /* Terminated string */
char hostname_string[PNAL_HOSTNAME_MAX_SIZE]; /* Terminated string */

mac_to_string (*p_macbuffer, mac_string);
ip_to_string (ip, ip_string);
ip_to_string (netmask, netmask_string);
ip_to_string (gateway, gateway_string);
pnal_get_hostname (hostname_string);

printf ("MAC address: %s\n", mac_string);
printf ("Current hostname: %s\n", hostname_string);
printf ("Current IP address: %s\n", ip_string);
printf ("Current Netmask: %s\n", netmask_string);
Expand Down Expand Up @@ -1281,8 +1271,9 @@ void app_plug_dap (pnet_t * net, void * arg)

/************ Configuration of product ID, software version etc **************/

int app_adjust_stack_configuration (pnet_cfg_t * stack_config)
int app_pnet_cfg_init_default (pnet_cfg_t * stack_config)
{
uint16_t i;
memset (stack_config, 0, sizeof (pnet_cfg_t));
stack_config->tick_us = APP_TICK_INTERVAL_US;

Expand Down Expand Up @@ -1357,9 +1348,16 @@ int app_adjust_stack_configuration (pnet_cfg_t * stack_config)
stack_config->min_device_interval = 32; /* Corresponds to 1 ms */

/* LLDP settings */
strcpy (stack_config->if_cfg.ports[0].port_id, "port-001");
stack_config->if_cfg.ports[0].rtclass_2_status = 0;
stack_config->if_cfg.ports[0].rtclass_3_status = 0;
for (i = 0; i < PNET_MAX_PORT; i++)
{
snprintf (
stack_config->if_cfg.ports[i].port_id,
PNET_LLDP_PORT_ID_MAX_SIZE,
"port-%03d",
i + 1);
stack_config->if_cfg.ports[i].rtclass_2_status = 0;
stack_config->if_cfg.ports[i].rtclass_3_status = 0;
}

/* Network configuration */
stack_config->send_hello = true;
Expand All @@ -1373,6 +1371,190 @@ int app_adjust_stack_configuration (pnet_cfg_t * stack_config)
return 0;
}

/**
* Initialize a network interface configuration from a network
* interface name.
* This includes reading the Ethernet MAC address.
* If the network interface can not be found or the operation
* fails to read the mac address from the network interface,
* error is returned.
* @param if_name In: Network interface name
* @param p_netif Out: Network interface configuration
* @param verbosity In: Verbosity
* @return 0 on success
* -1 on error
*/
int app_port_cfg_init (
const char * netif_name,
pnet_netif_t * p_netif,
int verbosity)
{
pnal_ethaddr_t mac;
char mac_string[PNAL_ETH_ADDRSTR_SIZE]; /* Terminated string */

int ret = pnal_get_macaddress (netif_name, &mac);
if (ret != 0)
{
printf (
"Error: The given network interface does not exist: \"%s\"\n",
netif_name);
return -1;
}
else
{
if (verbosity > 0)
{
app_mac_to_string (mac, mac_string);
printf ("%s %s\n", netif_name, mac_string);
}
}

strncpy (p_netif->if_name, netif_name, PNET_INTERFACE_NAME_MAX_SIZE);
memcpy (p_netif->eth_addr.addr, mac.addr, sizeof (pnal_ethaddr_t));

return 0;
}

int app_get_netif_namelist (
const char * arg_str,
app_netif_namelist_t * p_if_list,
int max_port)
{
int ret = 0;
uint16_t i = 0;
uint16_t j = 0;
uint16_t if_index = 0;
uint16_t if_list_size = max_port + 1; /* NELEMENTS (p_if_list->netif) dynamic
for test. */
char c;

memset (p_if_list, 0, sizeof (*p_if_list));
c = arg_str[i++];
while (c != '\0' && if_index < if_list_size)
{
if (c != ',')
{
p_if_list->netif[if_index].name[j++] = c;
}
else
{
p_if_list->netif[if_index].name[j++] = '\0';
j = 0;
if_index++;
}
c = arg_str[i++];
}

if (max_port == 1)
{
if (if_index >= max_port)
{
printf ("Error: Only 1 network interface expected.\n");
ret = -1;
}

if (strlen (p_if_list->netif[0].name) == 0)
{
printf ("Error: Zero length network interface name.\n");
ret = -1;
}
p_if_list->netif[1] = p_if_list->netif[0];
}

if (max_port > 1)
{
if (if_index != max_port)
{
printf ("Error: %u network interfaces expected.\n", max_port + 1);
ret = -1;
}

for (i = 0; i <= max_port; i++)
{
if (strlen (p_if_list->netif[i].name) == 0)
{
printf ("Error: Zero length network interface name (%d).\n", i);
ret = -1;
}
}
}

return ret;
}

int app_pnet_cfg_init_netifs (
const char * netif_list_str,
pnet_cfg_t * p_cfg,
int verbosity)
{
int ret = 0;
int i = 0;
pnal_ipaddr_t ip;
pnal_ipaddr_t netmask;
pnal_ipaddr_t gateway;
app_netif_namelist_t if_list;

ret = app_get_netif_namelist (netif_list_str, &if_list, PNET_MAX_PORT);
if (ret != 0)
{
return ret;
}

if (verbosity > 0)
{
printf ("Management port: ");
}
if (
app_port_cfg_init (
if_list.netif[0].name,
&p_cfg->if_cfg.main_port,
verbosity) != 0)
{
return -1;
}

for (i = 1; i <= PNET_MAX_PORT; i++)
{
if (verbosity > 0)
{
printf ("Physical port [%u]: ", i);
}

if (
app_port_cfg_init (
if_list.netif[i].name,
&p_cfg->if_cfg.ports[i - 1].phy_port,
verbosity) != 0)
{
return -1;
}
}

/* Read IP, netmask, gateway from operating system */
ip = pnal_get_ip_address (if_list.netif[0].name);
netmask = pnal_get_netmask (if_list.netif[0].name);
gateway = pnal_get_gateway (if_list.netif[0].name);

if (gateway == IP_INVALID)
{
printf (
"Error: Invalid gateway IP address for Ethernet interface: %s\n",
if_list.netif[0].name);
return -1;
}

if (verbosity > 0)
{
app_print_network_details (ip, netmask, gateway);
}

app_copy_ip_to_struct (&p_cfg->if_cfg.ip_cfg.ip_addr, ip);
app_copy_ip_to_struct (&p_cfg->if_cfg.ip_cfg.ip_gateway, gateway);
app_copy_ip_to_struct (&p_cfg->if_cfg.ip_cfg.ip_mask, netmask);

return ret;
}

/*************************** Helper functions ********************************/

void app_copy_ip_to_struct (
Expand Down Expand Up @@ -1566,7 +1748,8 @@ static void app_handle_cyclic_data (
if (outputdata_length != APP_DATASIZE_OUTPUT)
{
printf ("Wrong outputdata length: %u\n", outputdata_length);
app_set_outputs_default_value (p_appdata->arguments.verbosity);
app_set_outputs_default_value (
p_appdata->arguments.verbosity);
}
else if (outputdata_iops == PNET_IOXS_GOOD)
{
Expand All @@ -1583,7 +1766,8 @@ static void app_handle_cyclic_data (
{
printf ("Wrong IOPS: %u\n", outputdata_iops);
}
app_set_outputs_default_value (p_appdata->arguments.verbosity);
app_set_outputs_default_value (
p_appdata->arguments.verbosity);
}
}
}
Expand Down
Loading

0 comments on commit 6a56f03

Please sign in to comment.