def switch_handler(self, address, fd, events): if events & io_loop.READ: data = self.sock_sw.recv(1024) if data == '': print "switch disconnected" io_loop.remove_handler(self.fd_sw) print "closing connection to controller" self.sock_con.close() io_loop.remove_handler(self.fd_con) else: rmsg = of.ofp_header(data[0:8]) if rmsg.type == 6: print "OFPT_FEATURES_REPLY" #Actually,we just need to change here. header = of.ofp_header(data[0:8]) print "ofp_features_reply.xid ", header.xid msg = of.ofp_features_reply(data[8:32]) #all sw type should make the convertion. Because our protocol need to use in all nets. msg_port = data[32:] msg = header/msg/msg_port self.dpid=msg.datapath_id #record the dpid data = convert.of2ofc(msg, self.buffer, self.dpid) elif rmsg.type == 10: pkt_in_msg = of.ofp_packet_in(data[8:18]) pkt_parsed = of.Ether(data[18:]) self.counter+=1 #[port + id+ dpid] --> [buffer_id + pkt_in_msg] if isinstance(pkt_parsed.payload, of.IP) or isinstance(pkt_parsed.payload.payload, of.IP): self.buffer[(pkt_in_msg.in_port, self.counter, self.dpid)] = [pkt_in_msg.buffer_id, rmsg/pkt_in_msg/pkt_parsed] # bind buffer id with in port rmsg.xid = self.counter # use the counter to check the buffer data = rmsg/pkt_in_msg/pkt_parsed elif rmsg.type ==11: match = ofc.ofp_match(data[12:48]) #data[8:12]is wildcards for flow in self.flow_cache: if match == ofc.ofp_match(str(flow[1])[12:48]): self.flow_cache.remove(flow) #delete the flow elif rmsg.type == 17: print "stats_reply" ,len(data) body = data[8:] reply_header = of.ofp_stats_reply(body[:4]) if reply_header.type == 1 and len(data)>91: reply_body_match = ofc.ofp_match(body[12:48]) reply_body_data2 = ofc.ofp_flow_stats_data(body[48:92]) if reply_body_data2.byte_count == 0 and reply_body_data2.packet_count == 0: #it is a junck flow,delete it! for flow in self.flow_cache: if reply_body_match == ofc.ofp_match(str(flow[1])[12:48]): self.flow_cache.remove(flow) io_loop.update_handler(self.fd_con, io_loop.WRITE) self.queue_con.put(str(data)) if events & io_loop.WRITE: try: next_msg = self.queue_sw.get_nowait() except Queue.Empty: #print "%s queue empty" % str(address) io_loop.update_handler(self.fd_sw, io_loop.READ) else: #print 'sending "%s" to %s' % (of.ofp_type[of.ofp_header(next_msg).type], self.sock_sw.getpeername()) self.sock_sw.send(next_msg)
def features_reply_handler(data, fd): #print ">>>OFPT_FEATURES_REPLY" body = data[8:] msg = of.ofp_features_reply(body[0:24]) #length of reply msg sock_dpid[fd] = msg.datapath_id """ port_info_raw = str(body[24:]) #we change it into str so we can manipulate it. port_info = {} #print ">>>port number:",len(port_info_raw)/48, "total length:", len(port_info_raw) for i in range(len(port_info_raw)/48): port= of.ofp_phy_port(port_info_raw[0+i*48:48+i*48]) #port.show() #print port.port_no port_info[port.port_no]= port #save port_info by port_no #sock_dpid[fd] comes from here. features_info[msg.datapath_id] =(msg, port_info) #features_info[dpid] = (sw_features, port_info{}) """ return None
def features_reply_handler(data,fd): #print ">>>OFPT_FEATURES_REPLY" body = data[8:] msg = of.ofp_features_reply(body[0:24]) #length of reply msg sock_dpid[fd]=msg.datapath_id """ port_info_raw = str(body[24:]) #we change it into str so we can manipulate it. port_info = {} #print ">>>port number:",len(port_info_raw)/48, "total length:", len(port_info_raw) for i in range(len(port_info_raw)/48): port= of.ofp_phy_port(port_info_raw[0+i*48:48+i*48]) #port.show() #print port.port_no port_info[port.port_no]= port #save port_info by port_no #sock_dpid[fd] comes from here. features_info[msg.datapath_id] =(msg, port_info) #features_info[dpid] = (sw_features, port_info{}) """ return None
18 okay "OFPT_BARRIER_REQUEST", 19 okay "OFPT_BARRIER_REPLY", 20 okay "OFPT_QUEUE_GET_CONFIG_REQUEST", 21 okay "OFPT_QUEUE_GET_CONFIG_REPLY" 24 oaky "OFPT_CFEATURES_REPLY" 0xfe oaky "OFPT_CPORT_STATUS" 0xff okay "OFPT_CFLOW_MO """ if __name__ == '__main__': import convert import libopenflow as of #a = ofp_cfeatures_reply() #b = ofp_phy_cport() #c = ofp_phy_cport() #d=ofp_header(type =24,length = 32+78*2)/ofp_cfeatures_reply(n_cports=2)/ofp_phy_cport()/sup_wave_port_bandwidth(num_lmda=4)/ofp_phy_cport()/sup_wave_port_bandwidth(num_lmda=5) #d.show() #a.n_cports=2 #a.OFPC_TABLE_STATS=100 #a.OFPST_T_OTN = 1 #a.SUPP_SW_GRAN = 129 #print a.SUPP_SW_GRAN buffer = {} dpid = 8 e = of.ofp_header(type =6)/of.ofp_features_reply(datapath_id=1)/of.ofp_phy_port(port_no=1)/of.ofp_phy_port(port_no=2)\ /of.ofp_phy_port(port_no=3)/of.ofp_phy_port(port_no=4)/of.ofp_phy_port(port_no=5) f = convert.of2ofc(e, buffer, dpid) f.show() p = str(f)
def client_handler(address, fd, events): sock = fd_map[fd] #print sock, sock.getpeername(), sock.getsockname() if events & io_loop.READ: data = sock.recv(1024) if data == '': """ According to stackoverflow(http://stackoverflow.com/questions/667640/how-to-tell-if-a-connection-is-dead-in-python) When a socket is closed, the server will receive a EOF. In python, however, server will receive a empty string(''). So, when a switch disconnected, the server will find out at once. But, if you do not react on this incident, there will be always a ``ioloop.read`` event. And the loop will run forever, thus, the CPU useage will be pretty high. """ print "connection dropped" io_loop.remove_handler(fd) if len(data)<8: print "not a openflow message" else: #print len(data) #if the data length is 8, then only of header #else, there are payload after the header if len(data)>8: rmsg = of.ofp_header(data[0:8]) body = data[8:] else: rmsg = of.ofp_header(data) #rmsg.show() if rmsg.type == 0: print "OFPT_HELLO" msg = of.ofp_header(type = 5) io_loop.update_handler(fd, io_loop.WRITE) message_queue_map[sock].put(data) message_queue_map[sock].put(str(msg)) elif rmsg.type == 1: print "OFPT_ERROR" elif rmsg.type == 5: print "OFPT_FEATURES_REQUEST" elif rmsg.type == 6: print "OFPT_FEATURES_REPLY" #print "rmsg.load:",len(body)/48 msg = of.ofp_features_reply(body[0:24])#length of reply msg #msg.show() port_info_raw = body[24:] port_info = {} print "port number:",len(port_info_raw)/48, "total length:", len(port_info_raw) for i in range(len(port_info_raw)/48): #print "port", i, ",len:", len(port_info_raw[0+i*48:48+i*48]) """The port structure has a length of 48 bytes. so when receiving port info, first split the list into port structure length and then analysis """ port_info[i] = of.ofp_phy_port(port_info_raw[0+i*48:48+i*48]) #print port_info[i].port_name #port_info[i].show() #print port_info[i].OFPPC_PORT_DOWN elif rmsg.type == 2: print "OFPT_ECHO_REQUEST" msg = of.ofp_header(type=3, xid=rmsg.xid) #test for status request [which is good] global exe_id global ofp_match_obj if exe_id>1: #len = 8+4+44 stat_req = of.ofp_header(type=16,length=56)\ /of.ofp_stats_request(type=1)\ /of.ofp_flow_wildcards()\ /ofp_match_obj\ /of.ofp_flow_stats_request() #stat_req.show() message_queue_map[sock].put(str(msg)) if exe_id>1: message_queue_map[sock].put(str(stat_req)) io_loop.update_handler(fd, io_loop.WRITE) #end of test #io_loop.update_handler(fd, io_loop.WRITE) #message_queue_map[sock].put(str(msg)) elif rmsg.type == 3: print "OFPT_ECHO_REPLY" elif rmsg.type == 4: print "OFPT_VENDOR" elif rmsg.type == 6: print "OFPT_FEATURES_REPLY" elif rmsg.type == 7: print "OFPT_GET_CONFIG_REQUEST" elif rmsg.type == 8: print "OFPT_GET_CONFIG_REPLY" elif rmsg.type == 9: print "OFPT_SET_CONFIG" elif rmsg.type == 10: #print "OFPT_PACKET_IN" #rmsg.show() pkt_in_msg = of.ofp_packet_in(body) #pkt_in_msg.show() raw = pkt_in_msg.load pkt_parsed = of.Ether(raw) #pkt_parsed.payload.show() #print "to see if the payload of ether is IP" #if isinstance(pkt_parsed.payload, of.IP): #pkt_parsed.show() if isinstance(pkt_parsed.payload, of.ARP): #pkt_parsed.show() #pkt_out = of.ofp_header()/of.ofp_pktout_header()/of.ofp_action_output() pkt_out.payload.payload.port = 0xfffb pkt_out.payload.buffer_id = pkt_in_msg.buffer_id pkt_out.payload.in_port = pkt_in_msg.in_port pkt_out.length = 24 #pkt_out.show() io_loop.update_handler(fd, io_loop.WRITE) message_queue_map[sock].put(str(pkt_out)) if isinstance(pkt_parsed.payload, of.IP): if isinstance(pkt_parsed.payload.payload, of.ICMP): #print "from", pkt_parsed.src, "to", pkt_parsed.dst """ When receive a OPF_PACKET_IN message, you can caculate a path, and then use OFP_FLOW_MOD message to install path. Also, you can find out the exact port to send the message, then you can use the following code to send a OFP_PACKET_OUT message and send the packet to destination. """ #pkt_parsed.show() #pkt_out = of.ofp_header()/of.ofp_pktout_header()/of.ofp_action_output() pkt_out.payload.payload.port = 0xfffb pkt_out.payload.buffer_id = pkt_in_msg.buffer_id pkt_out.payload.in_port = pkt_in_msg.in_port pkt_out.length = 24 """ io_loop.update_handler(fd, io_loop.WRITE) message_queue_map[sock].put(str(pkt_out)) """ #print pkt_parsed.payload.proto #pkt_parsed.show() #print "ICMP protocol" #pkt_out.show() #usually don't have to fill in ``wilecards`` area global cookie global exe_id exe_id += 1 cookie += 1 flow_mod_msg = of.ofp_header(type=14, length=80, xid=exe_id)/\ of.ofp_flow_wildcards()\ /of.ofp_match(in_port=pkt_in_msg.in_port, dl_src=pkt_parsed.src, dl_dst=pkt_parsed.dst, dl_type=pkt_parsed.type, nw_tos=pkt_parsed.payload.tos, nw_proto=pkt_parsed.payload.proto, nw_src=pkt_parsed.payload.src, nw_dst=pkt_parsed.payload.dst, tp_src = pkt_parsed.payload.payload.type, tp_dst = pkt_parsed.payload.payload.code)\ /of.ofp_flow_mod(cookie=cookie, command=0, idle_timeout=60, buffer_id=pkt_in_msg.buffer_id,#icmp type 8: request, 0: reply flags=1)\ /of.ofp_action_output(type=0, port=0xfffb, len=8) #flow_mod_msg.show() global ofp_match_obj ofp_match_obj = of.ofp_match(in_port=pkt_in_msg.in_port, dl_src=pkt_parsed.src, dl_dst=pkt_parsed.dst, dl_type=pkt_parsed.type, nw_tos=pkt_parsed.payload.tos, nw_proto=pkt_parsed.payload.proto, nw_src=pkt_parsed.payload.src, nw_dst=pkt_parsed.payload.dst, tp_src = pkt_parsed.payload.payload.type, tp_dst = pkt_parsed.payload.payload.code) exe_id += 1 """ print "--------------------------------------------------------------------------------------" print "len of flow_mod_msg :", len(str(flow_mod_msg)) print "len of of_header() :", len(str(of.ofp_header())) print "len of ofp_flow_wildcards():", len(str(of.ofp_flow_wildcards())) print "len of ofp_match() :", len(str(of.ofp_match())) print "len of ofp_flow_mod() :", len(str(of.ofp_flow_mod(command=0,idle_timeout=60,buffer_id=pkt_in_msg.buffer_id))) print "len of ofp_action_output() :", len(str(of.ofp_action_output(type=0,port=0xfffb,len=8))) print "--------------------------------------------------------------------------------------" """ io_loop.update_handler(fd, io_loop.WRITE) #message_queue_map[sock].put(str(pkt_out)) message_queue_map[sock].put(str(flow_mod_msg)) message_queue_map[sock].put(str(of.ofp_header(type=18,xid=exe_id))) #send a barrier request msg. elif rmsg.type == 11: print "OFPT_FLOW_REMOVED" elif rmsg.type == 12: print "OFPT_PORT_STATUS" elif rmsg.type == 13: print "OFPT_PACKET_OUT" elif rmsg.type == 14: print "OFPT_FLOW_MOD" elif rmsg.type == 15: print "OFPT_PORT_MOD" elif rmsg.type == 16: print "OFPT_STATS_REQUEST" elif rmsg.type == 17: print "OFPT_STATS_REPLY" # 1. parsing ofp_stats_reply reply_header = of.ofp_stats_reply(body[:4]) # 2.parsing ofp_flow_stats msg reply_body_data1 = of.ofp_flow_stats(body[4:8]) # match field in ofp_flow_stats reply_body_wildcards = of.ofp_flow_wildcards(body[8:12]) reply_body_match = of.ofp_match(body[12:48]) # second part in ofp_flow_stats reply_body_data2 = of.ofp_flow_stats_data(body[48:92]) # 3.parsing actions # should first judge action type i = 0 reply_body_action = [] #print len(body[92:]) while i<len(body[92:]): if body[95+i:96+i]==0x08: print "0x08" i+=8 if body[95+i:96+i] == 0x08: reply_body_action.append(of.ofp_action_output(body[92+i:100+i])) #i+=8 # 4.show msg msg = reply_header/reply_body_data1/reply_body_wildcards/reply_body_match/reply_body_data2 msg.show() print reply_body_action # no message body elif rmsg.type == 18: print "OFPT_BARRIER_REQUEST" #no message body, the xid is the previous barrier request xid elif rmsg.type == 19: print "OFPT_BARRIER_REPLY: ", rmsg.xid, "Successful" elif rmsg.type == 20: print "OFPT_QUEUE_GET_CONFIG_REQUEST" elif rmsg.type == 21: print "OFPT_QUEUE_GET_CONFIG_REPLY" if events & io_loop.WRITE: try: next_msg = message_queue_map[sock].get_nowait() except Queue.Empty: #print "%s queue empty" % str(address) io_loop.update_handler(fd, io_loop.READ) else: #print 'sending "%s" to %s' % (of.ofp_header(next_msg).type, address) sock.send(next_msg)