How do I restrict RTI Connext to use only a subset of interfaces?

Note: Applies to RTI Connext 4.x and above.

On a machine with multiple NICs, you can restrict RTI Connext traffic to a subset of the available network interfaces (NICs). For example, this would allow you to segregate DDS traffic from other application-specific data. 

Selecting specific NICs involves configuring a transport plugin. For details on how this is done, see the HTML documentation under Modules, Programming How-To's, Transport Use Cases. The relevant section is called "Changing the properties of the automatically registered builtin transports." 

The following members of the NDDS_Transport_Property_t struct should be set: 

  • allow_interfaces_list and  allow_interfaces_list_length (to use only the specified interfaces) 
  • deny_interfaces_list and  deny_interfaces_list_length (to disable only the specified interfaces). 

The allow/deny lists are arrays of strings which are used to match the IP address of the interfaces (e.g., "10.10.1.123"). The * wildcard can be used to match a pattern of addresses. For example, to choose the NIC that is on the 10.10.0.0/16 network, use the string "10.10.*" to select the NIC. Alternatively, on most platforms the name of the interface may be used (e.g., "eth0" for the first Ethernet interface on a Linux system). 

It should be noted that the allow and deny lists determine:

  • The set of interfaces used for the input ports.
  • The set of interfaces that multicast will use for output (if multicast is available on those interfaces).
  • The set of interfaces that will be put in the participant builtin topic data (which informs the remote participant(s) how to contact this participant).

The allow and deny lists have NO effect on unicast output. This is controlled by the operating system routing table. There are multiple ways how this can be handled by the OS. For example, a Windows or Linux based system might have a physical network interface card (NIC) and a wireless interface card. When you set a unicast address in your initial peers, the participant announcement is sent via the interface with the higher priority. Which in this case will be the physical NIC. This can be configured by modifying the Metric of the network interface. The Metric is basically the priority assigned to the interface. By swapping Metrics between the physical NIC and the wireless adapter you are able to have the participant announcements sent via the wireless network. Another option would be to have a multicast address in your initial peers and the participant announcements will be sent via multicast on all network cards.

There are three methods for selecting a subset of interfaces: 

  1. Use an XML QoS file
  2. Use the transport settings
  3. Use the DomainParticipant's Property QoS

Older versions don't support all three -- see below for which methods are applicable for particular RTI versions.

Method 1 - Use the DomainParticipant's Property QoS  (versions 4.2 and higher)

This method involves using the Property QosPolicy to modify the UDP builtin transport properties. (The Property QoS policy is available in RTI Data Distribution Service 4.2 and higher.) With this method, you do not need to disable the DomainParticipant first.

1. Get the participant_qos and add the properties you want to modify to the QoS:

  #define NIC_IP   "10.10.1.*"
  #define NIC_IP_2 "10.10.1.35" 
  retcode = DDSTheParticipantFactory->get_default_participant_qos(domainparticipant_qos); 
  if (retcode != DDS_RETCODE_OK) {
      puts("Error, impossible get default participant qos");
      return NULL;
  }
  retcode = DDSPropertyQosPolicyHelper::add_property (
              domainparticipant_qos.property,
              "dds.transport.UDPv4.builtin.parent.deny_interfaces_list",
              NIC_IP_2, DDS_BOOLEAN_FALSE);
  if (retcode != DDS_RETCODE_OK) {
      printf("Error, impossible add property1");
      return NULL;
  }
  retcode = DDSPropertyQosPolicyHelper::add_property(
            domainparticipant_qos.property,
            "dds.transport.UDPv4.builtin.parent.allow_interfaces_list", 
                            NIC_IP, DDS_BOOLEAN_FALSE);

  if (retcode != DDS_RETCODE_OK) {
      printf("Error, impossible add property2");
      return NULL;
  }

2. Create the DomainParticipant

Method 2 - Use an XML QoS Profile (version 4.3 and higher)

This method uses an XML QoS profile to configure the DomainParticipant and transport properties.

<dds>
  <qos_library name="test"> 
    <qos_profile name="UDPv4_properties">
      <participant_qos>
        <property>    
          <value>
            <element>
              <name>dds.transport.UDPv4.builtin.parent.deny_interfaces_list</name>
              <value>10.10.1.35</value>
            </element> 
            <element>
              <name>dds.transport.UDPv4.builtin.parent.allow_interfaces_list</name>
              <value>10.10.1.*,192.168.*</value>
            </element>             
          </value>
        </property>
      </participant_qos>
    </qos_profile>
  </qos_library>
</dds>

If you are using RTI Data Distribution Service 4.3e, you must call  DDSTheParticipantFactory->load_profiles() before creating the DomainParticipant with a profile.

When using RTI Data Distribution Service 4.4 and higher, the XML file can be automatically loaded. If NDDS_QOS_PROFILES.xml is in the $NDDSHOME/resource/xml directory, it will be automatically loaded. Similarly, if USER_QOS_PROFILES.xml is in the working directory, it will be automatically loaded. See the Core Libraries and Utilities User’s Manual for more details on XML file loading.

When using version RTI Data Distribution Service 4.4 and higher, place the attached USER_QOS_PROFILES.xml file in the working directory.

Method 3 - Use the Transport Settings (all 4.x versions and above)

1. Before creating the DomainParticipant, make sure the DomainParticipant will be created in a disabled state. For example, in C++: 

  retcode = DDSTheParticipantFactory->get_qos(factory_qos);  
  factory_qos.entity_factory.autoenable_created_entities = DDS_BOOLEAN_FALSE;
  retcode = DDSTheParticipantFactory->set_qos(factory_qos);

2. Get the builtin transports and set the allowed interfaces.

3. Call  set_builtin_transport_property() before the DomainParticipant is enabled. For example, in C++:

#define NIC_IP "10.10.1.*"

  struct NDDS_Transport_UDPv4_Property_t property = NDDS_TRANSPORT_UDPV4_PROPERTY_DEFAULT;
              
  if (NDDSTransportSupport::get_builtin_transport_property 
     (participant, DDS_TRANSPORTBUILTIN_UDPv4,
     (struct NDDS_Transport_Property_t&)property) != DDS_RETCODE_OK) 
  {
      printf("***Error: get builtin transport property\n");                           
  }    

  /* Set the allowed interface(s) */
  property.parent.allow_interfaces_list = new char*[1];
  property.parent.allow_interfaces_list[0] = new char[strlen(NIC_IP)+1];

  strcpy(property.parent.allow_interfaces_list[0], NIC_IP);
  property.parent.allow_interfaces_list_length = 1;

  if (NDDSTransportSupport::set_builtin_transport_property 
             (participant, DDS_TRANSPORTBUILTIN_UDPv4,
             (struct NDDS_Transport_Property_t&)property) != DDS_RETCODE_OK) 
  {
    printf("***Error: set builtin transport property\n");                           
  }

To deny a subset of interfaces, you would do exactly the same as above, but use deny_interfaces_list instead of allow_interfaces_list.

4. Enable the DomainParticipant:

  retcode = participant->enable();

The allow/deny lists are only used during transport initialization; after the DomainParticipant has been enabled, you may dispose of the memory allocated for them.

Comments

It would be better if Method 3 was desbribed before Method 2 and then Method 1. Method 3 is the simplest and most flexible.