.. _`DDS_DomainParticipantFactory_get_instance()`: ../../../api_c/html/group__DDSDomainParticipantFactoryModule.html .. _allow_interface: ../../../api_c/html/structUDP__InterfaceFactoryProperty.html .. _deny_interface: ../../../api_c/html/structUDP__InterfaceFactoryProperty.html .. _enable_interface_bind: ../../../api_c/html/structUDP__InterfaceFactoryProperty.html .. _`DomainParticipantQos::transports`: ../../../api_c/html/structDDS__DomainParticipantQos.html .. _`DomainParticipantQos::discovery`: ../../../api_c/html/structDDS__DomainParticipantQos.html .. _`DomainParticipantQos::user_traffic`: ../../../api_c/html/structDDS__DomainParticipantQos.html .. _UDP_InterfaceFactoryProperty: ../../../api_c/html/structUDP__InterfaceFactoryProperty.html .. highlight:: c UDP Transport ------------- This section describes the built-in |rti_me| UDP transport and how to configure it. The built-in UDP transport (UDP) is a fairly generic UDPv4 transport. |me| supports the following functionality: - Unicast - Multicast - Automatic detection of available network interfaces - Manual configuration of network interfaces - Allow/Deny lists to select which network interfaces can be used - Simple NAT configuration - Configuration of receive threads Registering the UDP Transport ............................. The built-in UDP transport is a |rti_me| component that is automatically registered when the `DDS_DomainParticipantFactory_get_instance()`_ method is called. In order to change the UDP configuration it is necessary to first unregister the transport as shown below .. code-block:: c DDS_DomainParticipantFactory *factory = NULL; RT_Registry_T *registry = NULL; factory = DDS_DomainParticipantFactory_get_instance(); registry = DDS_DomainParticipantFactory_get_registry(factory); /* The built-in transport does not return any properties (3rd param) or * listener (4th param) */ if (!RT_Registry_unregister(registry, "_udp", NULL, NULL)) { /* ERROR */ } When a component is registered, the registration takes the properties and a listener as the 3rd and 4th parameters. In general, it is up to the caller to manage the memory for the properties and the listeners. There is no guarantee that a component makes a copy. The following code-snippet shows how to register the UDP transport with new parameters. .. code-block:: c struct UDP_InterfaceFactoryProperty *udp_property = NULL; /* Allocate a property structure for the heap, it must be valid as long * as the component is registered */ udp_property = (struct UDP_InterfaceFactoryProperty *) malloc(sizeof(struct UDP_InterfaceFactoryProperty)); if (udp_property != NULL) { *udp_property = UDP_INTERFACE_FACTORY_PROPERTY_DEFAULT; /* Only allow network interface "eth0" to be used; */ REDA_StringSeq_set_maximum(&udp_property->allow_interface, 1); REDA_StringSeq_set_length(&udp_property->allow_interface, 1); *REDA_StringSeq_get_reference(&udp_property->allow_interface, 0) = REDA_String_dup("eth0"); /* Register the transport again, using the built-in name */ if (!RT_Registry_register(registry, "_udp", UDP_InterfaceFactory_get_interface(), (struct RT_ComponentFactoryProperty*)udp_property, NULL)) { /* ERROR */ } } else { /* ERROR */ } It should be noted that the UDP transport can be registered with any name, but all transport QoS policies and initial peers must refer to this name. If a transport is referred to and it does not exist, an error message is logged. It is possible to register multiple UDP transports with a `DomainParticipantFactory <../../api_c/html/group__DDSDomainParticipantFactoryModule.html>`_ , and it is also possible to use different UDP transports within the same *DomainParticipant* when multiple network interfaces are available (either physical or virtual). When UDP transformations are enabled, this feature is always enabled and determined by the allow_interface_ and deny_interface_ lists. If any of the lists are non-empty the UDP transports will bind each receive socket to the specific interfaces. When UDP transformations are not enabled, this feature is determined by the value of the enable_interface_bind_. If this value is set to **RTI_TRUE** and the allow_interface_ and/or deny_interface_ properties are non-empty, the receive sockets are bound to specific interfaces. .. _udp_threads: Threading Model ............... The UDP transport creates one receive thread for each unique UDP receive address and port. Thus, by default, three UDP threads are created: - A multicast receive thread for discovery data (assuming multicast is available and enabled) - A unicast receive thread for discovery data - A unicast receive thread for user data Additional threads may be created depending on the transport configuration for a *DomainParticipant*, *DataReader*, and *DataWriter*. The UDP transport creates threads based on the following criteria: - Each unique unicast port creates a new thread - Each unique multicast address *and* port creates a new thread For example, if a *DataReader* specifies its own multicast receive address, a new receive thread will be created. Configuring UDP Receive Threads ''''''''''''''''''''''''''''''' All threads in the UDP transport share the same thread settings. It is important to note that all the UDP properties must be set before the UDP transport is registered. |rti_me| preregisters the UDP transport with default settings when the `DomainParticipantFactory <../../api_c/html/group__DDSDomainParticipantFactoryModule.html>`_ is initialized. To change the UDP thread settings, use the following code. .. code-block:: c struct UDP_InterfaceFactoryProperty *udp_property = NULL; struct UDP_InterfaceFactoryProperty udp_property = UDP_INTERFACE_FACTORY_PROPERTY_DEFAULT; /* Allocate a property structure for the heap, it must be valid as long * as the component is registered */ udp_property = (struct UDP_InterfaceFactoryProperty *) malloc(sizeof(struct UDP_InterfaceFactoryProperty)); *udp_property = UDP_INTERFACE_FACTORY_PROPERTY_DEFAULT; /* Please refer to OSAPI_ThreadOptions for possible options */ udp_property->recv_thread.options = ...; /* The stack-size is platform dependent, it is passed directly to the OS */ udp_property->recv_thread.stack_size = .... /* The priority is platform dependent, it is passed directly to the OS */ udp_property->recv_thread.priority = .... if (!RT_Registry_register(registry, "_udp", UDP_InterfaceFactory_get_interface(), (struct RT_ComponentFactoryProperty*)udp_property, NULL)) { /* ERROR */ } UDP Configuration ................. All the configuration of the UDP transport is done via the `UDP_InterfaceFactoryProperty <../../../api_c/html/structUDP__InterfaceFactoryProperty.html>`_. .. code-block:: c struct UDP_InterfaceFactoryProperty { /* Inherited from */ struct NETIO_InterfaceFactoryProperty _parent; /* Sequence of allowed interface names */ struct REDA_StringSeq allow_interface; /* Sequence of denied interface names */ struct REDA_StringSeq deny_interface; /* The size of the send socket buffer */ RTI_INT32 max_send_buffer_size; /* The size of the receive socket buffer */ RTI_INT32 max_receive_buffer_size; /* The maximum size of the message which can be received */ RTI_INT32 max_message_size; /* The maximum TTL */ RTI_INT32 multicast_ttl; #ifndef RTI_CERT struct UDP_NatEntrySeq nat; #endif /* The interface table if interfaces are added manually */ struct UDP_InterfaceTableEntrySeq if_table; /* The network interface to use to send to multicast */ REDA_String_T multicast_interface; /* If this should be considered the default UDP interfaces if * no other UDP interface is found to handle a route */ RTI_BOOL is_default_interface; /* Disable reading of available network interfaces using system * information and instead rely on the manually configured * interface table */ RTI_BOOL disable_auto_interface_config; /* Thread properties for each receive thread created by this * NETIO interface. */ struct OSAPI_ThreadProperty recv_thread; /* Bind to specific interfaces */ RTI_BOOL enable_interface_bind; struct UDP_TransformRuleSeq source_rules; /* Rules for how to transform sent UDP payloads based on the * destination address. */ struct UDP_TransformRuleSeq destination_rules; /* Determines how regular UDP is supported when transformations * are supported. */ UDP_TransformUdpMode_T transform_udp_mode; /* The locator to use for locators that have transformations. */ RTI_INT32 transform_locator_kind; }; allow_interface ''''''''''''''' The allow_interface_ string sequence determines which interfaces are allowed to be used for communication. Each string element is the name of a network interface, such as "en0" or "eth1". If this sequence is empty, all interface names pass the allow test. The default value is empty. Thus, all interfaces are allowed. deny_interface '''''''''''''' The deny_interface_ string sequence determines which interfaces are not allowed to be used for communication. Each string element is the name of a network interface, such as "en0" or "eth1". If this sequence is empty, the test is false. That is the interface is allowed. Note that the deny list is checked *after* the allow list. Thus, if an interface appears in both, it is denied. The default value is empty, thus no interfaces are denied. max_send_buffer_size '''''''''''''''''''' The max_send_buffer_size_ is the maximum size of the send socket buffer and it *must* be at least as big as the largest sample. Typically, this buffer should be a multiple of the maximum number of samples that can be sent at any given time. The default value is 256KB. max_receive_buffer_size ''''''''''''''''''''''' The max_receive_buffer_size_ is the maximum size of the receive socket buffer and it *must* be at least as big as the largest sample. Typically, this buffer should be a multiple of the maximum number of samples that can be received at any given time. The default value is 256KB. max_message_size '''''''''''''''' The max_message_size_ is the maximum size of the message which can be received, including any packet overhead. The default value is 8KB. Note that |me| does not support fragmentation. multicast_ttl ''''''''''''' The Time-To-Live (TTL) value is only used for multicast. It limits the number of hops a packet can pass through before it is dropped by a router. The default value is 1. nat ''' |me| supports firewalls with NAT. However, this feature has limited use and only supports translation between a private and public IP address. UDP ports are not translated. Furthermore, because |me| does not support any hole punching technique or WAN server, this feature is only useful when the private and public address mapping is static and known in advance. For example, to test between an Android emulator and the host, the following configuration can be used .. code-block:: c UDP_NatEntrySeq_set_maximum(&udp_property->nat,2); UDP_NatEntrySeq_set_length(&udp_property->nat,2); /* Translate the local emulator eth0 address 10.10.2.f:7410 to * 127.0.0.1:7410. This ensures that the address advertised by the * emulator to the host machine is the host's loopback interface, not * the emulator's host interface */ UDP_NatEntrySeq_get_reference(&udp_property->nat,0)-> local_address.kind = NETIO_ADDRESS_KIND_UDPv4; UDP_NatEntrySeq_get_reference(&udp_property->nat,0)-> local_address.port = 7410; UDP_NatEntrySeq_get_reference(&udp_property->nat,0)-> local_address.value.ipv4.address = 0x0a00020f; UDP_NatEntrySeq_get_reference(&udp_property->nat,0)-> public_address.kind = NETIO_ADDRESS_KIND_UDPv4; UDP_NatEntrySeq_get_reference(&udp_property->nat,0)-> public_address.port = 7410; UDP_NatEntrySeq_get_reference(&udp_property->nat,0)-> public_address.value.ipv4.address = 0x7f000001; /* Translate the local emulator eth0 address 10.10.2.f:7411 to * 127.0.0.1:7411. This ensures that the address advertised by the * emulator to the host machine is the host's loopback interface */ UDP_NatEntrySeq_get_reference(&udp_property->nat,1)-> local_address.kind = NETIO_ADDRESS_KIND_UDPv4; UDP_NatEntrySeq_get_reference(&udp_property->nat,1)-> local_address.port = 7411; UDP_NatEntrySeq_get_reference(&udp_property->nat,1)-> local_address.value.ipv4.address = 0x0a00020f; UDP_NatEntrySeq_get_reference(&udp_property->nat,1)-> public_address.kind = NETIO_ADDRESS_KIND_UDPv4; UDP_NatEntrySeq_get_reference(&udp_property->nat,1)-> public_address.port = 7411; UDP_NatEntrySeq_get_reference(&udp_property->nat,1)-> public_address.value.ipv4.address = 0x7f000001; if_table '''''''' The if_table_ provides a method to manually configure which interfaces are available for use; for example, when using IP stacks that do not support reading interface lists. The following example shows how to manually configure the interfaces. .. code-block:: c /* The arguments to the UDP_InterfaceTable_add_entry functions are: * The if_table itself * The network address of the interface * The netmask of the interface * The name of the interface * Interface flags. Valid flags are: * UDP_INTERFACE_INTERFACE_UP_FLAG - The interface is UP * UDP_INTERFACE_INTERFACE_MULTICAST_FLAG - The interface supports multicast */ if (!UDP_InterfaceTable_add_entry(&udp_property->if_table, 0x7f000001,0xff000000,"loopback", UDP_INTERFACE_INTERFACE_UP_FLAG | UDP_INTERFACE_INTERFACE_MULTICAST_FLAG)) { /* Error */ } multicast_interface ''''''''''''''''''' The multicast_interface_ may be used to select a particular network interface to be used to send multicast packets. The default value is any interface (that is, the OS selects the interface). is_default_interface '''''''''''''''''''' The is_default_interface_ flag is used to indicate that this |me| network transport shall be used if no other transport is found. The default value is **RTI_TRUE**. disable_auto_interface_config ''''''''''''''''''''''''''''' Normally, the UDP transport will try to read out the interface list (on platforms that support it). Setting disable_auto_interface_config_ to **RTI_TRUE** will prevent the UDP transport from reading the interface list. recv_thread ''''''''''' The recv_thread_ field is used to configure all the receive threads. Please refer to :ref:`udp_threads` for details. enable_interface_bind ''''''''''''''''''''' When this is set to **TRUE** the UDP transport binds each receive port to a specific interface when the allow_interface_/deny_interface_ lists are non-empty. This allows multiple UDP transports to be used by a single *DomainParticipant* at the expense of an increased number of threads. This property is ignored when transformations are enabled and the allow_interface_/deny_interface_ lists are non-empty. source_rules '''''''''''' Rules for how to transform received UDP payloads based on the source address. destination_rules ''''''''''''''''' Rules for how to transform sent UDP payloads based on the destination address. transform_udp_mode '''''''''''''''''' Determines how regular UDP is supported when transformations are supported. When transformations are enabled the default value is **UDP_TRANSFORM_UDP_MODE_DISABLED**. transform_locator_kind '''''''''''''''''''''' The locator to use for locators that have transformations. When transformation rules have been enabled, they are announced as a vendor specific locator. This property overrides this value. NOTE: Changing this value may prevent communication. UDP Transformations ................... The UDP transform feature enables custom transformation of incoming and outgoing UDP payloads based on transformation rules between a pair of source and destination IP addresses. Some examples of transformations are encrypted data or logging. This section explains how to implement and use transformations in an application and is organized as follows: - :ref:`udptf_overview` - :ref:`udptf_transformations` - :ref:`udptf_rules` - :ref:`udptf_interop` - :ref:`udptf_errors` - :ref:`udptf_example_code` - :ref:`udptf_examples` - :ref:`udptf_os_configuration` .. _udptf_overview: Overview '''''''' The UDP transformation feature enables custom transformation of incoming and outgoing UDP payloads. For the purpose of this section, a UDP payload is defined as a sequence of octets sent or received as a single UDP datagram excluding UDP headers -- typically UDP port numbers -- and trailers, such as the optional used checksum. An outgoing payload is the UDP payload passed to the network stack. The transformation feature allows a custom transformation of this payload just before it is sent. The UDP transport receives payloads to send from an upstream layer. In |rti_me| this layer is typically RTPS, which creates payloads containing one or more RTPS messages. The transformation feature enables transformation of the entire RTPS payload before it is passed to the network stack. The same RTPS payload may be sent to one or more locators. A locator identifies a destination address, such as an IPv4 address, a port, such as a UDP port, and a transport kind. The address and port is used by the UDP transport to reach a destination. However, only the destination address is used to determine which transformation to apply. An incoming payload is the UDP payload received from the network stack. The transformation feature enables transformation of the UDP payload received from the network stack *before* it is passed to the upstream interface, typically RTPS. The UDP transport only receives payloads destined for one of its network interface addresses, but may receive UDP payloads destined for many different ports. The transformation does not take a port into account, only the source address. In |me| the payload is typically a RTPS payload containing one or more RTPS messages. UDP transformations are registered with |me| and used by the UDP transport to determine how to transform payloads based on a source or destination address. Please refer to :ref:`udptf_transformations` for details on how to implement transformations and :ref:`udptf_rules` for how to add rules. Transformations are local resources. There is no exchange between different UDP transports regarding what a transformation does to a payload. This is considered a-priori knowledge and depends on the implementation of the transformation. Any negotiation of e.g. keys must be handled before the UDP transport is registered. Thus, if a sender and receiver does not apply consistent rules, they may not be able to communicate, or incorrect data may result. Note that while information is typically in the direction from a *DataWriter* to a *DataReader*, a reliable *DataReader* also send protocol data to a *DataWriter*. These messages are also transformed. Network Interface Selection """"""""""""""""""""""""""" When a *DomainParticipant* is created it first creates an instance of each transport configured in the `DomainParticipantQos::transports`_ Qos policy. Thus, each UDP transport registered with |me| must have a unique name (up to 7 characters). Each registered transport can be configured to use all or some of the available interfaces using the allow_interface_ and deny_interface_ properties. The registered transports may now be used for either discovery data (specified in `DomainParticipantQos::discovery`_), user_traffic (specified in `DomainParticipantQos::user_traffic`_) or both. The *DomainParticipant* also queries the transport for which addresses it is capable of sending to. When a participant creates multiple instances of the UDP transport, its important instances use non-overlapping networking interface resources. Data Reception """""""""""""" Which transport to use for discovery data is determined by the `DomainParticipantQos::discovery`_ Qos policy. For each transport listed the *DomainParticipant* reserves a network address to listen to. This network address is sent as part of the discovery data and is used by other *DomainParticipant* as the address to send discovery data for this *DomainParticipant*. Because a UDP transformation only looks at source and destination addresses, if different transformations are needed for discovery and user-data, different UDP transport registrations must be used and hence different network interfaces. Data Transmission """"""""""""""""" Which address to send data to is based on the locators received as part of discovery and the peer list. Received locators are analyzed and a transport locally registered with a *DomainParticipant* is selected based on the locator kind, address and mask. The first matching transport is selected. If a matching transport is not found, the locator is discarded. NOTE: A transport is not a matching criteria at the same level as a Qos policy. If a discovered entity requests user data on a transport that doesn’t exist, it is not unmatched. The peer list, as specified by the application, is a list of locators to send participant discovery announcements to. If the transport to use is not specified, e.g. “udp1@192.168.1.1”, but instead “192.168.1.1”, then all transports that understand this address will send to it. Thus, in this case the latter is used, and two different UDP transports are registered; they will both send to the same address. However, one transport may send transformed data and the other may not depending on the destination address. .. _udptf_transformations: Creating a Transformation Library ''''''''''''''''''''''''''''''''' The transformation library is responsible for creating and performing transformations. Note that a library is a logical concept and does not refer to an actual library in, for example, UNIX. A library in this context is a collection of routines that together creates, manages, and performs transformations. How these routines are compiled and linked with an application using |rti_me| is out of scope of this section. The transformation library must be registered with |me|'s run-time and must implement the required interfaces. This ensures proper life-cycle management of transformation resources as well as clear guidelines regarding concurrency and memory management. From |me|’s run-time point of view, the transformation library must implement methods so that: - A library can be initialized. - A library can be instantiated. - An instance of the library performs and manages transformations. The first two tasks are handled by |me|’s run-time factory interface which is common for all libraries managed by |me|. The third task is handled by the transformation interface, which is specific to UDP transformations. The following describes the relationship between the different interfaces: - A library is initialized once when it is registered with |me|. - A library is finalized once when it is unregistered from |me|. - Multiple library instances can be created. If a library is used twice, for example registered with two different transports, two different library contexts are created using the factory interface. |me| assumes that concurrent access to two different instances is allowed. - Different instances of the library can be deleted independently. An instance is deleted using the factory interface. - A library instance creates specific source or destination transformations. Each transformation is expected to transform a payload to exactly one destination or from one source. The following relationship is true between the UDP transport and a UDP transformation library: - Each registered UDP transport may make use of one or more UDP transformation libraries. - A DDS *DomainParticipant* creates one instance of each registered UDP transport. - Each instance of the UDP transport creates one instance of each enabled transformation library registered with the UDP transport. - Each Transformation rule created by the UDP transport creates one send or one receive transformation. .. _udptf_rules: Creating Transformation Rules ''''''''''''''''''''''''''''' Transformation rules decide how a payload should be transformed based on either a source or destination address. Before a UDP transport is registered, it must be configured with the transformation libraries to use, as well as which library to use for each source and destination address. For each UDP payload sent or received, an instance of the UDP transport searches for a matching source or destination rule to determine which transformation to apply. The transformation rules are added to the `UDP_InterfaceFactoryProperty <../../../api_c/html/structUDP__InterfaceFactoryProperty.html>`_ before registration takes place. If no transformation rules have been configured, all payloads are treated as regular UDP packets. If no send rules have been asserted, the payload is sent as is. If all outgoing messages are to be transformed, a single entry is sufficient (address = 0, mask = 0). If no receive rules have been asserted, it is passed upstream as is. If all incoming messages are to be transformed, a single entry is sufficient (address = 0, mask = 0). If no matching rule is found, the packet is dropped and an error is logged. NOTE: `UDP_InterfaceFactoryProperty <../../../api_c/html/structUDP__InterfaceFactoryProperty.html>`_ is immutable after the UDP transport has been registered. .. _udptf_interop: Interoperability '''''''''''''''' When the UDP transformations has enabled at least one transformation, it will only inter-operate with another UDP transport which also has at least one transformation. UDP transformations does not interoperate with |rti_core_pro|. .. _udptf_errors: Error Handling '''''''''''''' The transformation rules are applied on a local basis and correctness is based on configuration. It is not possible to detect that a peer participant is configured for different behavior and errors cannot be detected by the UDP transport itself. However, the transformation interface can return errors which are logged. .. _udptf_example_code: Example Code '''''''''''' Example Header file MyUdpTransform.h: .. literalinclude:: /examples/MyUdpTransform.h :language: c Example Source file MyUdpTransform.c: .. literalinclude:: /examples/MyUdpTransform.c :language: c Example configuration of rules: .. literalinclude:: /examples/common.c :language: c .. _udptf_examples: Examples '''''''' The following examples illustrate how this feature can be used in a system with a mixture of different types of UDP transport configurations. For the purpose of the examples, the following terminology is used: - Plain communication -- No transformations have been applied. - Transformed User Data -- Only the user-data is transformed, discovery is plain. - Transformed Discovery -- Only the discovery data is transformed, user-data is plain. - Transformed Data -- Both discovery and user-data are transformed. Unless stated otherwise the transformations are different. A transformation Tn is a transformation such that an outgoing payload transformed with Tn can be transformed back to its original state by applying Tn to the incoming data. A network interface can be either a physical or virtual. Plain Communication Between 2 Nodes """"""""""""""""""""""""""""""""""" In this system two Nodes, A and B, are communicating with plain communication. Node A has one interface, a0, and Node B has one interface, b0. Node A: - Register the UDP transport Ua with allow_interface = a0. - DomainParticipantQos.transports.enabled_transports = “Ua” - DomainParticipantQos.discovery.enabled_transports = ”Ua://” - DomainParticipantQos.user_data.enabled_transports = ”Ua://” Node B: - Register the UDP transport Ub with allow_interface = b0. - DomainParticipantQos.transports.enabled_transports = “Ub” - DomainParticipantQos.discovery.enabled_transports = ”Ub://” - DomainParticipantQos.user_data.enabled_transports = ”Ub://” Transformed User Data Between 2 Nodes """"""""""""""""""""""""""""""""""""" In this system two Nodes, A and B, are communicating with transformed user data. Node A has two interfaces, a0 and a1, and Node B has two interfaces, b0 and b1. Since each node has only one peer, a single transformation is sufficient. Node A: - Add a destination transformation T0 to Ua0, indicating that all sent data is transformed with T0. - Add a source transformation T1 to Ua0, indicating that all received data is transformed with T1. - Register the UDP transport Ua0 with allow_interface = a0. - Register the UDP transport Ua1 with allow_interface = a1. - No transformations are registered with Ua1. - DomainParticipantQos.transports.enabled_transports = “Ua0”,”Ua1” - DomainParticipantQos.discovery.enabled_transports = ”Ua1://” - DomainParticipantQos.user_traffic.enabled_transports = ”Ua0://” Node B: - Add a destination transformation T1 to Ub0, indicating that all sent data is transformed with T1. - Add a source transformation T0 to Ub0, indicating that all received data is transformed with T0. - Register the UDP transport Ub0 with allow_interface = b0. - Register the UDP transport Ub1 with allow_interface = b1. - No transformations are registered with Ub1. - DomainParticipantQos.transports.enabled_transports = “Ub0”,”Ub1” - DomainParticipantQos.discovery.enabled_transports = ”Ub1://” - DomainParticipantQos.user_traffic.enabled_transports = ”Ub0://” Ua0 and Ub0 performs transformations and are used for user-data. Ua1 and Ub1 are used for discovery and no transformations takes place. Transformed Discovery Data Between 2 Nodes """""""""""""""""""""""""""""""""""""""""" In this system two Nodes, A and B, are communicating with transformed user data. Node A has two interfaces, a0 and a1, and Node B has two interfaces, b0 and b1. Since each node has only one peer, a single transformation is sufficient. Node A: - Add a destination transformation T0 to Ua0, indicating that all sent data is transformed with T0. - Add a source transformation T1 to Ua0, indicating that all received data is transformed with T1. - Register the UDP transport Ua0 with allow_interface = a0. - Register the UDP transport Ua1 with allow_interface = a1. - No transformations are registered with Ua1. - DomainParticipantQos.transports.enabled_transports = “Ua0”,”Ua1” - DomainParticipantQos.discovery.enabled_transports = ”Ua0://” - DomainParticipantQos.user_data.enabled_transports = ”Ua1://” Node B: - Add a destination transformation T1 to Ub0, indicating that all sent data is transformed with T1. - Add a source transformation T0 to Ub0, indicating that all received data is transformed with T0. - Register the UDP transport Ub0 with allow_interface = b0. - Register the UDP transport Ub1 with allow_interface = b1. - No transformations are registered with Ub1. - DomainParticipantQos.transports.enabled_transports = “Ub0”,”Ub1” - DomainParticipantQos.discovery.enabled_transports = ”Ub0://” - DomainParticipantQos.user_data.enabled_transports = ”Ub1://” Ua0 and Ub0 performs transformations and are used for discovery. Ua1 and Ub1 are used for user-data and no transformation takes place. Transformed Data Between 2 Nodes (same transformation) """""""""""""""""""""""""""""""""""""""""""""""""""""" In this system two Nodes, A and B, are communicating with transformed data using the same transformation for user and discovery data. Node A has one interface, a0, and Node B has one interface, b0. Node A: - Add a destination transformation T0 to Ua0, indicating that all sent data is transformed with T0. - Add a source transformation T1 to Ua0, indicating that all received data is transformed with T1. - Register the UDP transport Ua0 with allow_interface = a0. - DomainParticipantQos.transports.enabled_transports = “Ua0” - DomainParticipantQos.discovery.enabled_transports = ”Ua0://” - DomainParticipantQos.user_data.enabled_transports = ”Ua0://” Node B: - Add a destination transformation T1 to Ub0, indicating that all sent data is transformed with T1. - Add a source transformation T0 to Ub0, indicating that all received data is transformed with T0. - Register the UDP transport Ub0 with allow_interface = b0. - DomainParticipantQos.transports.enabled_transports = “Ub0” - DomainParticipantQos.discovery.enabled_transports = ”Ub0://” - DomainParticipantQos.user_data.enabled_transports = ”Ub0://” Ua0 and Ub0 performs transformations and are used for discovery and for user-data. Transformed Data Between 2 Nodes (different transformations) """""""""""""""""""""""""""""""""""""""""""""""""""""""""""" In this system two Nodes, A and B, are communicating with transformed data using different transformations for user and discovery data. Node A has two interfaces, a0 and a1, and Node B has two interfaces, b0 and b1. Node A: - Add a destination transformation T0 to Ua0, indicating that all sent data is transformed with T0. - Add a source transformation T1 to Ua0, indicating that all received data is transformed with T1. - Add a destination transformation T2 to Ua1, indicating that all sent data is transformed with T2. - Add a source transformation T3 to Ua1, indicating that all received data is transformed with T3. - Register the UDP transport Ua0 with allow_interface = a0. - Register the UDP transport Ua1 with allow_interface = a1. - DomainParticipantQos.transports.enabled_transports = “Ua0”,”Ua1” - DomainParticipantQos.discovery.enabled_transports = ”Ua0://” - DomainParticipantQos.user_data.enabled_transports = ”Ua1://” Node B: - Add a destination transformation T1 to Ub0, indicating that all sent data is transformed with T1. - Add a source transformation T0 to Ub0, indicating that all received data is transformed with T0. - Add a destination transformation T3 to Ub1, indicating that all sent data is transformed with T3. - Add a source transformation T2 to Ub1, indicating that all received data is transformed with T2. - Register the UDP transport Ub0 with allow_interface = b0. - Register the UDP transport Ub1 with allow_interface = b1. - DomainParticipantQos.transports.enabled_transports = “Ub0”,”Ub1” - DomainParticipantQos.discovery.enabled_transports = ”Ub0://” - DomainParticipantQos.user_data.enabled_transports = ”Ub1://” Ua0 and Ub0 performs transformations and are used for discovery. Ua1 and Ub1 performs transformations and are used for user-data. .. _udptf_os_configuration: OS Configuration """""""""""""""" In systems with serveral network interfaces, |me| cannot ensure which network interface should be used to send a packet. Depending on the UDP transformations configured, this might be a problem. To illustrate this problem, let's assume a system with two nodes, A and B. Node A has two network interfaces, a0 and a1, and Node B has two network interfaces, b0 and b1. In this system, Node A is communicating with Node B using a transformation for discovery and a different transformation for user data. Node A: - Add a destination transformation T0 to Ua0, indicating that sent data to b0 is transformed with T0. - Add a source transformation T1 to Ua0, indicating that received data from b0 is transformed with T1. - Add a destination transformation T2 to Ua1, indicating that sent data to b1 is transformed with T2. - Add a source transformation T3 to Ua1, indicating that received data from b1 is transformed with T3. - Register the UDP transport Ua0 with allow_interface = a0. - Register the UDP transport Ua1 with allow_interface = a1. - DomainParticipantQos.transports.enabled_transports = “Ua0”,”Ua1” - DomainParticipantQos.discovery.enabled_transports = ”Ua0://” - DomainParticipantQos.user_data.enabled_transports = ”Ua1://” Node B: - Add a destination transformation T1 to Ub0, indicating that sent data to a0 is transformed with T1. - Add a source transformation T0 to Ub0, indicating that received data from a0 transformed with T0. - Add a destination transformation T3 to Ub1, indicating that sent data to a1 is transformed with T3. - Add a source transformation T2 to Ub1, indicating that received data from a1 transformed with T2. - Register the UDP transport Ub0 with allow_interface = b0. - Register the UDP transport Ub1 with allow_interface = b1. - DomainParticipantQos.transports.enabled_transports = “Ub0”,”Ub1” - DomainParticipantQos.discovery.enabled_transports = ”Ub0://” - DomainParticipantQos.user_data.enabled_transports = ”Ub1://” Node A sends a discovery packet to Node B to interface b0. This packet will be transformed using T0 as specified by Node A configuration. When this packet is received in Node B, it will be transformed using either T0 or T2 depending on the source address. Node's A OS will use a0 or a1 to send this packet but |me| cannot ensure which one will be used. In case the OS sends the packet using a1, the wrong transformation will be applied in Node B. Some systems have the possibility to configure the source address that should be used when a packet is sent. In POSIX systems, command ``ip route add dev `` can be used. By typing command ``ip route add < b0 ip >/32 dev a0`` in Node A, the OS will send all packets to Node B b0 IP address using interface a0. This would ensure that the correct transformation is applied in Node B. The same should be done to ensure that user data is sent with the right address ``ip route add < b1 ip >/32 dev a1``. Of course, similar configuration is needed in Node B.