pasta behaviour with multiple NICs
Hi everyone, I'm struggling to understand how pasta will behave when the host has multiple network interfaces. I can't see this mentioned in the website or man page. I'm using pasta with podman if that makes a difference. Example Scenario - 2 interfaces - eth0 (with default route) and eth1 in a different subnet. When the podman container is created, inside the container there is a single interface shown that mimics the eth0 interface name, IP, gateway. If traffic is initiated from the container to an IP within the eth1 subnet - how does pasta make it appear to come from the eth1 IP address? Does it automatically apply NAT to achieve this? If the host has a static route for a subnet not directly connected to either eth0 or eth1, but the static route uses a next hop IP address within the eth1 subnet - will pasta apply NAT to the eth1 IP address, and the use the static route to send it via the next-hop router? Thanks in advance. -- From: Ben Woods
Hi Ben,
On Fri, 25 Apr 2025 14:54:18 +0800
"Ben Woods"
Hi everyone,
I'm struggling to understand how pasta will behave when the host has multiple network interfaces. I can't see this mentioned in the website or man page.
Right, yeah, it's not really mentioned anywhere, sorry for that, and thanks for your question.
I'm using pasta with podman if that makes a difference.
It shouldn't make a difference.
Example Scenario - 2 interfaces - eth0 (with default route) and eth1 in a different subnet.
When the podman container is created, inside the container there is a single interface shown that mimics the eth0 interface name, IP, gateway.
If traffic is initiated from the container to an IP within the eth1 subnet - how does pasta make it appear to come from the eth1 IP address? Does it automatically apply NAT to achieve this?
The operating system (unfortunately it's Linux only, so far) takes care of all that, pasta has no idea: it just opens a socket and connect()s it to the destination address (that might be bind() _and_ connect(), for UDP). The kernel then decides based on routing rules and tables. But yes, this typically results in NAT, at least with the default source address selection Linux does. In other words: it's as if your container and everything inside it behaved like a local process, network-wise, as seen from outside. Given that pasta isn't in charge of network (or even transport) headers "outside", it doesn't really "do NAT", but, with default options and a matching upstream interface, it avoids that NAT is done in the bigger picture.
If the host has a static route for a subnet not directly connected to either eth0 or eth1, but the static route uses a next hop IP address within the eth1 subnet - will pasta apply NAT to the eth1 IP address, and the use the static route to send it via the next-hop router?
This also reduces to a question about Linux, essentially. Yes, as far as I know, that would be the outcome: source NAT using a matching address assigned to eth1, if any (preferred source address). Does that answer your question? -- Stefano
Hi Stefano, Thanks for the quick response. I think my questions came from a misunderstanding of how pasta works. I was thinking about the container network namespace directly sending the traffic out the host physical interface based on the IP/gateway inside the netns. Reading your answer, I think I understand now that in fact the network connection from inside the container netns is connected via a socket to pasta running on the host… and then pasta simply creates the TCP or UDP socket connection out the host physical interface using the host network stack. Is that correct? That then explains why you’re saying that pasta itself is not choosing the egress interface, route or source IP… it’s the kernel that does that when pasta creates the TCP/UDP connection. Hence the traffic egress interface, source IP and next-hop should be the same as if it originated from a process on the host. It does make we wonder what’s the purpose of assigning an IP/subnet/gateway inside the container netns at all - if all connections are sent via the socket and host pasta process then creates the actual connection? Cheers, Ben On Fri, 25 Apr 2025, at 3:26 PM, Stefano Brivio wrote:
Hi Ben,
On Fri, 25 Apr 2025 14:54:18 +0800 "Ben Woods"
wrote: Hi everyone,
I'm struggling to understand how pasta will behave when the host has multiple network interfaces. I can't see this mentioned in the website or man page.
Right, yeah, it's not really mentioned anywhere, sorry for that, and thanks for your question.
I'm using pasta with podman if that makes a difference.
It shouldn't make a difference.
Example Scenario - 2 interfaces - eth0 (with default route) and eth1 in a different subnet.
When the podman container is created, inside the container there is a single interface shown that mimics the eth0 interface name, IP, gateway.
If traffic is initiated from the container to an IP within the eth1 subnet - how does pasta make it appear to come from the eth1 IP address? Does it automatically apply NAT to achieve this?
The operating system (unfortunately it's Linux only, so far) takes care of all that, pasta has no idea: it just opens a socket and connect()s it to the destination address (that might be bind() _and_ connect(), for UDP). The kernel then decides based on routing rules and tables.
But yes, this typically results in NAT, at least with the default source address selection Linux does.
In other words: it's as if your container and everything inside it behaved like a local process, network-wise, as seen from outside.
Given that pasta isn't in charge of network (or even transport) headers "outside", it doesn't really "do NAT", but, with default options and a matching upstream interface, it avoids that NAT is done in the bigger picture.
If the host has a static route for a subnet not directly connected to either eth0 or eth1, but the static route uses a next hop IP address within the eth1 subnet - will pasta apply NAT to the eth1 IP address, and the use the static route to send it via the next-hop router?
This also reduces to a question about Linux, essentially. Yes, as far as I know, that would be the outcome: source NAT using a matching address assigned to eth1, if any (preferred source address).
Does that answer your question?
-- Stefano
-- From: Ben Woods ben@woods.am
On Fri, 25 Apr 2025 15:49:16 +0800
"Ben Woods"
Hi Stefano,
Thanks for the quick response.
I think my questions came from a misunderstanding of how pasta works. I was thinking about the container network namespace directly sending the traffic out the host physical interface based on the IP/gateway inside the netns.
Reading your answer, I think I understand now that in fact the network connection from inside the container netns is connected via a socket to pasta running on the host…
Not even via a socket, it's a tap (tuntap) file descriptor: https://passt.top/#pasta-pack-a-subtle-tap-abstraction with all the traffic encapsulated in Ethernet-like frames (Layer-2). We also have a "tap bypass" path but that's for loopback traffic only.
and then pasta simply creates the TCP or UDP socket connection out the host physical interface using the host network stack. Is that correct?
This part is correct, yes.
That then explains why you’re saying that pasta itself is not choosing the egress interface, route or source IP… it’s the kernel that does that when pasta creates the TCP/UDP connection. Hence the traffic egress interface, source IP and next-hop should be the same as if it originated from a process on the host.
Right.
It does make we wonder what’s the purpose of assigning an IP/subnet/gateway inside the container netns at all - if all connections are sent via the socket and host pasta process then creates the actual connection?
Because it makes things transparent (again, by default) which is an advantage for many applications, for example service meshes, or any transport / application protocol that might embed IP addresses in the protocol itself (think of SIP for example). And, albeit with some drawbacks, in general it might also be more intuitive for users. -- Stefano
Ok - I understand now. Thanks for tolerating my newbie questions - I really appreciate your replies. On Fri, 25 Apr 2025, at 4:49 PM, Stefano Brivio wrote:
On Fri, 25 Apr 2025 15:49:16 +0800 "Ben Woods"
wrote: Hi Stefano,
Thanks for the quick response.
I think my questions came from a misunderstanding of how pasta works. I was thinking about the container network namespace directly sending the traffic out the host physical interface based on the IP/gateway inside the netns.
Reading your answer, I think I understand now that in fact the network connection from inside the container netns is connected via a socket to pasta running on the host…
Not even via a socket, it's a tap (tuntap) file descriptor:
https://passt.top/#pasta-pack-a-subtle-tap-abstraction
with all the traffic encapsulated in Ethernet-like frames (Layer-2).
We also have a "tap bypass" path but that's for loopback traffic only.
and then pasta simply creates the TCP or UDP socket connection out the host physical interface using the host network stack. Is that correct?
This part is correct, yes.
That then explains why you’re saying that pasta itself is not choosing the egress interface, route or source IP… it’s the kernel that does that when pasta creates the TCP/UDP connection. Hence the traffic egress interface, source IP and next-hop should be the same as if it originated from a process on the host.
Right.
It does make we wonder what’s the purpose of assigning an IP/subnet/gateway inside the container netns at all - if all connections are sent via the socket and host pasta process then creates the actual connection?
Because it makes things transparent (again, by default) which is an advantage for many applications, for example service meshes, or any transport / application protocol that might embed IP addresses in the protocol itself (think of SIP for example).
And, albeit with some drawbacks, in general it might also be more intuitive for users.
-- Stefano
-- From: Ben Woods ben@woods.am
participants (2)
-
Ben Woods
-
Stefano Brivio