(一)定义action,修改ofproto_v1_3.py
# enum ofp_action_type
OFPAT_OUTPUT = 0 # Output to switch port.
OFPAT_COPY_TTL_OUT = 11 # Copy TTL "outwards" -- from
# next-to-outermost to outermost
OFPAT_COPY_TTL_IN = 12 # Copy TTL "inwards" -- from outermost to
# next-to-outermost
OFPAT_SET_MPLS_TTL = 15 # MPLS TTL.
OFPAT_DEC_MPLS_TTL = 16 # Decrement MPLS TTL
OFPAT_PUSH_VLAN = 17 # Push a new VLAN tag
OFPAT_POP_VLAN = 18 # Pop the outer VLAN tag
OFPAT_PUSH_MPLS = 19 # Push a new MPLS tag
OFPAT_POP_MPLS = 20 # Pop the outer MPLS tag
OFPAT_SET_QUEUE = 21 # Set queue id when outputting to a port
OFPAT_GROUP = 22 # Apply group
OFPAT_SET_NW_TTL = 23 # IP TTL.
OFPAT_DEC_NW_TTL = 24 # Decrement IP TTL.
OFPAT_SET_FIELD = 25 # Set a header field using OXM TLV format.
OFPAT_PUSH_PBB = 26 # Push a new PBB service tag (I-TAG)
OFPAT_POP_PBB = 27 # Pop the outer PBB service tag (I-TAG)
OFPAT_PROB_DROP = 29 # probdrop packet 新增这里
OFPAT_EXPERIMENTER = 0xffff
# struct ofp_action_header
OFP_ACTION_HEADER_PACK_STR = '!HH4x'
OFP_ACTION_HEADER_SIZE = 8
assert calcsize(OFP_ACTION_HEADER_PACK_STR) == OFP_ACTION_HEADER_SIZE
# struct ofp_action_output
OFP_ACTION_OUTPUT_PACK_STR = '!HHIH6x'
OFP_ACTION_OUTPUT_SIZE = 16
assert calcsize(OFP_ACTION_OUTPUT_PACK_STR) == OFP_ACTION_OUTPUT_SIZE
# enum ofp_controller_max_len
OFPCML_MAX = 0xffe5 # maximum max_len value which can be used to
# request a specific byte length.
OFPCML_NO_BUFFER = 0xffff # indicates that no buffering should be
# applied and the whole packet is to be
# sent to the controller.
# struct ofp_action_group
OFP_ACTION_GROUP_PACK_STR = '!HHI'
OFP_ACTION_GROUP_SIZE = 8
assert calcsize(OFP_ACTION_GROUP_PACK_STR) == OFP_ACTION_GROUP_SIZE
# struct ofp_action_set_queue
OFP_ACTION_SET_QUEUE_PACK_STR = '!HHI'
OFP_ACTION_SET_QUEUE_SIZE = 8
assert calcsize(OFP_ACTION_SET_QUEUE_PACK_STR) == OFP_ACTION_SET_QUEUE_SIZE
# struct ofp_action_mpls_ttl
OFP_ACTION_MPLS_TTL_PACK_STR = '!HHB3x'
OFP_ACTION_MPLS_TTL_SIZE = 8
assert calcsize(OFP_ACTION_MPLS_TTL_PACK_STR) == OFP_ACTION_MPLS_TTL_SIZE
# struct ofp_action_nw_ttl
OFP_ACTION_NW_TTL_PACK_STR = '!HHB3x'
OFP_ACTION_NW_TTL_SIZE = 8
assert calcsize(OFP_ACTION_NW_TTL_PACK_STR) == OFP_ACTION_NW_TTL_SIZE
# struct ofp_action_push
OFP_ACTION_PUSH_PACK_STR = '!HHH2x'
OFP_ACTION_PUSH_SIZE = 8
assert calcsize(OFP_ACTION_PUSH_PACK_STR) == OFP_ACTION_PUSH_SIZE
# struct ofp_action_pop_mpls
OFP_ACTION_POP_MPLS_PACK_STR = '!HHH2x'
OFP_ACTION_POP_MPLS_SIZE = 8
assert calcsize(OFP_ACTION_POP_MPLS_PACK_STR) == OFP_ACTION_POP_MPLS_SIZE
# struct ofp_action_prob_drop
OFP_ACTION_PROB_DROP_PACK_STR = '!HHI'
OFP_ACTION_PROB_DROP_SIZE = 8
assert calcsize(OFP_ACTION_PROB_DROP_PACK_STR) == OFP_ACTION_PROB_DROP_SIZE
1.OFPAT_PROB_DROP = 29 #probdrop packet
2.# struct ofp_action_prob_drop
OFP_ACTION_PROB_DROP_PACK_STR = '!HHI'
OFP_ACTION_PROB_DROP_SIZE = 8
assert calcsize(OFP_ACTION_PROB_DROP_PACK_STR) == OFP_ACTION_PROB_DROP_SIZE #共占8字节,进行校验
声明数据格式,我们需要传参,固定传参中由type和len各占2字节用H表示,我们需要的参数为一位32为数据,占4字节,用I表示,故!HHI为格式,共占8字节
(二)实现动作解析,修改ofproto_v1_3_parser.py
@OFPAction.register_action_type(ofproto.OFPAT_POP_PBB,
ofproto.OFP_ACTION_HEADER_SIZE)
class OFPActionPopPbb(OFPAction):
"""
Pop PBB action
This action pops the outermost PBB service instance header from
the packet.
"""
def __init__(self, type_=None, len_=None):
super(OFPActionPopPbb, self).__init__()
@classmethod
def parser(cls, buf, offset):
(type_, len_) = struct.unpack_from(
ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
return cls()
@OFPAction.register_action_type(ofproto.OFPAT_PROB_DROP,
ofproto.OFP_ACTION_PROB_DROP_SIZE)
class OFPActionProbdrop(OFPAction):
"""
Prob drop action
This action Randomly discarded the packet.
"""
def __init__(self, probd, type_=None, len_=None):
super(OFPActionProbdrop, self).__init__()
self.probd = probd
@classmethod
def parser(cls, buf, offset):
(type_, len_, probd) = struct.unpack_from(
ofproto.OFP_ACTION_PROB_DROP_PACK_STR, buf, offset)
return cls(probd)
def serialize(self, buf, offset):
msg_pack_into(ofproto.OFP_ACTION_PROB_DROP_PACK_STR, buf, offset,
self.type, self.len, self.probd)
1.我们需要进行传参处理
def __init__(self, probd, type_=None, len_=None):
super(OFPActionProbdrop, self).__init__()
self.probd = probd
2.进行报文解析
@classmethod
def parser(cls, buf, offset):
(type_, len_, probd) = struct.unpack_from(
ofproto.OFP_ACTION_PROB_DROP_PACK_STR, buf, offset)
return cls(probd)
3.进行序列化处理,按照HHI进行序列化即可
def serialize(self, buf, offset):
msg_pack_into(ofproto.OFP_ACTION_PROB_DROP_PACK_STR, buf, offset,
self.type, self.len, self.probd)
(三)重新进行源码安装Ryu
进入ryu主目录,目录下含有setup.py安装文件
sudo python3 setup.py install
(四)编写app文件,进行测试
1.编写python文件
from ryu.base import app_manager
from ryu.ofproto import ofproto_v1_3,ofproto_v1_3_parser
from ryu.ofproto import nx_actions
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER,CONFIG_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
class otheraction(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
def __init__(self,*args,**kwargs):
super(otheraction,self).__init__(*args,**kwargs)
self.Dst_Src_Table={}
@set_ev_cls(ofp_event.EventOFPSwitchFeatures,CONFIG_DISPATCHER)
def switch_features_handler(self,ev):
datapath = ev.msg.datapath
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser
match = ofp_parser.OFPMatch()
actions = [ofp_parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,ofproto.OFPCML_NO_BUFFER)]
self.add_flow(datapath,0,match,actions,"default flow entry")
def add_flow(self,datapath,priority,match,actions,remind_content):
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser
inst = [ofp_parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
actions)]
mod = ofp_parser.OFPFlowMod(datapath=datapath,priority=priority,
match=match,instructions=inst);
print("install to datapath,"+remind_content)
datapath.send_msg(mod);
@set_ev_cls(ofp_event.EventOFPPacketIn,MAIN_DISPATCHER)
def packet_in_handler(self,ev): msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser
in_port = msg.match['in_port']
match = ofp_parser.OFPMatch(in_port=in_port)
if(datapath.id == 1 and in_port == 1): #我们只对第一个交换机,s1,添加概率丢包动作
actions = [ofp_parser.OFPActionProbDrop(1000000000),ofp_parser.OFPActionOutput(2)]
else: #对于其他交换机,泛洪处理即可
actions = [ofp_parser.OFPActionOutput(ofproto.OFPP_FLOOD)]
self.add_flow(datapath,1,match,actions,"hub flow entry")
out = ofp_parser.OFPPacketOut(datapath=datapath,buffer_id=msg.buffer_id,
in_port=in_port,actions=actions)
datapath.send_msg(out)
2.实验测试