docker multiple containers with static addresses - static

I am working on a project usually implemented with VMs. But I would like to hack with docker containers instead, in order to practice and learn something new.
So here is what I would like to do : create several containers running on the same host, with static ip addresses, connected one to each others (but not necessarily connected to the outside world).
In other words, I would like emulate kind of a stand alone network, composed of several computers connected to the same switch.
I tried to change /etc/network/interfaces in containers to set static ip addresses for eth0, docker0, ... But it doesn't affect the system in any way. I tried to use --net=host, --cap-add=NET_ADMIN but it didn't help.
It's driving me crazy. SOS!
Thanks
EDIT :
Important stuff I didn't say : I'm using my Mac Book Air, and I am running boot2docker (which creates a VM running docker).
When I run an image with "docker run -i -t ubuntu /bin/bash", I don't have docker0 as an interface : running "ip a" in the container displays only lo and eth0.

Why did you try --net=host? This option disables network isolation at all, and runs container in default network namespace. This means that docker containers can see all host network interfaces. I think this is not your option.
There is important to tell, how docker deals with isolated networks. First of all, it creates bridge named docker0 (at least by default). Each time when you starting container with isolated network (i.e., without --net=host), docker creates a pair of veth interfaces. One of this interface docker gives to container (if you'll run ip link list in your container, you will see exactly this virtual interface). Another one docker plugs in bridge docker0 (by the way, you can say which bridge to use by passing "-b ${BRIDGE}" option to docker daemon).
I'd recommend you to read article about docker bridges and this one about network namespaces.
Try to run containers with isolated networking, and then assign static IP that you like. But be aware of routing - host must have route to subnet, where your containers running. Easiest way to do this (and the only adequate as for me) - assign to you containers IP from same subnet as docker bridge.
Following example works well for me.
user#host$ ip addr
docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff
inet 172.17.42.1/16 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::5484:7aff:fefe:9799/64 scope link
valid_lft forever preferred_lft forever
root#docker-1# ip addr
eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:2/64 scope link
valid_lft forever preferred_lft forever
root#docker-2# ip addr
eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 02:42:ac:11:00:05 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.3/16 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:5/64 scope link
valid_lft forever preferred_lft forever

Related

Can DPDK selectively init NIC ports

I'm using an dual-port NIC, Mellanox ConnectX-5, and the DPDK version is dpdk-stable-19.11.3. After configuration, the call of rte_eth_dev_count_avail() returns 2. But only one port of my ConnectX-5 NIC is connected to the other machine. All I can find is to init all available ports like this.
RTE_ETH_FOREACH_DEV(portid)
if (port_init(portid, mbuf_pool) != 0)
rte_exit(EXIT_FAILURE, "Cannot init port %u\n", portid);
Can dpdk selectively init ports? Or is there any way to make rte_eth_dev_count_avail() returning 1?
Another quick way to assign a particular port out all available ports to DPDK application by using DPDK tool dpdk-devbind.py and EAL port initialization will pick port which is assigned to UIO/VFIO kernel driver. Below are devbind script steps to identify port current status and how to bind required port to DPDK.
[root#linux usertools]# ./dpdk-devbind.py --status
Network devices using kernel driver
===================================
0000:00:03.0 '82540EM Gigabit Ethernet Controller 100e' if= drv=e1000 unused=vfio-pci
0000:00:04.0 '82540EM Gigabit Ethernet Controller 100e' if= drv=e1000 unused=vfio-pci
[root#linux usertools]# ./dpdk-devbind.py --bind=vfio-pci 00:04.0
[root#linux usertools]# ./dpdk-devbind.py --status
Network devices using DPDK-compatible driver
============================================
0000:00:04.0 '82540EM Gigabit Ethernet Controller 100e' drv=vfio-pci unused=e1000
Network devices using kernel driver
===================================
0000:00:03.0 '82540EM Gigabit Ethernet Controller 100e' if= drv=e1000 unused=vfio-pci
[EDIT-1] based on the updated question from author, the request is identify from the available DPDK ports which is connected? as mentioned above answer one needs to use rte_eth_link_get
Yes one can selectively init ports by passing the right PCIe Bus:Device:Function address as a whitelist. Hence only desired ports will pop up in the application.
How to do it:
create a dummy application to take in all DPDK port.
Initialize and start the dpdk ports. Check for link-state and create port-mask (global variable) which filters in application logic.
Invoke rte_eth_dev_stop & rte_eth_dev_close for link down ports.
Invoke rte_eal_cleanup.
Use the port-mask, as an argument for execv to invoke your desired DPDK application.
this way you can run your application with valid ports to it.
But relying on rte_eth_link_get is tricky because
if the other end is connected to dpdk-pktgen, first your DPDK application has to init the NIC locally.
if connected to linux box, the nic has to be bought up first with ifconfig [other nic] up
at times one needs to check link.link_speed if its valid.
certain PMD needs write to PCIe mapped register, hence has to dev_configure and port_init to get a reliable reading for link status.
Hence safest and recommended way to use is identify the NIC PCIe B:D:F in Linux driver and then whitelist the ports by using option -w for the desired port under igb_uio/virtio-pci. This can be done by bind all NIC back in linux by
lshw -c network -businfo will list NIC and PCIe Bus:Device:Function with kerel device name and driver.
use ethtool [eth device name] | grep Link to identify the link is connected.
for reference, you can use https://github.com/vipinpv85/DPDK-APP_SAMPLES/blob/master/auto-baseaddr-selector.c as template for dummy applciation.

How to prevent the ip address of hyper-v virtual switch from being changed?

I have a laptop with Windows 10 2004 installed. I configureded Hyper-V and created two VMs: On one VM runs windows 10 to enclose serveral malware IM softwares which I have to use for working contacts. On the other VM runs ubuntu server 20.04 for development.
I configured Hyper-V with a virtual switch of type internal network and Hyper-V automatically specified the virtual switch with a static IP. I want to connect to ubuntu with machine name. So I specified ubuntu VM with a static IP and added an item in the hosts file of the host windows 10. Then I can use the remote over SSH feature of VS Code to develop node.js app in windows 10 host. Everything went ok till I had restarted my laptop.
After I have restarted the laptop, the IP address of the hyper-v virtual switch was changed. I couldn't reconnect to VM ubuntu any more because the VM ubuntu was configured with a static IP and default gateway based on the old IP of the virtual switch.
I checked the IPv4 properties of the virtual switch via UI, It's configured as "using the following IP", so I thought of the IP shouldn't change. But I was wrong. Each time after my laptop being restarted, the "static IP" of virtual switch always changes. This change breaks the connection to VM ubuntu.
So, is there any way to prevent the IP address of the virtual switch from being changed? Or some way to add name resolving mechanism to Hyper-V virtual switch (then I can configure using dynamic IP address in VMs)?
I just added an additional Internal switch via Hyper-V "Virtual Switch Manager" and gave it a name of "Static Switch". Then changed it's settings via Control Panel->Network and Internet->Network and Sharing Center->Change adapter settings. Right click on the new adapter and select Properties->Internet Protocol Version 4 (TCP/IPv4) and set a static IP that is not currently used on your network, for example IP address: 192.168.199.1 Subnet mask: 255.255.255.0. No other settings are required. Click Ok and close all the parent windows.
Add the new nic to the Hyper-V machine via the settings for the VM, Add Hardware->Network Adapter-Add. Select the 'Static Switch' and click OK.
Edit your client virtual machine network settings, in my case Ubuntu 20.10 so it's Wired Settings for eth1 (the new 'Wired Connection'). I disabled IPv6 and edited the IPv4 settings using a manual configuration (static IP) setting the IP address to 192.168.199.2 and a net mask of 255.255.255.0 and a gateway of 192.168.199.1 (The 'Static Switch'). No other settings are required. Click Apply and check that the network eth1 is connected.
You should be able to ping 192.168.199.1 from the client VM and ping 192.168.199.2 from the host machine.
This configuration will persist after a reboot and you can edit your hosts file on the host machine with whatever name you want, eg 192.168.199.2 my.vm.machine
Note: You will need to edit the hosts file as an administrator.
Don't use the default switch created by Hyper-V. As Miket25 said: "The default switch is made by HNS, and there may be settings that causes it to have a DHCP address on reboot".
Create a internal virtual switch using NAT annually. Here is the guide. And then connect VMs to this switch. The static IP address assigned to this switch will not be changed through rebooting.
Setting Static IP address in Ubuntu in Hyperv
Note: VM(s) are connected on "External Switch" in Hyperv
Check DNS IP address VM uses
gtan#master:~$ systemd-resolve --status
...
Link 2 (eth0)
Current Scopes: DNS
LLMNR setting: yes
MulticastDNS setting: no
DNSSEC setting: no
DNSSEC supported: no
DNS Servers: 192.168.141.81
DNS Domain: mshome.net
Check Gateway and Subnet Mask
gtan#master:/etc/netplan$ netstat -r
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
default _gateway 0.0.0.0 UG 0 0 0 eth0
10.44.0.0 0.0.0.0 255.255.255.0 U 0 0 0 cni0
10.44.1.0 10.44.1.0 255.255.255.0 UG 0 0 0 flannel.1
10.44.2.0 10.44.2.0 255.255.255.0 UG 0 0 0 flannel.1
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 br-894a4759cb12
172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
192.168.141.80 0.0.0.0 255.255.255.240 U 0 0 0 eth0
_gateway 0.0.0.0 255.255.255.255 UH 0 0 0 eth0
eth0 Gateway = 192.168.141.81 mask 255.255.255.240 (192.168.141.80 is for broadcast)
Check eth0 IP address and subnet mask
gtan#master: ifconfig
...
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.141.85 netmask 255.255.255.240 broadcast 192.168.141.95
inet6 fe80::215:5dff:fe3a:1100 prefixlen 64 scopeid 0x20<link>
ether 00:15:5d:3a:11:00 txqueuelen 1000 (Ethernet)
RX packets 82792 bytes 103449317 (103.4 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 40353 bytes 10745111 (10.7 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
...
Edit "/etc/netplan/01-netcfg.yaml" to this (make a backup of the orginal 01-netcfg.yaml first: "sudo cp ./01-netcfg.yaml ./01-netcfg.yaml.bak"):
network:
version: 2
renderer: networkd
ethernets:
eth0:
dhcp4: no
addresses:
- 192.168.141.85/28
gateway4: 192.168.141.81
nameservers:
addresses: [8.8.8.8]
Shutdown the VM
In Hyperv, select the VM(s):
Go to Network Adaptor --> Advanced Features --> Set MAC address to "static"
All good to go!!!
After work, use "saved" instead of "paused" for the VMs'

Can u-boot support more than one ethernet port?

I want to ping out of multiple ethernet ports. Is there an inherent restriction where u-boot only supports a single ethernet port?
Can u-boot support more than one ethernet port?
Yes, in recent versions of U-Boot (going back to at least 2012.10).
Salient code is eth_current_changed() and eth_set_current() in net/eth.c.
Is there an inherent restriction where u-boot only supports a single ethernet port?
No, recent versions of U-Boot can support more than one Ethernet port on the board.
When more than one Ethernet interface is available (as reported by the "Net" device list on startup, e.g. "Net: macb0, gmac0, usb_ether"), the environment variable ethact is used to define the selected Ethernet interface that is active.
Use the printenv ethact command to view the current selection.
Use the setenv ethact <port name> to change the active Ethernet port.
The U-Boot network commands, such as ping and tftpboot, will use the Ethernet port defined by the ethact variable. This preserves the command syntax with older versions of U-Boot, and the syntax is consistent regardless of the number of available ports (e.g. scripts do not change).
Each Ethernet port is assigned its own MAC address, using the following environment variables:
ethaddr: Ethernet MAC address for first/only ethernet interface (= eth0 in Linux).
This variable can be set only once (usually during manufacturing of the board). U-Boot refuses to delete or overwrite this variable once it has been set.
eth1addr: Ethernet MAC address for second ethernet interface (= eth1 in Linux).
eth2addr: Ethernet MAC address for third ethernet interface (= eth2 in Linux).
Obviously you can only (easily) access one port at a time.
There is also only one static IP address assignment, i.e. the ipaddr environment variable.
(I don't know what happens with an IP address acquired by DHCP using one port, and then the active port is changed.)
U-Boot> printenv ethact
ethact=macb0
U-Boot> setenv ethact gmac0
U-Boot> ping 192.168.1.1
gmac0: PHY present at 7
gmac0: Starting autonegotiation...
gmac0: Autonegotiation complete
gmac0: link up, 1000Mbps full-duplex (lpa: 0x2800)
Using gmac0 device
host 192.168.1.1 is alive
U-Boot>
Note that there also a rotation scheme that automatically changes the active port when the ports are down:
U-Boot> printenv ethact
ethact=gmac0
U-Boot> ping 192.168.1.1
gmac0: PHY present at 7
gmac0: Starting autonegotiation...
gmac0: Autonegotiation timed out (status=0x7949)
gmac0: link down (status: 0x7949)
ERROR: Need valid 'usbnet_devaddr' to be set
at drivers/usb/gadget/ether.c:2362/usb_eth_init()
macb0: PHY present at 0
macb0:0 is connected to macb0. Reconnecting to macb0
macb0: Starting autonegotiation...
macb0: Autonegotiation timed out (status=0x7849)
macb0: link up, 100Mbps full-duplex (lpa: 0x41e1)
Using macb0 device
ping failed; host 192.168.1.1 is not alive
U-Boot> printenv ethact
ethact=macb0
U-Boot>

Multicast listening and interface IP address change

I am binding to a multicast group and port to listen a multicast stream. Since adding the group membership (via IP_ADD_MEMBERSHIP) requires specifying a specific network interface, what will happen when that interface IP address changes?
Do I have start again with a new socket and add membership? This is related to Linux/C environment. I do see some packets comming in without changing IP, but I feel I have to restart.
thanks,
gl
The Linux kernel appears to be tracking the interface based on the interface identifier rather than the interface IP address. From a couple of experiments, it looks like your application won't need to have any special handling
Experiment 1: Host Receiving
Here's an experiment I put together with Ubuntu to test if the host will continue to receive across the interface IP change.
$ uname -a
$ Linux joel-VirtualBox 3.16.0-34-generic #47-Ubuntu SMP Fri Apr 10 18:02:58 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
I have a simple Python test script for running a multicast receiver on a network interface eth2, identified by static IP 192.168.33.11:
import socket
import struct
sock = socket.socket( socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP )
sock.bind( ('',50400) )
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton('239.254.2.4') + socket.inet_aton('192.168.33.11') )
while True:
print sock.recv( 2048 )
sock.close( sock )
Once running the python script, I can verify the membership by running:
$ netstat -gn
lo 1 224.0.0.1
eth0 1 224.0.0.251
eth0 1 224.0.0.1
eth1 1 224.0.0.1
eth2 1 224.0.0.251
eth2 1 239.254.2.4
eth2 1 224.0.0.1
From another PC, I ran a multicast sender, sending to 239.254.2.4:50400 and verified the data is printed. I then changed the static IP to 192.168.33.12 and verified the membership is still reported by netstat and my python script can continue to receive data.
Experiment 2: IGMP Membership Reports
I put another experiment together to see what happens to the IGMP membership reports:
As you can see when the change of IP address happens, no new IGMP report for 239.254.2.4 is generated. But when the script is killed, an IGMP Leave message is sent.
This could be considered "a hole" though any switch or router that is performing IGMP snooping or multicast routing will be periodically issuing IGMP queries. Our host will respond to this query by sending its current memberships (including the membership for 239.254.2.4).
I don't think you have to rejoin the group. Both the localhost and the router only have a count of members, and in both cases if it's non-zero it will deliver the multicast internally. But I could be wrong.

what is interface in socket programming?

"INADDR_ANY binds the socket to all available interfaces."
This is the statement i Encountered.I found it here
What is interface here? Is it a port number or something else?
And another question is
Is interface and channel or one and same?
Usually your host (your computer) has more than one interfaces. For example, (older) computer without network would have only IPv4 loopback interface.
If you add and configure IPv4 network to that PC, you'll get another interface: eth0, or net0 or something similar.
When you install VPN, it will create you yet another interface, as instead of sending packets into unsecured network, you send it into logical VPN interface, and that one forwards data to eth0 after some processing.
Every time, when you add a hardware link (with driver) to a network, or create logical network, it creates you a new interface. For example, if you use VMVare, and create virtual machine, the system would provider you some set of interfaces needed to route data between your host, network, and virtual machine.
When routing IPv4, every interface is assigned IPv4 address. Even loopback (127.0.0.1). The address can be static, or obtained from server when your system boots.
So you can listen only on one interface. For example, if you bind to loopback, you will not be able to access any network, and network hosts will not be able to access your socket (assuming routing is not broken). But you connect multiple processes on your host to each other.
If you bind to particular network interface, it means you want to work with systems, that are connected to that network (directly or indirectly).
If you bind to any, for server sockets it means you let system to accept connections from anywhere, considering that anywhere can ping you.
As per my understanding the socket interface is something like this
Gives a file system like abstraction to the capabilities of the
network.
Each transport protocol offers a set of services. The socket API
provides the abstraction to access these services
The API defines function calls to create, close, read and write
to/from a socket.
Also something like this also
A network interface is the point of interconnection between a computer and a private or public network. A network interface is generally a network interface card (NIC), but does not have to have a physical form. Instead, the network interface can be implemented in software.
For example, the loopback interface (127.0.0.1 for IPv4 and ::1 for IPv6) is not a physical device but a piece of software simulating a network interface. The loopback interface is commonly used in test environments
Examples for interfaces:
your LAN card where you can plug a network cable,
a wifi adapter,
a (software-only) thing which provides an imaginary network between your main system and a virtual machine
the (software-only) loopback adapter which sends everything you send to it "back" to your own computer
etc. If you´re writing a socket server, you can choose
where the client connections may come from.
Only from a virtual machine, but no real computer outside?
Only wifi, but no cable-bound LAN? Or just all together?

Resources