How to control the source IP address of a ZeroMQ packet on a machine with multiple IPs?
Asked Answered
A

2

8

The Python standard library's socket.create_connection()method has a source address option, for controlling which source IP a connection uses.

How do I do the same thing with a Python ZeroMQ socket, given a machine that has multiple addresses?

In this case, I've been using Linux's iproute2 ip addr add to create the addresses and the ZeroMQ PUB/SUB socket-archetypes.

Actinozoan answered 6/10, 2017 at 23:20 Comment(2)
I don't think I fully understand the problem you're trying to solve ... it the interfaces have specific subnets on them the routing should decide where to egress, and if they don't does it really matter which one gets picked?Chelyabinsk
I'm testing layer 3 load balancing, so the source IP address determines where traffic ends up.Actinozoan
A
1

When trying to .connect() to a remote, I found the answer in the protocol documentation, put the source ip before a semicolon in the connect string:

rc = zmq_connect(socket, "tcp://192.168.1.17:5555;192.168.1.1:5555")

In Python, this looks like:

socket = zmq.Context().socket(zmq.SUB)
socket.connect('tcp://192.168.1.17:5555;192.168.1.1:5555')
Actinozoan answered 24/10, 2017 at 18:26 Comment(1)
A semicolon-separated list expansion is rather a side-effect of the "hidden" API feature of the ZeroMQ core. It functionally creates the same thing as a sequence of calls to the .connect()-method, irrespective whether the first was using a tcp:// transport-class and the other an epgm:// one, as explained above.Restaurateur
R
18

Well, ZeroMQ is a bit tricky to read as a socket-"counterparty" ( it's not )

Why?

Classical socket is a free-to-harness resource.

ZeroMQ is a rather complex hierarchy of ideas and principles of behaviours ( better - distributed behaviours ), that help design smart distributed computing systems, without touching the low-level ( ZeroMQ well abstracted ) details, that control the actual flow of events in the storms of harsh conditions all distributed computing systems are open to face ( and have to handle at low level accordingly, if the high-level abstractions "promised" by ZeroMQ to keep are to be fulfilled and ease the designers' minds to focus rather on his/her core application part, not re-designing wheels ( with all trials and errors ) on pulling strings on O/S resources and shaking systems services for collecting just a few low-hanging types of fruits ).


For these reasons better straight forget ZeroMQ to be "something-like-socket"


ZeroMQ hierarchy in less than a five seconds

1:
ZeroMQ promises an easy re-use of a few trivial Scalable Formal Communication Pattern archetypes offering a particular distributed behaviour { PUB/SUB | PUSH/PULL | PAIR/PAIR | XPUB/XSUB | ... | REQ/REP }.

2:
Except a case of exclusively using just a device-less inproc:// transport-class, in all other cases, ZeroMQ needs one or more instances of a tunable "engine" - a Context( nIOthreads = N ), N >= 1.

3:
Having this, any ( future socket ) Access Point could get instantiated, bearing a behavioural archetype since the very moment of birth:

aSubscribeCHANNEL = aLocalCONTEXT.socket( zmq.SUB )      # this is NOT a <SOCKET>
#                                 ^^^^^^__________________ even it was typed in

4:
Having an "Access Point" instance ready "inside" the local "engine", one can lock-in its materialisation in the external-reality, using one or more ( yes, more ... WOW! Meaning more incoming pulling-strings into / whistles blowing out from a single Access Point "behaviour-node" ) calls to either of these methods:
.bind( <transport-class>://<a-class-specific-address> )
or
.connect( <transport-class>://<a-class-specific-address> )

5:
If and only if a .bind()-RTO-ready Access Point A "gets visited" by a first live .connect()-RTO-ready Access Point B, having any matching behaviour pairing, the ZeroMQ-messaging/signalling archetype gets live ( naming it also a socket was probably used for historical reasons, to ease an explanation in times )

( PUB/PUB will never fit, for obvious reasons, whereas PUB/SUB and many other behaviour-archetype pairs will and do lovely match and form the mutually-"compatible"-behaviours that will finally go live and stay so )


So,
how do I do the same thing with a Python ZeroMQ socket,
given a machine that has multiple addresses?

Simply use the fully qualified specification in a call to
.bind( "{ tcp | pgm | epgm }://<ip>:<port#>" ) method and you are done.

That easy.

Cool, isn't it?

Many further pleasant surprises under the hood of performance tuning, latency shaving and security tweaking.

Restaurateur answered 7/10, 2017 at 13:14 Comment(2)
This answer is very helpful, but it turns out my question was not quite clear: I need to bind the source ip for the other end of the connection, in the connect method. I've added an answer to that effect and upvoted this.Actinozoan
Glad you have found it helpful. The .connect() works the same way as .bind()-method does. The important and cool thing is, that one [Access Point] can .connect( "tcp://<address>:<port>" ) and also .connect( "vmci://@:<port>" ) and also .connect( "ipc://<address_identifier>" ) and operate all these established connections under the same [Access Point]'s model of a Formal Communication Behaviour. That was the reason to elaborate all details above, to start to realise how different the ZeroMQ-sockets are and what immense powers they bring for advanced distributed systems.Restaurateur
A
1

When trying to .connect() to a remote, I found the answer in the protocol documentation, put the source ip before a semicolon in the connect string:

rc = zmq_connect(socket, "tcp://192.168.1.17:5555;192.168.1.1:5555")

In Python, this looks like:

socket = zmq.Context().socket(zmq.SUB)
socket.connect('tcp://192.168.1.17:5555;192.168.1.1:5555')
Actinozoan answered 24/10, 2017 at 18:26 Comment(1)
A semicolon-separated list expansion is rather a side-effect of the "hidden" API feature of the ZeroMQ core. It functionally creates the same thing as a sequence of calls to the .connect()-method, irrespective whether the first was using a tcp:// transport-class and the other an epgm:// one, as explained above.Restaurateur

© 2022 - 2024 — McMap. All rights reserved.