Ok, I found the problem. In lines 200 – 218 of dhcp.py there is a try except statement. I pulled the cls._parser out of the try to see the error it throws and I get this:
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
So, dhcp.py is not receiving the 233 bytes that it requires. Unfortunately, I am using an Open vSwitch on the VM provided by SDN hub, and 128 bytes seems to be a limit. So, I have a conflict with Ryu's dhcp.py file. My solution was to modify dhcp.py. How that was done follows.
Before modifying the code, I recommend you first update your Ryu controller. The procedures are as follows:
Step 1: If you are using a VM. Take a stapshot or clone it now.
Step 2: Update Ryu
cd ryu
git pull
If you were running an older version like I was, then the following error may occur when you next attempt to run your Ryu controller:
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'
Step 3: Update your oslo_config file
sudo pip install oslo.config --upgrade
The TypeError from step 2 should now be resolved. (Hopefully, you cloned your VM just in case.)
Step 3: Modify Ryu's dhcp.py file
Ryu's dhcp.py file (located at /ryu/ryu/lib/packet) expects to receive a buffer of more than 235 bytes. Otherwise, it throws and error and returns nothing to the controller. Since my buffer only receives a buffer size of about 81 bytes. I modified the Ryu dhcp.py file as follows.
The error occurs because dhcp.py specifies a string format of '!BBBBIHH4s4s4s4s16s64s128s'. In #1, I created a second option. Do so, allows me to insert a few if statements to handle the packet differently if a packet arrives that is smaller than 100 bytes. Likewise, if the packet is greater than 235 bytes, then dhcp.py's handles the packet normally and returns the extra values.
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:])
The complete file will soon be on https://github.com/Ryuretic/RyureticLabs/tree/master/ryu/ryu/app/Ryuretic/Support_Files.
If you make these adjustements to the dhcp.py file, then you will gain access to the following header fields:
============== ====================
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.