1 实验题目

假如你有一个假如你有⼀个笔友遍天下爱写信的朋友叫李华,她生活在1972年的UCLA,希望通过ARPANET(世界第一个数据包交换网络,互联网的鼻祖,接入了25个研究机构,共计55条链路。具体拓扑见下图)发送一封Email给位于MIT的李明同学,现在需要你借助Ryu控制器编写Ryu APP帮助她

  • 为减少网络中节点的中转,希望找到一条从UCLA到MIT跳数最少的连接,输出经过的路线
  • 为了尽快发送Email,希望能找到⼀条从UCLA到MIT时延最短的连接,输出经过的路线及总的时延,利用Ping包的RTT验证你的结果(此问题选做)
  • 实验资料下载
    https://www.aliyundrive.com/s/fzR7s2Twe3u

2 实验内容

2.1 跳数最少

2.1.1 实现思路
  • 拓扑中存在环路,需要解决ARP包洪泛的问题。利用(dpid,mac,dstnation ip)作为键值记录对应的port,每个交换机第一次收到广播的Arp Request时记录下来,下一次收到键值相同但是port不同的Arp Request直接将包丢弃,从而避免了洪泛。
  • 对于图的存储及最短路径算法,使用现有的库networkx
2.1.2 具体实现
  • 全局变量

    • mac_to_port
      {{dpid:dst_mac}:port},用于控制器流表的下发。
    • arp_table
      {ip:mac},用于记录ipmac地址的映射关系。
    • sw
      {(dpid,src_mac,dst_ip):port},用于解决ARP包洪泛问题。
    • net
      用于记录实验拓扑的有向图。
  • ARP包洪泛问题的解决
    • 利用(dpid,mac,dstnation ip)作为键值记录对应的port,每个交换机第一次收到广播的Arp Request时记录下来,下一次收到键值相同但是port不同的Arp Request直接将包丢弃,从而避免了洪泛。
    • 具体代码如下:
if (datapath.id, eth_src, arp_dst_ip) in self.sw:  # Break the loopif self.sw[(datapath.id, eth_src, arp_dst_ip)] != in_port:out = datapath.ofproto_parser.OFPPacketOut(datapath=datapath,buffer_id=datapath.ofproto.OFP_NO_BUFFER,in_port=in_port,actions=[], data=None)datapath.send_msg(out)return True
else:self.sw[(datapath.id, eth_src, arp_dst_ip)] = in_port
  • 获取实验拓扑

    • 新建线程,每隔两秒更新一次实验拓扑,使用现有库networkx保存拓扑。
    • 具体代码如下:
def _get_topology(self):while True:#self.logger.info('\n')hosts = get_all_host(self)switch_list = get_all_switch(self)links_list = get_all_link(self)switches =[switch.dp.id for switch in switch_list]self.net.add_nodes_from(switches) # add nodelinks=[(link.src.dpid,link.dst.dpid,{'port':link.src.port_no}) for link in links_list] # [src_dpid,dst_dpid,port:src_port]self.net.add_edges_from(links) # add edgehub.sleep(2) # get topo in 2 seconds
  • _packet_in_handler()

    • 过滤掉lldp包和ipv6包
      lldp包和ipv6包存在的情况会导致拓扑结构获取出现问题
    • 加入主机到net
      将接收到packet_in报文的mac地址作为节点加入到net中,并增加主机到交换机两者间的有向边。
    • 使用networkx.shortest_path()求取最短路
2.1.3 测试截图
  • 启动控制器
sudo ryu-manager short_path.py --observe-links

- 启动加载自定义拓扑文件

sudo mn --custom SDNexp3Topo.py --topo generated --controller remote

  • 测试最短路
UCLA ping MIT

控制器端打印链路:

2.2 时延最短

2.2.1 实现思路

对ryu源码进行修改,增加计算获取链路时延功能,重新编译安装ryu,在安装目录下运行sudo python setup.py install

2.2.2 具体实现

在有向图上增加边的权重为时延,即可完成实验任务

if eth.ethertype == ether_types.ETH_TYPE_LLDP:src_dpid, src_port_no = switches.LLDPPacket.lldp_parse(msg.data)if self.switches is None:self.switches = app_manager.lookup_service_brick('switches')for port in self.switches.ports.keys():if src_dpid == port.dpid and src_port_no == port.port_no:delay=self.switches.ports[port].delay*1000print("src_switch:%s   dst_switch:%s    delay:%s"%(src_dpid,dpid,delay))self.lldp_delay[(src_dpid,dpid)] = delayself.net.add_edge(src_dpid,dpid,weight = delay)self.net.add_edge(dpid,src_dpid,weight = delay)
2.2.3 测试截图
  • 启动控制器
sudo ryu-manager min_delay.py --observe-links

  • 启动加载自定义拓扑文件
sudo python SDNexp3Topo.py --controller remote

  • 测试最小时延
UCLA ping MIT

控制器端打印链路时延:

3 代码

3.1 拓扑

# SDNexp3Topo.py
"""
Custom topology for Mininet, generated by GraphML-Topo-to-Mininet-Network-Generator.
"""
from mininet.topo import Topo
from mininet.net import Mininet
from mininet.node import RemoteController
from mininet.node import Node
from mininet.node import CPULimitedHost
from mininet.link import TCLink
from mininet.cli import CLI
from mininet.log import setLogLevel
from mininet.util import dumpNodeConnectionsclass GeneratedTopo( Topo ):"Internet Topology Zoo Specimen."def __init__( self, **opts ):"Create a topology."# Initialize TopologyTopo.__init__( self, **opts )# add nodes, switches first...s1 = self.addSwitch( 's1' )s2 = self.addSwitch( 's2' )s3 = self.addSwitch( 's3' )s4 = self.addSwitch( 's4' )s5 = self.addSwitch( 's5' )s6 = self.addSwitch( 's6' )s7 = self.addSwitch( 's7' )s8 = self.addSwitch( 's8' )s9 = self.addSwitch( 's9' )s10 = self.addSwitch( 's10' )s11 = self.addSwitch( 's11' )s12 = self.addSwitch( 's12' )s13 = self.addSwitch( 's13' )s14 = self.addSwitch( 's14' )s15 = self.addSwitch( 's15' )s16 = self.addSwitch( 's16' )s17 = self.addSwitch( 's17' )s18 = self.addSwitch( 's18' )s19 = self.addSwitch( 's19' )s20 = self.addSwitch( 's20' )s21 = self.addSwitch( 's21' )s22 = self.addSwitch( 's22' )s23 = self.addSwitch( 's23' )s24 = self.addSwitch( 's24' )s25 = self.addSwitch( 's25' )# ... and now hostsh1 = self.addHost( 'ILLINOIS' )h2 = self.addHost( 'MITRE' )h3 = self.addHost( 'CARNEGIE' )h4 = self.addHost( 'CASE' )h5 = self.addHost( 'ETAC' )h6 = self.addHost( 'AFGWC' )h7 = self.addHost( 'BBN' )h8 = self.addHost( 'NBS' )h9 = self.addHost( 'Tinker' )h10 = self.addHost( 'AMES' )h11 = self.addHost( 'RADC' )h12 = self.addHost( 'McClellan' )h13 = self.addHost( 'RAND' )h14 = self.addHost( 'AMES13' )h15 = self.addHost( 'SDC' )h16 = self.addHost( 'BBN15' )h17 = self.addHost( 'HARVARD' )h18 = self.addHost( 'SRI' )h19 = self.addHost( 'UCSB' )h20 = self.addHost( 'UCLA' )h21 = self.addHost( 'Stanford' )h22 = self.addHost( 'USC' )h23 = self.addHost( 'UTAH' )h24 = self.addHost( 'Lincoln' )h25 = self.addHost( 'MIT' )# add edges between switch and corresponding hostself.addLink( s1 , h1 )self.addLink( s2 , h2 )self.addLink( s3 , h3 )self.addLink( s4 , h4 )self.addLink( s5 , h5 )self.addLink( s6 , h6 )self.addLink( s7 , h7 )self.addLink( s8 , h8 )self.addLink( s9 , h9 )self.addLink( s10 , h10 )self.addLink( s11 , h11 )self.addLink( s12 , h12 )self.addLink( s13 , h13 )self.addLink( s14 , h14 )self.addLink( s15 , h15 )self.addLink( s16 , h16 )self.addLink( s17 , h17 )self.addLink( s18 , h18 )self.addLink( s19 , h19 )self.addLink( s20 , h20 )self.addLink( s21 , h21 )self.addLink( s22 , h22 )self.addLink( s23 , h23 )self.addLink( s24 , h24 )self.addLink( s25 , h25 )# add edges between switchesself.addLink( s1 , s25, bw=10, delay='50ms')self.addLink( s1 , s23, bw=10, delay='34ms')self.addLink( s2 , s3, bw=10, delay='13ms')self.addLink( s2 , s5, bw=10, delay='14ms')self.addLink( s3 , s4, bw=10, delay='15ms')self.addLink( s4 , s11, bw=10, delay='12ms')self.addLink( s4 , s6, bw=10, delay='17ms')self.addLink( s5 , s8, bw=10, delay='10ms')self.addLink( s7 , s25, bw=10, delay='18ms')self.addLink( s7 , s16, bw=10, delay='17ms')self.addLink( s8 , s17, bw=10, delay='13ms')self.addLink( s9 , s22, bw=10, delay='14ms')self.addLink( s9 , s16, bw=10, delay='19ms')self.addLink( s10 , s18, bw=10, delay='14ms')self.addLink( s10 , s14, bw=10, delay='15ms')self.addLink( s11 , s24, bw=10, delay='17ms')self.addLink( s12 , s18, bw=10, delay='40ms')self.addLink( s12 , s23, bw=10, delay='44ms')self.addLink( s13 , s20, bw=10, delay='15ms')self.addLink( s13 , s21, bw=10, delay='18ms')self.addLink( s13 , s15, bw=10, delay='15ms')self.addLink( s14 , s21, bw=10, delay='19ms')self.addLink( s15 , s22, bw=10, delay='15ms')self.addLink( s16 , s17, bw=10, delay='12ms')self.addLink( s18 , s19, bw=10, delay='44ms')self.addLink( s19 , s20, bw=10, delay='48ms')self.addLink( s22 , s23, bw=10, delay='16ms')self.addLink( s24 , s25, bw=10, delay='13ms')topos = { 'generated': ( lambda: GeneratedTopo() ) }# HERE THE CODE DEFINITION OF THE TOPOLOGY ENDS# the following code produces an executable script working with a remote controller
# and providing ssh access to the the mininet hosts from within the ubuntu vm
controller_ip = ''def setupNetwork(controller_ip):"Create network and run simple performance test"# check if remote controller's ip was set# else set it to localhosttopo = GeneratedTopo()if controller_ip == '':#controller_ip = '10.0.2.2';controller_ip = '127.0.0.1'net = Mininet(topo=topo, controller=lambda a: RemoteController( a, ip=controller_ip, port=6633 ), host=CPULimitedHost, link=TCLink)return netdef connectToRootNS( network, switch, ip, prefixLen, routes ):"Connect hosts to root namespace via switch. Starts network.""network: Mininet() network object""switch: switch to connect to root namespace""ip: IP address for root namespace node""prefixLen: IP address prefix length (e.g. 8, 16, 24)""routes: host networks to route to"# Create a node in root namespace and link to switch 0root = Node( 'root', inNamespace=False )intf = TCLink( root, switch ).intf1root.setIP( ip, prefixLen, intf )# Start network that now includes link to root namespacenetwork.start()# Add routes from root ns to hostsfor route in routes:root.cmd( 'route add -net ' + route + ' dev ' + str( intf ) )def sshd( network, cmd='/usr/sbin/sshd', opts='-D' ):"Start a network, connect it to root ns, and run sshd on all hosts."switch = network.switches[ 0 ]  # switch to useip = '10.123.123.1'  # our IP address on host networkroutes = [ '10.0.0.0/8' ]  # host networks to route toconnectToRootNS( network, switch, ip, 8, routes )for host in network.hosts:host.cmd( cmd + ' ' + opts + '&' )# DEBUGGING INFOprint()print ("Dumping host connections")dumpNodeConnections(network.hosts)print()print("*** Hosts are running sshd at the following addresses:")print()for host in network.hosts:print(host.name, host.IP())print()print("*** Type 'exit' or control-D to shut down network")print()print("*** For testing network connectivity among the hosts, wait a bit for the controller to create all the routes, then do 'pingall' on the mininet console.")print()CLI( network )for host in network.hosts:host.cmd( 'kill %' + cmd )network.stop()# by zys
def start_network(network):network.start()# DEBUGGING INFOprint()print("Dumping host connections")dumpNodeConnections(network.hosts)printfor host in network.hosts:print(host.name, host.IP())print()print("*** Type 'exit' or control-D to shut down network")print()print("*** For testing network connectivity among the hosts, wait a bit for the controller to create all the routes, then do 'pingall' on the mininet console.")print()print("*** edited for xjtu sdn_exp_2020")print()CLI( network )network.stop()if __name__ == '__main__':setLogLevel('info')#setLogLevel('debug')# sshd( setupNetwork(controller_ip) )start_network(setupNetwork(controller_ip))

3.2 跳数最少

# short_path.py
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
from ryu.lib.packet import ethernet
from ryu.lib.packet import ether_types
from ryu.lib.packet import arpfrom ryu.lib import hub
from ryu.topology.api import get_all_host, get_all_link, get_all_switch
from ryu.topology import event, switchesimport networkx as nx
import matplotlib.pyplot as pltETHERNET = ethernet.ethernet.__name__
ETHERNET_MULTICAST = "ff:ff:ff:ff:ff:ff" # broadcast mac
ARP = arp.arp.__name__class ARP_PROXY_13(app_manager.RyuApp):OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]def __init__(self, *args, **kwargs):super(ARP_PROXY_13, self).__init__(*args, **kwargs)self.mac_to_port = {}# {{dpid,dstmac}:port}self.arp_table = {} # {ip:mac}self.sw = {}# {(dpid,eth_src,arp_dst_ip):port}self.net = nx.DiGraph()# nx graphself.topo_thread = hub.spawn(self._get_topology)@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)def switch_features_handler(self, ev):datapath = ev.msg.datapathofproto = datapath.ofprotoparser = datapath.ofproto_parsermatch = parser.OFPMatch()actions = [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.ofprotoparser = datapath.ofproto_parserinst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,actions)]mod = parser.OFPFlowMod(datapath=datapath, priority=priority,idle_timeout=5, hard_timeout=15,match=match, instructions=inst)datapath.send_msg(mod)def _get_topology(self):while True:#self.logger.info('\n')hosts = get_all_host(self)switch_list = get_all_switch(self)links_list = get_all_link(self)switches =[switch.dp.id for switch in switch_list]self.net.add_nodes_from(switches) # add nodelinks=[(link.src.dpid,link.dst.dpid,{'port':link.src.port_no}) for link in links_list] # [src_dpid,dst_dpid,port:src_port]self.net.add_edges_from(links) # add edgehub.sleep(2) # get topo in 2 seconds@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)def _packet_in_handler(self, ev):#print "packet in"msg = ev.msgdp = msg.datapathofp = dp.ofprotodpid = dp.idparser = dp.ofproto_parserin_port = msg.match['in_port']pkt = packet.Packet(msg.data)eth = pkt.get_protocols(ethernet.ethernet)[0]dst = eth.dstsrc = eth.src# Filtering out lldp package and IPv6 package will lead to the problem of topology acquisitionif eth.ethertype == ether_types.ETH_TYPE_LLDP:returnif eth.ethertype == 34525:returnheader_list = dict((p.protocol_name, p)for p in pkt.protocols if type(p) != str)if ARP in header_list:self.arp_table[header_list[ARP].src_ip] = src  # ARP learningself.mac_to_port.setdefault(dpid, {})#self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)# learn a mac address to avoid FLOOD next time.self.mac_to_port[dpid][src] = in_port # L2LearningSwitch# add host to netif src not in self.net:self.net.add_node(src)self.net.add_edge(dpid, src, port=in_port, weight=0)self.net.add_edge(src, dpid, weight=0)if dst in self.mac_to_port[dpid]:out_port = self.mac_to_port[dpid][dst]if dst in self.net:path = nx.shortest_path(self.net, src, dst, weight=0)print("path : %s" % path)if  dpid in path:next = path[path.index(dpid) + 1]out_port = self.net[dpid][next]['port']else:if self.arp_handler(header_list, dp, in_port, msg.buffer_id):# 1:reply or drop;  0: floodprint("ARP_PROXY_13")return Noneelse:out_port = ofp.OFPP_FLOODprint('OFPP_FLOOD')actions = [parser.OFPActionOutput(out_port)]# install a flow to avoid packet_icn next timeif out_port != ofp.OFPP_FLOOD:match = parser.OFPMatch(in_port=in_port, eth_dst=dst)self.add_flow(dp, 1, match, actions)data = Noneif msg.buffer_id == ofp.OFP_NO_BUFFER:data = msg.dataout = parser.OFPPacketOut(datapath=dp, buffer_id=msg.buffer_id,in_port=in_port, actions=actions, data=data)dp.send_msg(out)def arp_handler(self, header_list, datapath, in_port, msg_buffer_id):header_list = header_listdatapath = datapathin_port = in_portif ETHERNET in header_list:eth_dst = header_list[ETHERNET].dsteth_src = header_list[ETHERNET].srcprint(header_list)'''Using (dpid, srcmac, dstip) as the port corresponding to the key value record,each switch records the ARP request when it receives the broadcast for the first time,and discards the packet when it receives the ARP request with the same key value but different port next time,so as to avoid flooding'''if eth_dst == ETHERNET_MULTICAST and ARP in header_list:arp_dst_ip = header_list[ARP].dst_ip# If (datapath. ID, eth_ src, arp_ dst_ IP) in sw, directly discard the packet and return trueif (datapath.id, eth_src, arp_dst_ip) in self.sw:  # Break the loopif self.sw[(datapath.id, eth_src, arp_dst_ip)] != in_port:out = datapath.ofproto_parser.OFPPacketOut(datapath=datapath,buffer_id=datapath.ofproto.OFP_NO_BUFFER,in_port=in_port,actions=[], data=None)datapath.send_msg(out)return Trueelse:self.sw[(datapath.id, eth_src, arp_dst_ip)] = in_portreturn False

3.3 时延最短

# min_delay.py
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
from ryu.lib.packet import ethernet
from ryu.lib.packet import ether_types
from ryu.lib.packet import arpfrom ryu.lib import hub
from ryu.topology.api import get_all_host, get_all_link, get_all_switch
from ryu.topology import event, switchesimport networkx as nx
import matplotlib.pyplot as pltETHERNET = ethernet.ethernet.__name__ #
ETHERNET_MULTICAST = "ff:ff:ff:ff:ff:ff" # broadcast mac
ARP = arp.arp.__name__class ARP_PROXY_13(app_manager.RyuApp):OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]def __init__(self, *args, **kwargs):super(ARP_PROXY_13, self).__init__(*args, **kwargs)self.mac_to_port = {} # {{dpid,dstmac}:port}self.arp_table = {} # {ip:mac}self.sw = {} # {(dpid,eth_src,arp_dst_ip):port}self.net = nx.DiGraph() # nx graphself.lldp_delay={} # record the delayself.switches = Noneself.topo_thread = hub.spawn(self._get_topology)@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)def switch_features_handler(self, ev):datapath = ev.msg.datapathofproto = datapath.ofprotoparser = datapath.ofproto_parsermatch = parser.OFPMatch()actions = [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.ofprotoparser = datapath.ofproto_parserinst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,actions)]mod = parser.OFPFlowMod(datapath=datapath, priority=priority,idle_timeout=5, hard_timeout=15,match=match, instructions=inst)datapath.send_msg(mod)def _get_topology(self):while True:#self.logger.info('\n')hosts = get_all_host(self)switch_list = get_all_switch(self)links_list = get_all_link(self)switches =[switch.dp.id for switch in switch_list]self.net.add_nodes_from(switches) # add nodeedges=[]for link in links_list:edges.append((link.src.dpid,link.dst.dpid,{'port':link.src.port_no}))self.net.add_edges_from(edges) # add edgehub.sleep(2) # get topo in 2 seconds@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)def _packet_in_handler(self, ev):msg = ev.msgdp = msg.datapathofp = dp.ofprotodpid = dp.idparser = dp.ofproto_parserin_port = msg.match['in_port']pkt = packet.Packet(msg.data)eth = pkt.get_protocols(ethernet.ethernet)[0]dst = eth.dstsrc = eth.srcsum_delay=0# acculate delayif eth.ethertype == ether_types.ETH_TYPE_LLDP:src_dpid, src_port_no = switches.LLDPPacket.lldp_parse(msg.data)if self.switches is None:self.switches = app_manager.lookup_service_brick('switches')for port in self.switches.ports.keys():if src_dpid == port.dpid and src_port_no == port.port_no:delay=self.switches.ports[port].delay*1000print("src_switch:%s   dst_switch:%s    delay:%s"%(src_dpid,dpid,delay))self.lldp_delay[(src_dpid,dpid)] = delayself.net.add_edge(src_dpid,dpid,weight = delay)self.net.add_edge(dpid,src_dpid,weight = delay)# Filtering out lldp package and IPv6 package will lead to the problem of topology acquisitionif eth.ethertype == ether_types.ETH_TYPE_LLDP or eth.ethertype == 34525:returnheader_list = dict((p.protocol_name, p)for p in pkt.protocols if type(p) != str)if ARP in header_list:self.arp_table[header_list[ARP].src_ip] = src  # ARP learningself.mac_to_port.setdefault(dpid, {})# learn a mac address to avoid FLOOD next time.self.mac_to_port[dpid][src] = in_port # L2LearningSwitch# add host to netif src not in self.net:self.net.add_node(src)self.net.add_edge(dpid, src, port=in_port, weight=0)self.net.add_edge(src, dpid, weight=0)if dst in self.mac_to_port[dpid]:out_port = self.mac_to_port[dpid][dst]if dst in self.net:path = nx.shortest_path(self.net, src, dst, weight='weight')print("path : %s" % path)if  dpid in path:next = path[path.index(dpid) + 1]out_port = self.net[dpid][next]['port']for i in range(1, len(path)-1):now_switch = path[i]next_switch = path[i+1]if i < len(path)-2:print("src_switch:%s   dst_switch:%s    delay:%s"%(now_switch,next_switch,self.net[now_switch][next_switch]['weight']))sum_delay = sum_delay + self.net[now_switch][next_switch]['weight']print("sum_delay: %s" % sum_delay)else:if self.arp_handler(header_list, dp, in_port, msg.buffer_id):# 1:reply or drop;  0: floodprint("ARP_PROXY_13")return Noneelse:out_port = ofp.OFPP_FLOODprint('OFPP_FLOOD')actions = [parser.OFPActionOutput(out_port)]# install a flow to avoid packet_icn next timeif out_port != ofp.OFPP_FLOOD:match = parser.OFPMatch(in_port=in_port, eth_dst=dst)self.add_flow(dp, 1, match, actions)data = Noneif msg.buffer_id == ofp.OFP_NO_BUFFER:data = msg.dataout = parser.OFPPacketOut(datapath=dp, buffer_id=msg.buffer_id,in_port=in_port, actions=actions, data=data)dp.send_msg(out)def arp_handler(self, header_list, datapath, in_port, msg_buffer_id):'''Using (dpid, srcmac, dstip) as the port corresponding to the key value record,each switch records the ARP request when it receives the broadcast for the first time,and discards the packet when it receives the ARP request with the same key value but different port next time,so as to avoid flooding'''header_list = header_listdatapath = datapathin_port = in_portif ETHERNET in header_list:eth_dst = header_list[ETHERNET].dsteth_src = header_list[ETHERNET].srcprint(header_list)if eth_dst == ETHERNET_MULTICAST and ARP in header_list:arp_dst_ip = header_list[ARP].dst_ip# If (datapath. ID, eth_ src, arp_ dst_ IP) in sw, directly discard the packet and return trueif (datapath.id, eth_src, arp_dst_ip) in self.sw:  # Break the loopif self.sw[(datapath.id, eth_src, arp_dst_ip)] != in_port:out = datapath.ofproto_parser.OFPPacketOut(datapath=datapath,buffer_id=datapath.ofproto.OFP_NO_BUFFER,in_port=in_port,actions=[], data=None)datapath.send_msg(out)return Trueelse:self.sw[(datapath.id, eth_src, arp_dst_ip)] = in_portreturn False

4 问题整理

  • 获取拓扑

    • 问题描述
      使用实验指导书中的获取拓扑代码,获取的拓扑是错误的。
    • 解决方法
      lldp包和ipv6包存在的情况会导致拓扑结构获取出现问题,_packet_in_handler()中应过滤掉lldp包和ipv6包
  • 获取时延
    • 问题描述
      使用实验指导书中获取时延代码,但获取的时延是错误的。
    • 解决方法
      启动加载自定义拓扑文件更改为sudo python SDNexp3Topo.py --controller remote

5 参考博客

  • 生成树协议STP介绍
  • networkx使用

SDN Experiment3相关推荐

  1. 全球SDN测试认证中心发布OpenDaylight测试报告

    随着软件定义网络(Software Defined Network, SDN)商业部署速度地加快,关乎整个SDN 网络性能表现的控制平面核心组件--SDN 控制器也越来越成为网络用户关心的焦点.日前, ...

  2. SDN:软件定义网络

    近期高级网络课的小组任务是在老师给定的范围内自选方向主题研究并做展示报告.我们组选了sdn.原以为这东西会是工业界无人问津的概念化产品,Google了一下却发现事实上sdn挺火的,因为它可能带来的可扩 ...

  3. SDN要防止七种认识偏差

    在过去几年中,SDN理念已经在业界获得极高关注.大部分企业已经意识到该技术的存在,并有计划地进行实施或者有计划地对其加以评估.但与此同时,关于该技术的认识偏差仍然广泛存在,归结起来共有七类常见误解. ...

  4. 技术沙龙 | TeaTalk 带你深度探索 SDN 网络技术再创新

    越来越多的企业.行业和政府机关顺应企业数字化转型.云服务和国家政策等趋势将业务迁移上云.随着移动云的快速发展,对网络提供差异化的服务能力也提出了很多新的考验.大规模数据中心.虚拟化 SDN 网络技术及 ...

  5. SDN 网络技术创新探索 | 移动云 TeaTalk 线上直播 倒计时启动中

    在企业数字化转型.云服务和国家政策等多种因素驱动下,越来越多的企业.行业和政府机关将业务迁移到云上,随着移动云的快速发展,在"多系统.多场景.多业务"需求下,对网络提供差异化的服务 ...

  6. Google VC投资SDN初创公司Plexxi

    近日,网络解决方案提供商Plexxi公司宣布,该公司已经收到了来自Google风险投资公司(简称GV)的风投资金. Plexxi公司并没有披露本次风投的规模及资金,但该公司表示在此前的几轮融资中一共募 ...

  7. 我看过的SDN方面的好文章

    本文不定期更新,最后更新于2019-5-25 SDN 技术分享 | OpenShift网络之SDN 央行数字货币研究所姚前:SDN增添金融科技新动力 SDN 技术指南(一):架构概览 SDN 技术指南 ...

  8. 计算机网络sdn,刘少伟:SDN重新定义网络

    ●SDN--客户需求驱动,为解决用户实际问题而生 它首先在数据中心发生,完美解决了多租户带来的虚拟机频繁.快速迁移问题.在WAN,它解决了广域带宽利用率低的问题,正在解决通过传统路由算法难以完美解决的 ...

  9. 2016年SDN通往成功路的5大步

    IT组织经常被企业需求搞的焦头烂额,迫切需要提高数据中心的效率和敏捷性.尽管SDN具备了高可见度.高网络灵活性等优点,但是它依然没有步入正轨,虽然有一些企业在2015年成功部署了SDN架构,但更多的企 ...

最新文章

  1. linux用yum安装svn,linux下 yum安装svn
  2. php 去掉数组中的空值_PHP删除数组中空值的方法介绍
  3. 草原深处的“那达慕”
  4. [cocos2dx-lua]Hello Lua分析
  5. IIS发布网站出现“未能加载文件或程序集“System.Data.SQLite”或它的某一个依赖项。”的解决方法...
  6. oracle 中某张表备份,张表系统流程(java程序备份及恢复SQL2000中数据库中的某张表)...
  7. dubbo mysql_Dubbo学习系列之六(微服务架构实战)
  8. C++-加载EXCEL数据
  9. 推荐项目| 微信小程序富文本解析组件-wxParse
  10. cmd整人小程序(e~~,不要乱用)
  11. KEIL下载程序失败系列问题
  12. mac终端常见命令大全
  13. MacBook上Wi-Fi抓包权限
  14. 流媒体开发之-音悦台TV解析特定条件下的所有TV视频
  15. 三农数据(1990-2020)七:农村居民家庭生产现金支出、农村固定资产构成、固定资产投向
  16. 上海交大计算机系王楠,交通学院本科生学生组织干部名单
  17. 滴滴顺风车即将重新上线,试运营方案涉嫌歧视女性乘客
  18. python精确有理数实验_有理数类实验报告
  19. 华为路由器虚拟服务器怎么设置方法,华为路由器PPPoE配置案例-华为路由器设置...
  20. ZOJ 3939。规律题

热门文章

  1. Arduino光敏传感器控制LED灯亮度
  2. PP飞桨 AI studio Notebook基础操作学习
  3. 《c语言入门题目19》判断一个数是不是质数(素数)
  4. c语言经典100例c13 条件运算符
  5. The Google File System中文版附英文资源链接(上)
  6. 【转】什么是WTW Wi-Fi 6(802.11ax)解析18:TWT节能机制(Target Wake Time)
  7. HART协议数据格式避坑(C语言压缩字符串Packed-ASCII和ASCII转换)
  8. OFDM系统同步技术的matlab仿真,包括符号定时同步,采样钟同步,频偏估计
  9. 【DevOps】2021.11 centos7搭建公司内网链接 ,集成openldap服务统一账号管理登录内网服务
  10. 走近棒球运动·克利夫兰守护者队·MLB棒球创造营