eclipse-cyclonedds / cyclonedds

Eclipse Cyclone DDS project
https://projects.eclipse.org/projects/iot.cyclonedds
Other
870 stars 355 forks source link

Can the unicast port number of dds be configured with a static port number? #2110

Open luzizheng opened 1 week ago

luzizheng commented 1 week ago

One unicast port per domain participant it serves, chosen by the kernel from the list of anonymous ports, that is, >= 32768. Can this unicast port number be configured with a static port number?

eboasson commented 4 days ago

Yes, you can. You do it by configuring something called the "participant index":

<Domain>
  <Discovery>
    <ParticipantIndex>
      X
    </ParticipantIndex>
  </Discovery>
</Domain>

and this X can be none, auto, an integer ≥ 0 and ≤ N or default (= none or auto, depending on some heuristics about multicast). If it is none, you get this random port number. If it is auto it tries integers from 0 .. M ≤ N, trying to bind sockets to the corresponding port numbers and failing if it doesn't find a number that works. So that leaves M, N and the resulting port numbers.

N ultimately comes from the limits on port numbers (the resulting port numbers must be ≤ 65535) and way the port numbers get calculated using this number. With the default settings, N ≤ 120 IIRC. M is Domain/Discovery/MaxAutoParticipantIndex which used to be 9 but today got bumped to 99.

The mapping comes from the specification and can be configured using the elements under Domain/Discovery/Ports. It is:

Base
+ DomainGain * domain_id
+ ParticipantGain * participant index
+ (UnicastMetaOffset and/or UnicastDataOffset)

With the defaults, for domain id 0, participant index 0 you get 7410/7411; participant index 1 you get 7412/7413; &c.

The normal way to get a static port number is by putting a number in ParticipantIndex. If you really want to, you can also fix it by tweaking the port mapping, but that'll confuse everyone 🙂.

luzizheng commented 3 days ago

My configuration is as follows:

I then run a test program that creates two participants with domains 0 and 1. Then I use the ss tool to detect that there are two more dynamically bound random port numbers.

<Domain>
  <Discovery>
    <ParticipantIndex>0</ParticipantIndex>
  </Discovery>
</Domain>
ss -tunlp | grep dds

udp  UNCONN  0      0       10.13.83.236:38628    0.0.0.0.*   user:(("test_dds_port",pid=17724,fd=10))

udp  UNCONN  0      0       0.0.0.0:7410                0.0.0.0.*   user:(("test_dds_port",pid=17724,fd=3))

udp  UNCONN  0      0       0.0.0.0:7411                0.0.0.0.*   user:(("test_dds_port",pid=17724,fd=4))

udp  UNCONN  0      0       0.0.0.0:7660                0.0.0.0.*   user:(("test_dds_port",pid=17724,fd=8))

udp  UNCONN  0      0       0.0.0.0:7661                0.0.0.0.*   user:(("test_dds_port",pid=17724,fd=9))

udp  UNCONN  0      0       10.13.83.236:45700    0.0.0.0.*   user:(("test_dds_port",pid=17724,fd=5))
eboasson commented 3 days ago

Oy! I forgot about the sockets it creates for sending data. Those get a random port number and I don't think it can be configured otherwise currently ...

There is not much use for separate sockets for sending data if there's only one network interface in use, which is the common case for Cyclone. It is not difficult to change that, but it is a bit fiddly because the multicast transmit interface needs to be set and it does not do that for the sockets it uses to receive data.

I think it'll stop creating that extra socket and use the "unicast data" socket (i.e., the one at offset 11) if you change https://github.com/eclipse-cyclonedds/cyclonedds/blob/447912e79fd08e2a0dcb439a0022116a96267c90/src/core/ddsi/src/ddsi_init.c#L1567 to

  if (gv->n_interfaces == 1 || gv->config.many_sockets_mode == DDSI_MSM_NO_UNICAST)

and you change: https://github.com/eclipse-cyclonedds/cyclonedds/blob/447912e79fd08e2a0dcb439a0022116a96267c90/src/core/ddsi/src/ddsi_udp.c#L602 to

set_mc_xmit_options = true;

but I haven't tried it ...

If you decide to give it a go, please let me know whether it works or not ☺️