这篇文章是本人的第一篇投稿,万分紧张,希望一切顺利,有什么错误还请大家指正。
本文记录了一些我在运行李呈老师的Ryu基于跳数的最短路径转发代码时遇到的错误,以及如何解决的,希望能够给大家带来帮助。
请勿直接粘贴此代码!!!有错误
from ryu.base import app_manager
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.ofproto import ofproto_v1_3
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.topology import event, switches
from ryu.topology.api import get_switch, get_link
import networkx as nx
class ExampleShortestForwarding(app_manager.RyuApp):
"""docstring for ExampleShortestForwarding"""
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
def __init__(self, *args, **kwargs):
super(ExampleShortestForwarding, self).__init__(*args, **kwargs)
self.network=nx.DiGraph()
self.topology_api_app = self
self.paths = {}
@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
# install the table-miss flow entry.
match = ofp_parser.OFPMatch()
actions = [ofp_parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
ofproto.OFPCML_NO_BUFFER)]
self.add_flow(datapath, 0, match, actions)
def add_flow(self, datapath, priority, match, actions):
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser
# construct flow_mod message and send it.
inst = [ofp_parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
actions)]
mod = ofp_parser.OFPFlowMod(datapath=datapath, priority=priority,
match=match, instructions=inst)
datapath.send_msg(mod)
@set_ev_cls(event.EventSwitchEnter, [CONFIG_DISPATCHER, MAIN_DISPATCHER])
def get_topology(self, ev):
# get switches and store them into self.network
switch_list = get_switch(self.topology_api_app, None)
switches=[switch.dp.id for switch in switch_list]
self.network.add_nodes_from(switches)
# get links and store them into self.network
links_list = get_link(self.topology_api_app, None)
links=[(link.src.dpid,link.dst.dpid,{'port':link.src.port_no}) for link in links_list]
self.network.add_edges_from(links)
# reverse link.
links=[(link.dst.dpid,link.src.dpid,{'port':link.dst.port_no}) for link in links_list]
self.network.add_edges_from(links)
def get_out_port(self, src, dst, datapath, in_port):
dpid = datapath.id
# add link between host and ingress switch.
if src not in self.network:
self.network.add_node(src)
self.network.add_edge(dpid,src,{'port':in_port})
self.network.add_edge(src,dpid)
self.paths.setdefault(src, {})
if dst in self.network:
# if path is not existed, calculate it and save it.
if dst not in self.paths[src]:
path = nx.shortest_path(self.network,src,dst)
self.paths[src][dst] = path
# find out_port to next hop.
path = self.paths[src][dst]
print "path: ", path
next_hop = path[path.index(dpid)+1]
out_port = self.network[dpid][next_hop]['port']
else:
out_port = datapath.ofproto.OFPP_FLOOD
return out_port
@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
pkt = packet.Packet(msg.data)
eth = pkt.get_protocol(ethernet.ethernet)
in_port = msg.match['in_port']
out_port = self.get_out_port(eth.src, eth.dst, datapath, in_port)
actions = [ofp_parser.OFPActionOutput(out_port)]
# install flow_mod to avoid packet_in next time.
if out_port != ofproto.OFPP_FLOOD:
match = ofp_parser.OFPMatch(in_port=in_port, eth_dst=eth.dst)
self.add_flow(datapath, 1, match, actions)
# send packet_out msg to flood packet.
out = ofp_parser.OFPPacketOut(
datapath=datapath,buffer_id=msg.buffer_id,in_port=in_port,
actions=actions)
datapath.send_msg(out)
这里显示add_edge()参数数量有问题,但是我明明只输入了三个呀。
我在“国宝小十三”的博客中找到了原因:https://blog.csdn.net/dududududou/article/details/89183207
原因是networkx版本的原因,需要卸载此版本,安装旧版的networkx
pip uninstall networkx
pip install networkx==1.11
之后,上述代码便可运行成功
解决上述问题后,我用mininet连接了控制器
mn --controller=remote,ip=192.168.83.144,port=6653 --switch ovs,protocols=OpenFlow13 --mac --topo=tree,2,2
然而pingall命令执行后,所有主机都ping不通。
查阅了大量的csdn博客,也尝试将
self.network.add_edge(dpid,src,{'port':in_port})
修改为
self.network.add_edge(dpid,src,port=in_port)
依旧失败。
之后我突然想起之前学习“自学习交换机”的时候也遇到了ping不通的问题。于是使用之前的解决方法进行了尝试
datapath=datapath,buffer_id=msg.buffer_id,in_port=in_port,
actions=actions)
修改为
datapath=datapath,buffer_id=msg.buffer_id,in_port=in_port,
actions=actions, data=msg.data)
添加了一个data参数。这次修改之后,连接Mininet,应用pingall命令。
有的时候可以ping通所有主机。
有的时候只能ping通同一交换机下连接的主机。
这就很玄学了。如果哪位大神找到了解决方案,还请不吝赐教
如果帮到了大家,请点个赞,如果有其他问题,欢迎留言~~
from ryu.base import app_manager
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.ofproto import ofproto_v1_3
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.topology import event, switches
from ryu.topology.api import get_switch, get_link
import networkx as nx
class ExampleShortestForwarding(app_manager.RyuApp):
"""docstring for ExampleShortestForwarding"""
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
def __init__(self, *args, **kwargs):
super(ExampleShortestForwarding, self).__init__(*args, **kwargs)
self.network=nx.DiGraph()
self.topology_api_app = self
self.paths = {}
@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
# install the table-miss flow entry.
match = ofp_parser.OFPMatch()
actions = [ofp_parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
ofproto.OFPCML_NO_BUFFER)]
self.add_flow(datapath, 0, match, actions)
def add_flow(self, datapath, priority, match, actions):
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser
# construct flow_mod message and send it.
inst = [ofp_parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
actions)]
mod = ofp_parser.OFPFlowMod(datapath=datapath, priority=priority,
match=match, instructions=inst)
datapath.send_msg(mod)
@set_ev_cls(event.EventSwitchEnter, [CONFIG_DISPATCHER, MAIN_DISPATCHER])
def get_topology(self, ev):
# get switches and store them into self.network
switch_list = get_switch(self.topology_api_app, None)
switches=[switch.dp.id for switch in switch_list]
self.network.add_nodes_from(switches)
# get links and store them into self.network
links_list = get_link(self.topology_api_app, None)
links=[(link.src.dpid,link.dst.dpid,{'port':link.src.port_no}) for link in links_list]
self.network.add_edges_from(links)
# reverse link.
links=[(link.dst.dpid,link.src.dpid,{'port':link.dst.port_no}) for link in links_list]
self.network.add_edges_from(links)
def get_out_port(self, src, dst, datapath, in_port):
dpid = datapath.id
# add link between host and ingress switch.
if src not in self.network:
self.network.add_node(src)
self.network.add_edge(dpid,src,{'port':in_port})
self.network.add_edge(src,dpid)
self.paths.setdefault(src, {})
if dst in self.network:
# if path is not existed, calculate it and save it.
if dst not in self.paths[src]:
path = nx.shortest_path(self.network,src,dst)
self.paths[src][dst] = path
# find out_port to next hop.
path = self.paths[src][dst]
print("path: ", path)
next_hop = path[path.index(dpid)+1]
out_port = self.network[dpid][next_hop]['port']
else:
out_port = datapath.ofproto.OFPP_FLOOD
return out_port
@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
pkt = packet.Packet(msg.data)
eth = pkt.get_protocol(ethernet.ethernet)
in_port = msg.match['in_port']
out_port = self.get_out_port(eth.src, eth.dst, datapath, in_port)
actions = [ofp_parser.OFPActionOutput(out_port)]
# install flow_mod to avoid packet_in next time.
if out_port != ofproto.OFPP_FLOOD:
match = ofp_parser.OFPMatch(in_port=in_port, eth_dst=eth.dst)
self.add_flow(datapath, 1, match, actions)
# send packet_out msg to flood packet.
out = ofp_parser.OFPPacketOut(
datapath=datapath,buffer_id=msg.buffer_id,in_port=in_port,
actions=actions, data=msg.data)
datapath.send_msg(out)