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 run configure
  and run a mulitport configuration
- Verified on Raspberry Pi with additional USB ethernet interfaces
- Todo: Automatic test suite fails when PNET_MAX PORT > 1
  • Loading branch information
olbjo committed Jan 18, 2021
1 parent 707e94e commit d904487
Show file tree
Hide file tree
Showing 26 changed files with 735 additions and 321 deletions.
12 changes: 12 additions & 0 deletions .pytest_cache/v/cache/lastfailed
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"build2/_deps/googletest-src/googlemock/test/gmock_leak_test.py": true,
"build2/_deps/googletest-src/googlemock/test/gmock_output_test.py": true,
"build2/_deps/googletest-src/googletest/test/gtest_help_test.py": true,
"build2/_deps/googletest-src/googletest/test/gtest_testbridge_test.py": true,
"build3/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py": true,
"build3/_deps/googletest-src/googlemock/test/gmock_leak_test.py": true,
"build3/_deps/googletest-src/googlemock/test/gmock_output_test.py": true,
"build3/_deps/googletest-src/googletest/test/gtest_help_test.py": true,
"build3/_deps/googletest-src/googletest/test/gtest_testbridge_test.py": true,
"build3/_deps/googletest-src/googletest/test/gtest_xml_outfiles_test.py": true
}
32 changes: 32 additions & 0 deletions .pytest_cache/v/cache/nodeids
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMethodsTest::testArgsOfTemplateTypes",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMethodsTest::testArrayArgWithoutNames",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMethodsTest::testCStyleCommentsInParameterListAreNotRemoved",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMethodsTest::testDefaultParameters",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMethodsTest::testDoubleSlashCommentsInParameterListAreRemoved",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMethodsTest::testExplicitVoid",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMethodsTest::testExplicitlyDefaultedConstructorsAndDestructor",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMethodsTest::testExplicitlyDeletedConstructorsAndDestructor",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMethodsTest::testMultipleDefaultParameters",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMethodsTest::testPointerArgWithoutNames",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMethodsTest::testReferenceArgWithoutNames",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMethodsTest::testRemovesCommentsWhenDefaultsArePresent",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMethodsTest::testReturnTypeWithManyTemplateArgs",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMethodsTest::testReturnTypeWithOneTemplateArg",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMethodsTest::testSimpleConstMethod",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMethodsTest::testSimpleConstructorsAndDestructor",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMethodsTest::testSimpleMethod",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMethodsTest::testSimpleMethodInTemplatedClass",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMethodsTest::testSimpleOverrideMethod",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMethodsTest::testStrangeNewlineInParameter",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMethodsTest::testVirtualDestructor",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMocksTest::testClassWithStorageSpecifierMacro",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMocksTest::testEnumClass",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMocksTest::testNamespaces",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMocksTest::testTemplateInATemplateTypedef",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMocksTest::testTemplateInATemplateTypedefWithComma",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMocksTest::testTemplatedClass",
"build2/_deps/googletest-src/googlemock/scripts/generator/cpp/gmock_class_test.py::GenerateMocksTest::testTemplatedForwardDeclaration",
"build2/_deps/googletest-src/googletest/test/gtest_xml_outfiles_test.py::GTestXMLOutFilesTest::testOutfile1",
"build2/_deps/googletest-src/googletest/test/gtest_xml_outfiles_test.py::GTestXMLOutFilesTest::testOutfile2"
]
1 change: 1 addition & 0 deletions .pytest_cache/v/cache/stepwise
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
38 changes: 34 additions & 4 deletions doc/multiple_ports.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,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 @@ -98,7 +99,36 @@ Configuration of p-net stack and sample application (TBD)
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.

Pass the list of ports, starting with the management port as network interface argument
when starting the application for example: ``sudo ./pn_dev -i br0,eth0,eth1 -v``

And/or in ``pnet\src\ports\linux\sampleapp_main.c`` change line::

#define APP_DEFAULT_ETHERNET_INTERFACE "eth0"
to
#define APP_DEFAULT_ETHERNET_INTERFACE "br0,eth0,eth1"

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

pi@pndevice-pi:~/profinet/build $ sudo ./pn_dev -i br0,eth0,eth1 -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
MAC address: C2:38:F3:A6:0A:66
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
232 changes: 219 additions & 13 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 mac_to_string (pnal_ethaddr_t mac, char * outputstring)
{
snprintf (
outputstring,
Expand Down Expand Up @@ -1281,8 +1275,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 +1352,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-00%d",
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 +1375,208 @@ 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.
* I the network interface can not be found or the operation
* fails to read mac, error is
* @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)
{
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;
}

/**
* Parse a comma separated list of network interfaces and check
* that the number of interfaces match the PNET_MAX port configuration.
* Examples:
* PNET_MAX_PORT arg_str status
* 1 "eth0" ok
* 1 "eth0,eth1" err
* 2 "br0,eth0,eth1" ok
* 2 "br0,eth0," err
*
* @param arg_str In: Network interface list as comma separated string
* For example "eth0" or "br0,eth0,eth1
* @param p_if_list Out: List of network interfaces
* @return 0 if network interface list matches configuration
* -1 on error
*/
int app_get_netif_list (const char * arg_str, app_netif_list_t * p_if_list)
{
int ret = 0;
uint16_t i = 0;
uint16_t j = 0;
uint16_t if_index = 0;
char c;

memset (p_if_list, 0, sizeof (*p_if_list));
c = arg_str[i++];
while (c != '\0' && if_index < NELEMENTS (p_if_list->netif))
{
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 (PNET_MAX_PORT == 1)
{
if (if_index >= PNET_MAX_PORT)
{
printf ("Error: Only 1 network interface expected.");
ret = -1;
}

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

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

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

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_list_t if_list;

ret = app_get_netif_list (netif_list_str, &if_list);
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 (
(pnal_ethaddr_t *)&p_cfg->if_cfg.main_port.eth_addr,
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 +1770,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 +1788,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 d904487

Please sign in to comment.