好的,我发现了问题。在 dhcp.py 的第 200 - 218 行中有一条 try except 语句。我将 cls._parser 拉出尝试查看它抛出的错误,我得到了这个:
Ryuretic_coupler: Exception occurred during handler processing. Backtrace
from offending handler [initial_event] servicing event [EventOFPPacketIn] follows.
Traceback (most recent call last):
File "/home/ubuntu/ryu/ryu/base/app_manager.py", line 290, in _event_loop
handler(ev)
File "/home/ubuntu/ryu/ryu/app/Ryuretic/Ryuretic.py", line 72, in initial_event
pkt = parsPkt.handle_pkt(ev)
File "/home/ubuntu/ryu/ryu/app/Ryuretic/Pkt_Parse13.py", line 81, in handle_pkt
dhcp_p = pkt['dhcp'] = dhcp.dhcp.parser(pkt['pkt'][3])
File "/home/ubuntu/ryu/ryu/lib/packet/dhcp.py", line 212, in parser
return cls._parser(buf)
File "/home/ubuntu/ryu/ryu/lib/packet/dhcp.py", line 192, in _parser
) = struct.unpack_from(unpack_str, buf)
error: unpack_from requires a buffer of at least 233 bytes
所以,dhcp.py 没有收到它需要的 233 个字节。不幸的是,我在 SDN 集线器提供的 VM 上使用 Open vSwitch,128 字节似乎是一个限制。所以,我和 Ryu 的 dhcp.py 文件有冲突。我的解决方案是修改 dhcp.py。以下是如何完成的。
在修改代码之前,我建议你先更新你的 Ryu 控制器。程序如下:
第 1 步:如果您使用的是虚拟机。立即拍摄快照或克隆它。
第 2 步:更新 Ryu
cd ryu
git pull
如果您像我一样运行旧版本,那么当您下次尝试运行 Ryu 控制器时可能会出现以下错误:
Traceback (most recent call last):
File "./bin/ryu-manager", line 18, in <module>
from ryu.cmd.manager import main
File "/home/ubuntu/ryu/ryu/cmd/manager.py", line 31, in <module>
from ryu.base.app_manager import AppManager
File "/home/ubuntu/ryu/ryu/base/app_manager.py", line 37, in <module>
from ryu.controller.controller import Datapath
File "/home/ubuntu/ryu/ryu/controller/controller.py", line 74, in <module>
help='Maximum number of unreplied echo requests before datapath is disconnected.')
File "/usr/local/lib/python2.7/dist-packages/oslo_config/cfg.py", line 1033, in __init__
super(IntOpt, self).__init__(name, type=types.Integer(), **kwargs)
TypeError: __init__() got an unexpected keyword argument 'min'
第 3 步:更新您的 oslo_config 文件
sudo pip install oslo.config --upgrade
现在应该解决步骤 2 中的 TypeError。(希望你克隆了你的虚拟机以防万一。)
第三步:修改 Ryu 的 dhcp.py 文件
Ryu 的 dhcp.py 文件(位于 /ryu/ryu/lib/packet)预计接收超过 235 字节的缓冲区。否则,它会抛出错误并且不向控制器返回任何内容。因为我的缓冲区只接收大约 81 字节的缓冲区大小。我修改了 Ryu dhcp.py 文件如下。
发生错误是因为 dhcp.py 指定的字符串格式为 '!BBBBIHH4s4s4s4s16s64s128s'。在#1 中,我创建了第二个选项。这样做,如果数据包到达时小于 100 字节,我可以插入一些 if 语句以不同方式处理数据包。同样,如果数据包大于 235 字节,则 dhcp.py 会正常处理数据包并返回额外的值。
class dhcp(packet_base.PacketBase):
"""DHCP (RFC 2131) header encoder/decoder class.
....deleted....
"""
_MIN_LEN = 236
_HLEN_UNPACK_STR = '!BBB'
_HLEN_UNPACK_LEN = struct.calcsize(_HLEN_UNPACK_STR)
_DHCP_UNPACK_STR = '!BIHH4s4s4s4s%ds%ds64s128s'
##################################################
#1(mod) Created second option for unpacking string
_DHCP_UNPACK_STR2 = '!BIHH4s4s4s4s%ds%ds40s'
_DHCP_PACK_STR = '!BBBBIHH4s4s4s4s16s64s128s'
#################################################
_DHCP_CHADDR_LEN = 16
_HARDWARE_TYPE_ETHERNET = 1
_class_prefixes = ['options']
_TYPE = {
'ascii': [
'ciaddr', 'yiaddr', 'siaddr', 'giaddr', 'chaddr', 'sname'
]
}
def __init__(self, op, chaddr, options, htype=_HARDWARE_TYPE_ETHERNET,
hlen=0, hops=0, xid=None, secs=0, flags=0,
ciaddr='0.0.0.0', yiaddr='0.0.0.0', siaddr='0.0.0.0',
giaddr='0.0.0.0', sname='', boot_file=b''):
super(dhcp, self).__init__()
#...Deleted No Changes made to init.
@classmethod
def _parser(cls, buf):
(op, htype, hlen) = struct.unpack_from(cls._HLEN_UNPACK_STR, buf)
buf = buf[cls._HLEN_UNPACK_LEN:]
####################################################
#2(mod) provided option for smaller packet sizes
if len(buf) < 100:
unpack_str = cls._DHCP_UNPACK_STR2 % (hlen,
(cls._DHCP_CHADDR_LEN - hlen))
else:
unpack_str = cls._DHCP_UNPACK_STR % (hlen,
(cls._DHCP_CHADDR_LEN - hlen))
#####################################################
min_len = struct.calcsize(unpack_str)
######################################################
#3(mod) provided option for smaller packets, set bootfile to b''
if min_len > 233:
(hops, xid, secs, flags, ciaddr, yiaddr, siaddr, giaddr,
chaddr, dummy, sname, boot_file
) = struct.unpack_from(unpack_str, buf)
else:
boot_file=b''
(hops, xid, secs, flags, ciaddr, yiaddr, siaddr, giaddr,
chaddr, dummy, sname, boot_file
) = struct.unpack_from(unpack_str, buf)+(boot_file,)
########################################################
length = min_len
########################################################
# (mod) provided option for smaller packet sizes, no parse_opt
if len(buf) > 233:
parse_opt = options.parser(buf[min_len:])
length += parse_opt.options_len
else:
parse_opt = None
length = min_len
#########################################################
return (cls(op, addrconv.mac.bin_to_text(chaddr), parse_opt,
htype, hlen, hops, xid, secs, flags,
addrconv.ipv4.bin_to_text(ciaddr),
addrconv.ipv4.bin_to_text(yiaddr),
addrconv.ipv4.bin_to_text(siaddr),
addrconv.ipv4.bin_to_text(giaddr),
sname.decode('ascii'), boot_file),
None, buf[length:])
完整的文件很快就会在https://github.com/Ryuretic/RyureticLabs/tree/master/ryu/ryu/app/Ryuretic/Support_Files上。
如果您对 dhcp.py 文件进行这些调整,那么您将可以访问以下标头字段:
============== ====================
Attribute Description
============== ====================
op Message op code / message type.\
1 = BOOTREQUEST, 2 = BOOTREPLY
htype Hardware address type (e.g. '1' = 10mb ethernet).
hlen Hardware address length (e.g. '6' = 10mb ethernet).
hops Client sets to zero, optionally used by relay agent\
when booting via a relay agent.
xid Transaction ID, a random number chosen by the client,\
used by the client and serverto associate messages\
and responses between a client and a server.
secs Filled in by client, seconds elapsed since client\
began address acquisition or renewal process.
flags Flags.
ciaddr Client IP address; only filled in if client is in\
BOUND, RENEW or REBINDING state and can respond\
to ARP requests.
yiaddr 'your' (client) IP address.
siaddr IP address of next server to use in bootstrap;\
returned in DHCPOFFER, DHserver.
giaddr Relay agent IP address, used in booting via a\
relay agent.
chaddr Client hardware address.
sname(partial) Optional server host name, null terminated string.