How do I set up my publisher and subscriber to only send/receive data from a particular network card?

Note: Applies to RTI Connext 4.1 and above.

Use the transport properties for the UDPv4 transport to restrict which interfaces the transport will attempt to use. The properties allow you to either use an "allow" list (to specifically allow certain interfaces), or a "deny" list (to specifically deny interfaces). You will usually only use only one of those (probably the allow list).

Using the allow or deny list to restrict interfaces will give you most of what you want, but not quite all:

  • Multicast UDP, receive and send:
RTI Connext will only use the interfaces specified by the allow/deny lists to send or receive multicast datagrams.
  • Unicast UDP, receive:
Every RTI Connext application tells other applications which IP addresses they can use to send data to it. This list will only include the interfaces specified by the allow/deny lists. If the routing configuration has been set up properly on all of the machines and networking hardware, then only the specified interfaces will receive data from other Connext nodes. 
  • Unicast UDP, send:
When an application sends UDP traffic, it is not supposed to be involved in deciding which specific interface will be used to send the traffic. Instead, the networking stack itself will use the destination address and the local machine's routing table to determine the "best" available interface. This is an inherent part of the design of IP networking and allows for some important functionality of IP (e.g., route fail-over). 

So what does this mean for RTI Connext? 

  • You must ensure that the routing tables on your machines are correct and reflect your desired interface usage. If the routing table says that traffic to a certain groups of addresses should use a particular NIC, that NIC will be used, and RTI Connext doesn't have a say in controlling that. 

  • The destination addresses used to send data from a certain node will be the interface addresses provided by all of the other nodes. In other words, a node with incorrectly configured allow/deny lists may cause outgoing unicast UDP traffic to use the "wrong" interface on the *other nodes* in your system.

To summarize

If you see outgoing unicast traffic using a NIC that you do not want to use, then either the destination address is incorrect (which usually means you should adjust the allow/deny lists on the *destination* node for the traffic), or the routing table is incorrect (and you need to fix it). 

Example C++ code:

/* You can specify the UDPv4 transport properties by 
 * using the property structure (struct NDDS_Transport_UDPv4_Property_t)
 *     
 * By default, the participant is created in an enabled state.
 * When using the transport property structure, we need to create a participant disabled. 

 * As an alternative to using the transport property structure, 
 * RTI Data Distribution 4.2 introduces the property QoS. When specifying
 * the DomainParticipant's Property QoS policy, it is not necessary to first create
 * the participant disabled. 
 */

    DDS_DomainParticipantFactoryQos factory_qos;
    retcode = DDSTheParticipantFactory->get_qos(factory_qos);
    if (retcode != DDS_RETCODE_OK) {
        printf("Cannot get factory Qos for domain participant\n");
        // handle the error!
    }

    factory_qos.entity_factory.autoenable_created_entities = DDS_BOOLEAN_FALSE;
    retcode = DDSTheParticipantFactory->set_qos(factory_qos);
    if (retcode != DDS_RETCODE_OK) {
        printf("Cannot set factory Qos for domain participant\n");
        // handle the error!
    }

    // ... set up the participant QoS if desired ...

    /* To create participant with default QoS, use DDS_PARTICIPANT_QOS_DEFAULT
       instead of participant_qos */
    participant = DDSTheParticipantFactory->create_participant(
        domainId, DDS_PARTICIPANT_QOS_DEFAULT,
        NULL /* listener */, DDS_STATUS_MASK_NONE);
    if (participant == NULL) {
        printf("create_participant error\n");
        // handle the error!
    }

    // OK, we have a disabled participant.

    /* Get the transport properties. */
    struct NDDS_Transport_UDPv4_Property_t udp_property =
        NDDS_TRANSPORT_UDPV4_PROPERTY_DEFAULT;
    if (NDDSTransportSupport::get_builtin_transport_property(
            participant, DDS_TRANSPORTBUILTIN_UDPv4,
            (struct NDDS_Transport_Property_t&)udp_property)
            != DDS_RETCODE_OK) {
        printf("***Error: get builtin transport property\n");
        // handle the error!
    }

    char* ALLOWED_NICS[] = {
        "192.168.11.3"  // IP address of the interface to allow (can contain wildcards)
        // You could specify additional allowed interfaces if desired
    };
    const unsigned int NUM_ALLOWED_NICS = sizeof(ALLOWED_NICS)/sizeof(ALLOWED_NICS[0]);
    udp_property.parent.allow_interfaces_list = ALLOWED_NICS;
    udp_property.parent.allow_interfaces_list_length = NUM_ALLOWED_NICS;

    /* Set the transport properties with our changes.
       This *must* be done while the participant is still disabled.
     */
    if (NDDSTransportSupport::set_builtin_transport_property(
            participant, DDS_TRANSPORTBUILTIN_UDPv4,
            (struct NDDS_Transport_Property_t&)udp_property)
            != DDS_RETCODE_OK) {
        printf("***Error: set builtin transport property\n");
        // handle the error!
    }

    /* We're ready to enable the participant. */
    if (participant->enable() != DDS_RETCODE_OK) {
        printf("Cannot enable participant");
        // handle the error!
    }