好的,我发现了问题。在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步:如果您使用的是VM。拍摄快照或立即克隆它。
第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。 (希望你克隆你的VM以防万一。)
第3步:修改Ryu的dhcp.py文件
Ryu的dhcp.py文件(位于/ ryu / ryu / lib / packet)期望接收超过235字节的缓冲区。否则,它抛出并发生错误并且不向控制器返回任何内容。由于我的缓冲区只接收大约81字节的缓冲区大小。我修改了Ryu dhcp.py文件,如下所示。
发生此错误是因为dhcp.py指定字符串格式为'!BBBBIHH4s4s4s4s16s64s128s'。在#1中,我创建了第二个选项。这样做,允许我插入一些if语句,以便在数据包到达小于100字节时以不同方式处理数据包。同样,如果数据包大于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.