riebl/vanetza

communication between two hosts using socktap and UDP

razr opened this issue · 9 comments

razr commented

I'd like to establish a UDP connection between docker and host both running socktap

This works

# Docker
sudo ./socktap -i eth0 --print-tx-cam

# Host
sudo ./socktap -i docker0 --print-rx-cam

This does not work

# Docker
 ./socktap -l udp -i eth0 --print-tx

# Host
./socktap -l udp -i docker0 --print-rx

However, I see on the receiver side the messages coming from the transmitter:

# Host

sudo tcpdump -nvvvXi docker0 net 239.118.122.97
tcpdump: listening on docker0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
17:46:01.890966 IP (tos 0x0, ttl 1, id 9917, offset 0, flags [DF], proto UDP (17), length 215)
    172.17.0.2.52764 > 239.118.122.97.8947: [bad udp cksum 0x16c0 -> 0x6c56!] UDP, length 187
        0x0000:  4500 00d7 26bd 4000 0111 3c6e ac11 0002  E...&.@...<n....
        0x0010:  ef76 7a61 ce1c 22f3 00c3 16c0 ffff ffff  .vza..".........
        0x0020:  ffff 0242 ac11 0002 8947 1200 1a01 0210  ...B.....G......
        0x0030:  0000 0235 8409 5436 ff02 0000 0024 8000  ...5..T6.....$..
        0x0040:  0151 2050 0080 002d 0100 8000 0242 ac11  .Q.P...-.....B..
        0x0050:  0002 c5a4 2e22 1d11 3b88 06d0 6527 8000  ....."..;...e'..
        0x0060:  0000 0000 0000 07d1 0000 0202 0000 0001  ................
        0x0070:  2e22 005a 56c4 918e 4346 e4ff ffff fc23  .".ZV...CF.....#
        0x0080:  b774 3e00 0001 2000 003f e1ed 0403 ffe3  .t>......?......
        0x0090:  fff4 0043 0100 0000 0000 0000 0000 0000  ...C............
        0x00a0:  0000 0000 0000 0000 0000 0000 0000 0000  ................
        0x00b0:  0000 0000 0000 0000 0000 0000 0000 0000  ................
        0x00c0:  0000 0000 0000 0000 0000 0000 0000 0000  ................
        0x00d0:  0000 0000 0000 00                        .......
riebl commented

I suppose the low-level Ethernet frames in the former case are not filtered and thus receivable by the host. For the UDP-based link layer, we use IP multicast. Possibly some further configuration is required to forward multicast traffic from/to Docker containers?

Maybe binding UDP multicast to the specific IP helps

razr commented

Hi @riebl

I got on the receiver side the multicast packages from 172.17.0.2 to 239.118.122.97.8947 and wondering whether the command I'm using for the UDP communication on the receiver side (./socktap -l udp -i docker0 --print-rx) is correct.
I couldn't find any example apart for the lo interface

./socktap -l udp --mac-address 00:00:00:00:00:01 --print-rx
riebl commented

Hi @razr,

socktap has no --print-rx flag but only --print-rx-cam. Apart from that, your invocation of socktap looks sane.
The IP address 239.118.122.97 is the multicast IP address used for the UDP link layer (see

ip::udp::endpoint multicast(ip::address::from_string("239.118.122.97"), 8947);
). According to moby/moby#23659, IP multicast traffics is tricky with Docker containers.

I have no experience with multicast and docker, but these modifications in udp_link.cpp should work, when more network interaces are present. IP address of the device specified with -i parameter is stored in std::string ip.
You can give it a try if you want.

tx_socket_.open(multicast_endpoint_.protocol());
if(ip.size() != 0){
//select proper tx interface for udp in case there are more
boost::asio::ip::address_v4 local_interface = boost::asio::ip::address_v4::from_string(ip);
boost::asio::ip::multicast::outbound_interface option(local_interface);
tx_socket_.set_option(option);
}
rx_socket_.open(multicast_endpoint_.protocol());
rx_socket_.set_option(ip::udp::socket::reuse_address(true));
rx_socket_.bind(multicast_endpoint_);
rx_socket_.set_option(ip::multicast::enable_loopback(false));
if(ip.size() != 0){
//select rx interface for udp in case there are more
boost::asio::ip::address_v4 local_interface = boost::asio::ip::address_v4::from_string(ip);
rx_socket_.set_option(ip::multicast::join_group(multicast_endpoint_.address().to_v4(), local_interface));
}else{
	rx_socket_.set_option(ip::multicast::join_group(multicast_endpoint_.address()));
}
do_receive();
razr commented

@riebl it looks like that socktap accepts (allow_guessing) partial command line arguments, e.g.

./socktap --print-t

I'm not sure whether it is an expected behavior, this extra line forces strict options:

diff --git a/tools/socktap/main.cpp b/tools/socktap/main.cpp
index de61b871..40c3a4f6 100644
--- a/tools/socktap/main.cpp
+++ b/tools/socktap/main.cpp
@@ -48,6 +48,7 @@ int main(int argc, const char** argv)
             po::command_line_parser(argc, argv)
                 .options(options)
                 .positional(positional_options)
+                .style(po::command_line_style::default_style & ~po::command_line_style::allow_guessing)
                 .run(),
             vm
         );
razr commented

@valt2017 Thanks much for your reply. It is not docker-related, as you have mentioned it is about multiple network interfaces in the system. I have added a route on the host side:

sudo ip route add 239.118.122.97 dev docker0

After that socktap works properly. However, I still do not understand why I need to pass -i on the receiver side

# Docker
./bin/socktap -l udp --print-tx-cam

# Host
./bin/socktap -l udp -i docker0 --print-rx-cam

It looks like the interface is used for the raw sockets only.

riebl commented

@riebl it looks like that socktap accepts (allow_guessing) partial command line arguments, e.g.

Right, obviously a feature I have completely forgotten :-)

@valt2017 binding the multicast sockets to a specific interface sounds reasonable. Can you create a PR for this change please?

OK, I can try it during the weekend.