Wednesday, October 6, 2010

broadcast

很少使用UDP协议和原始数据包, 所以对broadcast这种特殊地址使用不多。
知识总是关联在一起的。今天在看LVS-DR模式的配置时,发现对下面的配置有些不理解:

# ifconfig lo:0 IP_Adress broadcast IP_Adress netmask 255.255.255.255 up
# route add -host IP_Adress dev lo:0
 * IP_Adress为IP地址

如果只是为了配置LVS的话,就不需要理会上面的语句背后的原理,但作为技术控,很希望可以知道它背后后原理。

結果发现背后是好大一个坑,最经典的问题就是LVS的ARP问题:
 * http://www.austintek.com/LVS/LVS-HOWTO/HOWTO/LVS-HOWTO.arp_problem.html
都与broadcast有关系. 先对broadcast下手:

为什么 broadcast与IP_Adress相同, 而不是常用的172.16.2.255这种特殊IP?
首先, broadcast有如下几种:
1. layer 2 broadcast
2. layer 3 broadcast
3. unicast
4. multicast

要知道broadcast的作用是"一对多", 一台机器发出的数据多台机器有兴趣接收. 这种特点是TCP协议没有的.
下面使用UDP协议来举个layer 3的例子:
接收端(调用bind函数), 这一端的机器可以多台:
import socket
import sys
x = ('<broadcast>', 51423)

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.bind(x)
(buf, address) = s.recvfrom(2048)
s.sendto("Hi", address)

发送端(调用send函数):
import socket
import sys
x = ('<broadcast>', 51423)

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.sendto("Hi", x)
(buf, address) = s.recvfrom(2048)
print "Received from %s: %s" % (address, buf)

send端使用的'<broadcast>' 很另类: 不是使用具体的IP地址, 而是使用代名词.
回到上面的ifconfig例子, 这个'<broadcast>' 其实就是NIC里的broadcast参数.
如果NIC的参数不同, '<broadcast>' 代表的意义就不同.
从发送端看:
send函数发出的数据包里的destination地址为'<broadcast>'
从接收端看:
recvfrom函数只接收destination地址为NIC里'<broadcast>' 参数的广播包.

所以, 上面的ifconfig设置明显是不想服务器接收layer 3的广播信息( 例如destination为192.168.0.255这种数据包)
从netmask的角度可以这样思考:
ifconfig lo:0 192.168.0.10 broadcast 192.168.0.10 netmask 255.255.255.255可以变形成ifconfig lo:0 192.168.0.10 netmask 255.255.255.255
它们与
ifconfig lo:0 192.168.0.10 netmask 255.255.255.0
是属于不同的subnet, 所以192.168.0.0/24的信息对于网段192.168.0.0/32是不会接收的
这种单一的广播地址被称为 unicast
broadcast还有layer 2的. 典型的例子就是arp协议. 使用的以太网广播地址: FF.FF.FF.FF.FF.FF 作为destination

linux下没有CLI接口的命令可以发出arp请求包. 因为arp功能放在kernel中(可以看手册man 7 arp), layer 3的数据压到layer 2时kernel为自动调用arp请求包(如果是需求的话).
如果要手动发出这种请求也是可以的, 比如这段代码: http://svn.pythonfr.org/public/pythonfr/utils/network/arp-flood.py

当ping一个IP时, 系统的arp表示里没有与IP对应的条目时kernel是会发出arp请求包的, 所以为了测试, 可以在清除arp条目的情况下,在两机之间ping对方.
如下代码:
import socket
soc = socket.socket(socket.PF_PACKET, socket.SOCK_RAW) #create the raw-socket
soc.bind(("wlan0",0x0806)) # ether type for ARP
data = soc.recv(1024)

程序属于接收端, 程序运行后会一直block, 直到接收到一个arp请求. 向子网的所有机器询问的MAC, 所以是"一对多", 这时就需要使用到广播地址, layer 2的广播地址为FF.FF.FF.FF.FF.FF.

与layer 3相比, layer 2的广播地址不是在NIC上配置的, 但是LVS-DR模式又希望real server不要响应和发出arp请求, 于是, LVS-DR的arp问题就产生了. 也就是文章开头的route add命令的原理. 至于这个原理这里就不写了. 认真阅读下面的文章即可, 下面的文章涉及了linux kernel的多个版本, 如2.0.x, 2.2.x, 2.6.x.
http://www.austintek.com/LVS/LVS-HOWTO/HOWTO/LVS-HOWTO.arp_problem.html

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.