Mininet自定义拓扑下Pingall及主机间Ping失败求助
自定义Mininet拓扑与Ryu控制器连通性故障排查
故障现象
- 执行
pingall或h1 ping h2操作时,100%丢包,无网络连通性 - Ryu控制器日志显示:控制器启动正常,交换机成功连接;ping操作时收到Packet-in、ARP请求包,且发送了ARP回复,但Mininet终端无响应
相关代码
自定义Mininet拓扑代码
from mininet.topo import Topo from mininet.net import Mininet from mininet.node import RemoteController, OVSSwitch from mininet.cli import CLI from mininet.log import setLogLevel class CustomTopo(Topo): def build(self): s1 = self.addSwitch('s1', protocols='OpenFlow13') h1 = self.addHost('h1', ip='10.0.0.1/24', mac='00:00:00:00:00:01') h2 = self.addHost('h2', ip='10.0.0.2/24', mac='00:00:00:00:00:02') self.addLink(h1, s1) self.addLink(h2, s1) def run(): topo = CustomTopo() net = Mininet(topo=topo, controller=lambda name: RemoteController(name, ip='127.0.0.1', port=6653), switch=OVSSwitch, autoSetMacs=True) net.start() CLI(net) net.stop() if __name__ == '__main__': setLogLevel('info') run()
Ryu控制器路由代码
from ryu.base import app_manager from ryu.controller import ofp_event from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER from ryu.controller.handler import set_ev_cls from ryu.ofproto import ofproto_v1_3 from ryu.lib.packet import packet, ethernet, ipv4, arp from ryu.lib.packet import ether_types class SimpleRouter(app_manager.RyuApp): OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] def __init__(self, *args, **kwargs): super(SimpleRouter, self).__init__(*args, **kwargs) self.arp_table = { '10.0.0.1': '00:00:00:00:00:01', '10.0.0.2': '00:00:00:00:00:02', } @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) def switch_features_handler(self, ev): datapath = ev.msg.datapath parser = datapath.ofproto_parser ofproto = datapath.ofproto match = parser.OFPMatch() actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, ofproto.OFPCML_NO_BUFFER)] inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)] mod = parser.OFPFlowMod(datapath=datapath, priority=0, match=match, instructions=inst) datapath.send_msg(mod) def add_flow(self, datapath, priority, match, actions): parser = datapath.ofproto_parser ofproto = datapath.ofproto inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)] mod = parser.OFPFlowMod(datapath=datapath, priority=priority, match=match, instructions=inst) datapath.send_msg(mod) @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) def packet_in_handler(self, ev): msg = ev.msg datapath = msg.datapath parser = datapath.ofproto_parser in_port = msg.match['in_port'] pkt = packet.Packet(msg.data) eth = pkt.get_protocol(ethernet.ethernet) if eth.ethertype == ether_types.ETH_TYPE_ARP: self.handle_arp(datapath, pkt, in_port) elif eth.ethertype == ether_types.ETH_TYPE_IP: ip_pkt = pkt.get_protocol(ipv4.ipv4) dst_ip = ip_pkt.dst if dst_ip in self.arp_table: out_port = 2 if in_port == 1 else 1 actions = [parser.OFPActionOutput(out_port)] match = parser.OFPMatch( eth_type=ether_types.ETH_TYPE_IP, ipv4_dst=dst_ip ) self.add_flow(datapath, 1, match, actions) datapath.send_packet_out( buffer_id=msg.buffer_id, in_port=in_port, actions=actions, data=msg.data ) def handle_arp(self, datapath, pkt, port): arp_pkt = pkt.get_protocol(arp.arp) dst_ip = arp_pkt.dst_ip if dst_ip not in self.arp_table: return src_mac = self.arp_table[dst_ip] dst_mac = arp_pkt.src_mac src_ip = dst_ip dst_ip = arp_pkt.src_ip e = ethernet.ethernet(dst=dst_mac, src=src_mac, ethertype=ether_types.ETH_TYPE_ARP) a = arp.arp(opcode=arp.ARP_REPLY, src_mac=src_mac, src_ip=src_ip, dst_mac=dst_mac, dst_ip=dst_ip) p = packet.Packet() p.add_protocol(e) p.add_protocol(a) p.serialize() actions = [datapath.ofproto_parser.OFPActionOutput(port)] datapath.send_packet_out( buffer_id=0xffffffff, in_port=datapath.ofproto.OFPP_CONTROLLER, actions=actions, data=p.data )
故障原因
- MAC地址不匹配:Mininet拓扑中开启了
autoSetMacs=True,会自动覆盖手动设置的主机MAC地址,导致Ryu控制器静态ARP表中的MAC与实际主机MAC不一致,ARP回复无法被主机正确识别。 - IP包转发未修正以太网MAC:Ryu控制器转发IP包时,未修改以太网帧的目的MAC为目标主机的正确MAC,即使数据包被转发,目标主机可能因MAC不匹配丢弃数据包。
修复方案
1. 修正Mininet拓扑MAC配置
关闭autoSetMacs,确保手动设置的MAC地址生效:
def run(): topo = CustomTopo() net = Mininet(topo=topo, controller=lambda name: RemoteController(name, ip='127.0.0.1', port=6653), switch=OVSSwitch, autoSetMacs=False) # 禁用自动MAC分配 net.start() CLI(net) net.stop()
2. 修正Ryu控制器IP包转发逻辑
转发IP包时,重新构造以太网帧,设置正确的目的MAC:
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) def packet_in_handler(self, ev): msg = ev.msg datapath = msg.datapath parser = datapath.ofproto_parser ofproto = datapath.ofproto in_port = msg.match['in_port'] pkt = packet.Packet(msg.data) eth = pkt.get_protocol(ethernet.ethernet) if eth.ethertype == ether_types.ETH_TYPE_ARP: self.handle_arp(datapath, pkt, in_port) elif eth.ethertype == ether_types.ETH_TYPE_IP: ip_pkt = pkt.get_protocol(ipv4.ipv4) dst_ip = ip_pkt.dst src_ip = ip_pkt.src if dst_ip in self.arp_table and src_ip in self.arp_table: out_port = 2 if in_port == 1 else 1 # 获取源和目的主机的正确MAC src_mac = self.arp_table[src_ip] dst_mac = self.arp_table[dst_ip] # 重新构造以太网帧和IP包 new_eth = ethernet.ethernet(dst=dst_mac, src=src_mac, ethertype=ether_types.ETH_TYPE_IP) new_pkt = packet.Packet() new_pkt.add_protocol(new_eth) new_pkt.add_protocol(ip_pkt) new_pkt.serialize() # 设置转发动作和流表项 actions = [parser.OFPActionOutput(out_port)] match = parser.OFPMatch( eth_type=ether_types.ETH_TYPE_IP, ipv4_dst=dst_ip ) self.add_flow(datapath, 1, match, actions) # 发送转发数据包 datapath.send_packet_out( buffer_id=msg.buffer_id, in_port=in_port, actions=actions, data=new_pkt.data if msg.buffer_id == ofproto.OFP_NO_BUFFER else None )
验证修复
- 重启Ryu控制器和Mininet拓扑
- 在Mininet终端执行
pingall,应显示h1与h2连通 - 查看Ryu日志,确认ARP回复正常发送,IP包转发流表项正确添加
内容的提问来源于stack exchange,提问作者Sylvia_Khan
相关产品推荐
相关产品推荐

