尽管有多个套接字,但所有接口都未被使用

All interfaces not being used despite multiple sockets

尽管将两个 UDP 套接字绑定到主机不同接口上的 2 个不同地址,但流量流经单个接口。

网络拓扑图如下: 2 links 在 h2 和 s1 之间 1 link 在 h1 和 s1

之间
 ________
|        |
h2       s1_______h1
|________|

我正在 mininet 上模拟 2 台主机和一台交换机。 h1 是 运行 位于 10.0.0.1:4243 的 UDP 服务器。另一台主机有 2 个接口,ips 10.0.0.2 & 10.0.0.4。我在 h2 上制作 2 个套接字,将一个绑定到 (10.0.0.2,9999),另一个绑定到 (10.0.0.4,8888)。我是 运行 下面的代码,它应该在两个接口上交替发送数据包。

而是在两个接口上发送第一个数据包。所有后续数据包都通过单个接口发送。

客户代码(运行 on h2)

def client():
    sock1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock1.bind(("10.0.0.2",9999))

    sock2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock2.bind(("10.0.0.4",8888))

    while True:
        text = 'The time is {}'.format(datetime.now())
        data = text.encode('ascii')

        sock1.sendto(data, ('10.0.0.1', 4243))
        data, address = sock1.recvfrom(MAX_BYTES)

        sock2.sendto(data, ('10.0.0.1', 4243))
        data, address = sock2.recvfrom(MAX_BYTES)

服务器代码(运行 on h1)

def server():
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.bind(('10.0.0.1', 4243))
    print('Listening at {}'.format(sock.getsockname()))
    while True:
        data, address = sock.recvfrom(MAX_BYTES)
        text = data.decode('ascii')
        print('The client at {} says {!r}'.format(address, text))
        text = 'Your data was {} bytes long'.format(len(data))
        data = text.encode('ascii')
        sock.sendto(data, address)

一个数据包通过h2 的两个接口发送。随后的数据包都仅通过 IP 10.0.0.2 的接口发送和接收。在 wiresharking 上,一半的数据包将 src/dest IP 设置为 10.0.0.4

根据您的评论,这是我认为正在发生的事情:

  1. 您有冲突的默认路由
  2. 您已 ip_forwarding 启用允许内部路由
  3. 由于 #1 和 #2
  4. ,绑定调用实际上被否定了

冲突的默认路由

根据您的评论,这两个接口可能都有一个 /8。这意味着对于 h2,内核会为两者添加相同的路由,例如:

10.0.0.0/8 dev h2-eth0 proto kernel scope link src 10.0.0.2 
10.0.0.0/8 dev h2-eth1 proto kernel scope link src 10.0.0.4 

这意味着内核只想选择其中一个来发送所有 10.0.0.0/8 流量 to/from。您试图通过绑定调用来解决这个问题,但我不相信绑定会覆盖路由 table 行为。

ip_forwarding

如果设置了这个标志,它也会使事情复杂化,因为它可能允许通过 eth0 的 eth1 流量。

绑定

因此,将所有这些放在一起,您将套接字绑定到与各个接口关联的各个 IP,但内核只想将发往 10.0.0.1 的流量路由到一个接口,它选择了 eth0。我认为通常这会阻止 eth1 流量,但由于路由和 ip_forward 标志,eth1 流量通过 eth0 路由(在初始 ARP 数据包之后,您看到的那个数据包)。

解决方案

给h1的接口两个IP地址10.1.0.1/16和10.0.0.1/16。然后给h2-eth0 ip地址10.0.0.2/16和h2-eth1 ip地址10.1.0.2/16。然后让您的程序从 10.1.0.2 向 10.1.0.1 发送数据,从 10.0.0.2 向 10.0.0.1 发送数据。

通过隔离子网,您将防止混淆的根本原因,即路由冲突。