You don't need usage of macvlan in your case.
- Assign addresses on single interface. Aliases are deprecated way to have multiple addresses on same interface. You need macvlan only if you want have various mac addresses for various ip addresses, but it complicates the configuration of routing.
l1:~# ip link set up dev eth0
l1:~# ip address add 172.17.1.14/21 dev eth0
l1:~# ip address add 172.17.1.15/21 dev eth0
l1:~# ip address add 172.17.1.16/21 dev eth0
- Verify list of addresses on the
eth0
interface:
l1:~# ip -4 a ls dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
inet 172.17.0.14/21 scope global eth0
valid_lft forever preferred_lft forever
inet 172.17.0.15/21 scope global secondary eth0
valid_lft forever preferred_lft forever
inet 172.17.0.16/21 scope global secondary eth0
valid_lft forever preferred_lft forever
- Add the default route and the default source address, then verify configuration:
l1:~# ip route add 0/0 via 172.17.0.1 src 172.17.0.14
l1:~# ip route list
default via 172.17.0.1 dev eth0 src 172.17.0.14
172.17.0.0/21 dev eth0 proto kernel scope link src 172.17.0.14
- You have two ways to use the secondary addresses for specific destination. You can add the route to a particular destination with specifying src attribute:
Use 172.17.0.15
as source address for 192.168.10.2
destination
l1:~# ip route add 192.168.10.2 via 172.17.0.1 src 172.17.0.15
Use 172.17.0.16
as source address for 192.168.11.2
destination
l1:~# ip r add 192.168.11.2 via 172.17.0.1 src 172.17.0.16
Verify the routing table:
l1:~# ip r ls
default via 172.17.0.1 dev eth0 src 172.17.0.14
172.17.0.0/21 dev eth0 proto kernel scope link src 172.17.0.14
192.168.10.2 via 172.17.0.1 dev eth0 src 172.17.0.15
192.168.11.2 via 172.17.0.1 dev eth0 src 172.17.0.16
Also you can check the actual routes for a specific destination with ip route get
command:
l1:~# ip route get 192.168.10.2
192.168.10.2 via 172.17.0.1 dev eth0 src 172.17.0.15 uid 0
cache
There is a short version of same command:
l1:~# ip r g 192.168.11.2
192.168.11.2 via 172.17.0.1 dev eth0 src 172.17.0.16 uid 0
cache
Check the results with ping
and tcpdump
. Ping the hosts and check the output of tcpdump in an other console. You can use the wireshark instead tcpdump.:
l1:~# tcpdump -ni eth0 'icmp'
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
10:21:07.972535 IP 172.17.0.14 > 172.17.0.1: ICMP echo request, id 23048, seq 0, length 64
10:21:07.974416 IP 172.17.0.1 > 172.17.0.14: ICMP echo reply, id 23048, seq 0, length 64
10:21:15.391709 IP 172.17.0.15 > 192.168.10.2: ICMP echo request, id 23304, seq 0, length 64
10:21:15.393515 IP 192.168.10.2 > 172.17.0.15: ICMP echo reply, id 23304, seq 0, length 64
10:21:18.207461 IP 172.17.0.16 > 192.168.11.2: ICMP echo request, id 23560, seq 0, length 64
10:21:18.209391 IP 192.168.11.2 > 172.17.0.16: ICMP echo reply, id 23560, seq 0, length 64
- Other way is usage the
SNAT
target in the iptables. But if you have the hundreds of similar rules, it may impact the performance.
l1:~# iptables -t nat -A POSTROUTING \
-o eth0 --dst 192.168.10.2 \
-j SNAT --to-source 172.17.0.15
l1:~# iptables -t nat -A POSTROUTING \
-o eth0 --dst 192.168.11.2 \
-j SNAT --to-source 172.17.0.16
Better use the iptables-save
and iptables-apply
to safe configure the iptables. Verification is the same as in the route case - with ping
and tcpdump
. Also, you can check the rule counters to sure those rules work.
l1:~# iptables-save -c -t nat
# Generated by iptables-save v1.6.2 on Wed May 15 10:31:26 2019
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [4:336]
:POSTROUTING ACCEPT [0:0]
[2:168] -A POSTROUTING -d 192.168.10.2/32 -o eth0 -j SNAT --to-source 172.17.0.15
[2:168] -A POSTROUTING -d 192.168.11.2/32 -o eth0 -j SNAT --to-source 172.17.0.16
COMMIT
# Completed on Wed May 15 10:31:26 2019
- There is the third way to use the specific source. In some applications you can specify the source in a configuration file or with command line arguments. For
ping
this is -I
option:
l1:~# ping -c 2 -I 172.17.0.15 192.168.11.2
PING 192.168.11.2 (192.168.11.2) from 172.17.0.15: 56 data bytes
64 bytes from 192.168.11.2: seq=0 ttl=63 time=2.348 ms
64 bytes from 192.168.11.2: seq=1 ttl=63 time=1.270 ms
--- 192.168.11.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 1.270/1.809/2.348 ms
l1:~# tcpdump -ni eth0 'icmp'
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
10:37:08.724723 IP 172.17.0.15 > 192.168.11.2: ICMP echo request, id 37384, seq 0, length 64
10:37:08.726805 IP 192.168.11.2 > 172.17.0.15: ICMP echo reply, id 37384, seq 0, length 64
10:37:09.724985 IP 172.17.0.15 > 192.168.11.2: ICMP echo request, id 37384, seq 1, length 64
10:37:09.726084 IP 192.168.11.2 > 172.17.0.15: ICMP echo reply, id 37384, seq 1, length 64
- Also, you should know, what neither
ip route
or iptables
know nothing about domain-names and can use only ip address of destination. Iptables can resolve domain-name at rule creation, but ip address in it won't being updated magically. There are some tricks to avoid this limitation:
- Fix the ip address associated with domain-name. You can use the
/etc/hosts
file to do it. This way suitable for quick tests and DNS records with long TTL.
- Most flexible way: usage of
dnsmasq
, ipset
and iptables
. In this case dnsmasq
resolves the domain-names and stores its ip addresses into ipset
lists. You can use these lists in the iptables
SNAT
rules.