1.5.2. Connecting Nodes over an External Network

1.5.2.1. Background

Many robotic applications involve complex network topologies (mesh, nested, etc.) in which nodes, processes or entities from one host may need to interact with both, nodes from outside and inside its network.

Consider the following nested network scenario: one talker node inside one host’s private LAN sub-network needs to communicate with two listener nodes; the first one belonging to the same LAN as the talker, and the second one deployed within an external host with its own private sub-network. Also consider both hosts externally connected to the same network. The following diagram depicts the aforementioned scheme.

../../../../../_images/network_setup.svg

This example case consists on two hosts, the first one maintaining two docker containers running the well-known ROS 2 talker-listener example nodes, and a second one with a ROS 2 listener inside another container. In Vulcanexus, the communication among the different nodes can be achieved by means of Fast DDS’ External Locators feature defined in WireProtocolConfigQos.

1.5.2.2. Prerequisites

For accomplishing this tutorial, two available hosts with Docker and a Vulcanexus image are required. Please refer to the installation steps detailed in Docker installation. In addition, host’s ports 11200, 11201 need to be available (these ports have been selected as an example for this tutorial, but it is up to the user to make a different choice).

Fast DDS domain participants will require to announce themselves into their host’s external network(s). Net-tools, Network Manager or similar packages need to be installed in the system in order to retrieve the corresponding IPs addresses.

1.5.2.3. Understanding External Locators

External locators should be seen as an extra feature over the default communication mechanisms (unicast, multicast). In that sense, it is possible not just to discover peers via multicast within the same LAN, but also peers in remote sub-networks over a shared external network at some higher level (WAN, WLAN, etc.). It is for this reason that External Locators relies on the the concept of levels of externality, which effectively map to the different nesting levels of the network setup, resulting in a sequence of external IP addresses exposed by the different nested sub-network interfaces.

As described in the next section, it is possible to configure external IP locators with an associated externality index, cost, and sub-network mask within the DomainParticipant configuration.

1.5.2.4. Enable External Locators via XML configuration files

In order to define the desired External Locators configuration, an XML profile needs to be provided (see Fast DDS XML profiles). External Locators announcement for the different Communication phases: participant and endpoint discovery phase (metatraffic, initial peers tags), and user data communication phase (user traffic tag), should be defined.

Following with the example above, two XML configuration profiles should be provided. The power of External Locators is the ability to connect to nodes within external networks while still being discovered in the local network. Due to this reasoning, multicast discovery will be used for the second container on the first host (consequently, there is no need to provide any additional XML profile). The two resultant XML configurations are detailed below:

Note

Note that the container network itself does not create another level of externality in this case, as it is bridged with the host network.

<?xml version="1.0" encoding="UTF-8" ?>
<dds>
    <profiles xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles">
        <participant profile_name="container0" is_default_profile="true">
            <rtps>
                <!-- External locators for user traffic -->
                <default_external_unicast_locators>
                    <udpv4 externality="1" cost="0" mask="24">
                        <!-- Host 1 external IP -->
                        <address>192.168.1.40</address>
                        <port>11201</port>
                    </udpv4>
                </default_external_unicast_locators>
                <builtin>
                    <!-- External locators for discovery traffic -->
                    <metatraffic_external_unicast_locators>
                        <udpv4 externality="1" cost="0" mask="24">
                            <!-- Host 1 external IP -->
                            <address>192.168.1.40</address>
                            <port>11200</port>
                        </udpv4>
                    </metatraffic_external_unicast_locators>
                    <!-- Locators of remote participants (discovery traffic)-->
                    <initialPeersList>
                        <!-- Container 2 peer-->
                        <locator>
                            <udpv4>
                                <!-- Host 2 external IP -->
                                <address>192.168.1.56</address>
                                <port>11200</port>
                            </udpv4>
                        </locator>
                        <!--
                            Local network DDS default multicast to discover
                            other participants in the same LAN,
                            using External Locators, or not
                        -->
                        <locator>
                            <udpv4>
                                <address>239.255.0.1</address>
                                <port>7400</port>
                            </udpv4>
                        </locator>
                    </initialPeersList>
                </builtin>
            </rtps>
        </participant>
    </profiles>
</dds>

1.5.2.5. Run the example

This section provides with step-by-step instructions for setting up the example scenario described in previous sections. On both hosts, open a shell and run:

docker run --rm -it `# Cleanup, interactive terminal` \
    -p 11200-11201:7410-7411/udp `# Expose default internal ports to host` \
    ubuntu-vulcanexus:humble-desktop `# Image name`

Important

For galactic and former distributions, the following port mapping should be used instead: -p 11200-11201:7412-7413/udp

Note

It is important to specify the port mapping argument so as to expose docker internal ports to the host. See Docker Networking for further information.

The next step is the creation of the XML profiles. Inside each one of the three containers, create a Profiles.xml file and paste the contents of the corresponding XML profile configuration, according to the previous section.

Finally, export the environment variable pointing to the Profiles.xml file, source Vulcanexus environment and run the ros2 example nodes.

source /vulcanexus_entrypoint.sh
export FASTRTPS_DEFAULT_PROFILES_FILE=/Profiles.xml # Or the Profiles.xml file location
ros2 run demo_nodes_cpp talker

At this point, nodes should be communicating with each other as expected. A message Hello World: [count] should start printing in the talker’s container terminal while both listeners keep receiving it, in their respective container consoles, as follows: