Advertisement
hsiuyee

Untitled

Nov 12th, 2023
692
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 13.72 KB | None | 0 0
  1. #!/usr/bin/env python
  2. """@package topo
  3.  
  4. Network topology creation.
  5.  
  6. @author Brandon Heller (brandonh@stanford.edu)
  7.  
  8. This package includes code to represent network topologies.
  9.  
  10. A Topo object can be a topology database for NOX, can represent a physical
  11. setup for testing, and can even be emulated with the Mininet package.
  12. """
  13.  
  14. from mininet.util import irange, natural, naturalSeq
  15.  
  16. # pylint: disable=too-many-arguments
  17.  
  18.  
  19. class MultiGraph( object ):
  20.     "Utility class to track nodes and edges - replaces networkx.MultiGraph"
  21.  
  22.     def __init__( self ):
  23.         self.node = {}
  24.         self.edge = {}
  25.  
  26.     def add_node( self, node, attr_dict=None, **attrs):
  27.         """Add node to graph
  28.           attr_dict: attribute dict (optional)
  29.           attrs: more attributes (optional)
  30.           warning: updates attr_dict with attrs"""
  31.         attr_dict = {} if attr_dict is None else attr_dict
  32.         attr_dict.update( attrs )
  33.         self.node[ node ] = attr_dict
  34.  
  35.     def add_edge( self, src, dst, key=None, attr_dict=None, **attrs ):
  36.         """Add edge to graph
  37.           key: optional key
  38.           attr_dict: optional attribute dict
  39.           attrs: more attributes
  40.           warning: updates attr_dict with attrs"""
  41.         attr_dict = {} if attr_dict is None else attr_dict
  42.         attr_dict.update( attrs )
  43.         self.node.setdefault( src, {} )
  44.         self.node.setdefault( dst, {} )
  45.         self.edge.setdefault( src, {} )
  46.         self.edge.setdefault( dst, {} )
  47.         self.edge[ src ].setdefault( dst, {} )
  48.         entry = self.edge[ dst ][ src ] = self.edge[ src ][ dst ]
  49.         # If no key, pick next ordinal number
  50.         if key is None:
  51.             keys = [ k for k in entry.keys() if isinstance( k, int ) ]
  52.             key = max( [ 0 ] + keys ) + 1
  53.         entry[ key ] = attr_dict
  54.         return key
  55.  
  56.     def nodes( self, data=False):
  57.         """Return list of graph nodes
  58.           data: return list of ( node, attrs)"""
  59.         return self.node.items() if data else self.node.keys()
  60.  
  61.     def edges_iter( self, data=False, keys=False ):
  62.         "Iterator: return graph edges, optionally with data and keys"
  63.         for src, entry in self.edge.items():
  64.             for dst, entrykeys in entry.items():
  65.                 if src > dst:
  66.                     # Skip duplicate edges
  67.                     continue
  68.                 for k, attrs in entrykeys.items():
  69.                     if data:
  70.                         if keys:
  71.                             yield( src, dst, k, attrs )
  72.                         else:
  73.                             yield( src, dst, attrs )
  74.                     else:
  75.                         if keys:
  76.                             yield( src, dst, k )
  77.                         else:
  78.                             yield( src, dst )
  79.  
  80.     def edges( self, data=False, keys=False ):
  81.         "Return list of graph edges"
  82.         return list( self.edges_iter( data=data, keys=keys ) )
  83.  
  84.     def __getitem__( self, node ):
  85.         "Return link dict for given src node"
  86.         return self.edge[ node ]
  87.  
  88.     def __len__( self ):
  89.         "Return the number of nodes"
  90.         return len( self.node )
  91.  
  92.     def convertTo( self, cls, data=False, keys=False ):
  93.         """Convert to a new object of networkx.MultiGraph-like class cls
  94.           data: include node and edge data
  95.           keys: include edge keys as well as edge data"""
  96.         g = cls()
  97.         g.add_nodes_from( self.nodes( data=data ) )
  98.         g.add_edges_from( self.edges( data=( data or keys ), keys=keys ) )
  99.         return g
  100.  
  101.  
  102. class Topo( object ):
  103.     "Data center network representation for structured multi-trees."
  104.  
  105.     def __init__( self, *args, **params ):
  106.         """Topo object.
  107.           Optional named parameters:
  108.           hinfo: default host options
  109.           sopts: default switch options
  110.           lopts: default link options
  111.           calls build()"""
  112.         self.g = MultiGraph()
  113.         self.hopts = params.pop( 'hopts', {} )
  114.         self.sopts = params.pop( 'sopts', {} )
  115.         self.lopts = params.pop( 'lopts', {} )
  116.         # ports[src][dst][sport] is port on dst that connects to src
  117.         self.ports = {}
  118.         self.build( *args, **params )
  119.  
  120.     def build( self, *args, **params ):
  121.         "Override this method to build your topology."
  122.         # Add hosts
  123.         h1 = self.addHost('h1')
  124.         h2 = self.addHost('h2')
  125.         h3 = self.addHost('h3')
  126.         h4 = self.addHost('h4')
  127.  
  128.         # Add switches
  129.         s1 = self.addSwitch('s1')
  130.         s2 = self.addSwitch('s2')
  131.         s3 = self.addSwitch('s3')
  132.         s4 = self.addSwitch('s4')
  133.  
  134.         # Connect hosts to switches
  135.         self.addLink(h1, s1)
  136.         self.addLink(h2, s1)
  137.         self.addLink(h3, s2)
  138.         self.addLink(h4, s3)
  139.  
  140.         # Connect switches
  141.         self.addLink(s1, s2)
  142.         self.addLink(s1, s3)
  143.         self.addLink(s2, s4)
  144.         pass
  145.  
  146.     def addNode( self, name, **opts ):
  147.         """Add Node to graph.
  148.           name: name
  149.           opts: node options
  150.           returns: node name"""
  151.         self.g.add_node( name, **opts )
  152.         return name
  153.  
  154.     def addHost( self, name, **opts ):
  155.         """Convenience method: Add host to graph.
  156.           name: host name
  157.           opts: host options
  158.           returns: host name"""
  159.         if not opts and self.hopts:
  160.             opts = self.hopts
  161.         return self.addNode( name, **opts )
  162.  
  163.     def addSwitch( self, name, **opts ):
  164.         """Convenience method: Add switch to graph.
  165.           name: switch name
  166.           opts: switch options
  167.           returns: switch name"""
  168.         if not opts and self.sopts:
  169.             opts = self.sopts
  170.         result = self.addNode( name, isSwitch=True, **opts )
  171.         return result
  172.  
  173.     def addLink( self, node1, node2, port1=None, port2=None,
  174.                  key=None, **opts ):
  175.         """node1, node2: nodes to link together
  176.           port1, port2: ports (optional)
  177.           opts: link options (optional)
  178.           returns: link info key"""
  179.         if not opts and self.lopts:
  180.             opts = self.lopts
  181.         port1, port2 = self.addPort( node1, node2, port1, port2 )
  182.         opts = dict( opts )
  183.         opts.update( node1=node1, node2=node2, port1=port1, port2=port2 )
  184.         return self.g.add_edge(node1, node2, key, opts )
  185.  
  186.     def nodes( self, sort=True ):
  187.         "Return nodes in graph"
  188.         if sort:
  189.             return self.sorted( self.g.nodes() )
  190.         else:
  191.             return self.g.nodes()
  192.  
  193.     def isSwitch( self, n ):
  194.         "Returns true if node is a switch."
  195.         return self.g.node[ n ].get( 'isSwitch', False )
  196.  
  197.     def switches( self, sort=True ):
  198.         """Return switches.
  199.           sort: sort switches alphabetically
  200.           returns: dpids list of dpids"""
  201.         return [ n for n in self.nodes( sort ) if self.isSwitch( n ) ]
  202.  
  203.     def hosts( self, sort=True ):
  204.         """Return hosts.
  205.           sort: sort hosts alphabetically
  206.           returns: list of hosts"""
  207.         return [ n for n in self.nodes( sort ) if not self.isSwitch( n ) ]
  208.  
  209.     def iterLinks( self, withKeys=False, withInfo=False ):
  210.         """Return links (iterator)
  211.           withKeys: return link keys
  212.           withInfo: return link info
  213.           returns: list of ( src, dst [,key, info ] )"""
  214.         for _src, _dst, key, info in self.g.edges_iter( data=True, keys=True ):
  215.             node1, node2 = info[ 'node1' ], info[ 'node2' ]
  216.             if withKeys:
  217.                 if withInfo:
  218.                     yield( node1, node2, key, info )
  219.                 else:
  220.                     yield( node1, node2, key )
  221.             else:
  222.                 if withInfo:
  223.                     yield( node1, node2, info )
  224.                 else:
  225.                     yield( node1, node2 )
  226.  
  227.     def links( self, sort=False, withKeys=False, withInfo=False ):
  228.         """Return links
  229.           sort: sort links alphabetically, preserving (src, dst) order
  230.           withKeys: return link keys
  231.           withInfo: return link info
  232.           returns: list of ( src, dst [,key, info ] )"""
  233.         links = list( self.iterLinks( withKeys, withInfo ) )
  234.         if not sort:
  235.             return links
  236.         # Ignore info when sorting
  237.         tupleSize = 3 if withKeys else 2
  238.         return sorted( links, key=( lambda l: naturalSeq( l[ :tupleSize ] ) ) )
  239.  
  240.     # This legacy port management mechanism is clunky and will probably
  241.     # be removed at some point.
  242.  
  243.     def addPort( self, src, dst, sport=None, dport=None ):
  244.         """Generate port mapping for new edge.
  245.            src: source switch name
  246.            dst: destination switch name"""
  247.         # Initialize if necessary
  248.         ports = self.ports
  249.         ports.setdefault( src, {} )
  250.         ports.setdefault( dst, {} )
  251.         # New port: number of outlinks + base
  252.         if sport is None:
  253.             src_base = 1 if self.isSwitch( src ) else 0
  254.             sport = len( ports[ src ] ) + src_base
  255.         if dport is None:
  256.             dst_base = 1 if self.isSwitch( dst ) else 0
  257.             dport = len( ports[ dst ] ) + dst_base
  258.         ports[ src ][ sport ] = ( dst, dport )
  259.         ports[ dst ][ dport ] = ( src, sport )
  260.         return sport, dport
  261.  
  262.     def port( self, src, dst ):
  263.         """Get port numbers.
  264.            src: source switch name
  265.            dst: destination switch name
  266.            sport: optional source port (otherwise use lowest src port)
  267.            returns: tuple (sport, dport), where
  268.                sport = port on source switch leading to the destination switch
  269.                dport = port on destination switch leading to the source switch
  270.            Note that you can also look up ports using linkInfo()"""
  271.         # A bit ugly and slow vs. single-link implementation ;-(
  272.         ports = [ ( sport, entry[ 1 ] )
  273.                   for sport, entry in self.ports[ src ].items()
  274.                   if entry[ 0 ] == dst ]
  275.         return ports if len( ports ) != 1 else ports[ 0 ]
  276.  
  277.     def _linkEntry( self, src, dst, key=None ):
  278.         "Helper function: return link entry and key"
  279.         entry = self.g[ src ][ dst ]
  280.         if key is None:
  281.             key = min( entry )
  282.         return entry, key
  283.  
  284.     def linkInfo( self, src, dst, key=None ):
  285.         "Return link metadata dict"
  286.         entry, key = self._linkEntry( src, dst, key )
  287.         return entry[ key ]
  288.  
  289.     def setlinkInfo( self, src, dst, info, key=None ):
  290.         "Set link metadata dict"
  291.         entry, key = self._linkEntry( src, dst, key )
  292.         entry[ key ] = info
  293.  
  294.     def nodeInfo( self, name ):
  295.         "Return metadata (dict) for node"
  296.         return self.g.node[ name ]
  297.  
  298.     def setNodeInfo( self, name, info ):
  299.         "Set metadata (dict) for node"
  300.         self.g.node[ name ] = info
  301.  
  302.     def convertTo( self, cls, data=True, keys=True ):
  303.         """Convert to a new object of networkx.MultiGraph-like class cls
  304.           data: include node and edge data (default True)
  305.           keys: include edge keys as well as edge data (default True)"""
  306.         return self.g.convertTo( cls, data=data, keys=keys )
  307.  
  308.     @staticmethod
  309.     def sorted( items ):
  310.         "Items sorted in natural (i.e. alphabetical) order"
  311.         return sorted( items, key=natural )
  312.  
  313.  
  314. # Our idiom defines additional parameters in build(param...)
  315. # pylint: disable=arguments-differ
  316.  
  317. class SingleSwitchTopo( Topo ):
  318.     "Single switch connected to k hosts."
  319.  
  320.     def build( self, k=2, **_opts ):
  321.         "k: number of hosts"
  322.         self.k = k
  323.         switch = self.addSwitch( 's1' )
  324.         for h in irange( 1, k ):
  325.             host = self.addHost( 'h%s' % h )
  326.             self.addLink( host, switch )
  327.  
  328.  
  329. class SingleSwitchReversedTopo( Topo ):
  330.     """Single switch connected to k hosts, with reversed ports.
  331.       The lowest-numbered host is connected to the highest-numbered port.
  332.       Useful to verify that Mininet properly handles custom port
  333.       numberings."""
  334.  
  335.     def build( self, k=2 ):
  336.         "k: number of hosts"
  337.         self.k = k
  338.         switch = self.addSwitch( 's1' )
  339.         for h in irange( 1, k ):
  340.             host = self.addHost( 'h%s' % h )
  341.             self.addLink( host, switch,
  342.                           port1=0, port2=( k - h + 1 ) )
  343.  
  344.  
  345. class MinimalTopo( SingleSwitchTopo ):
  346.     "Minimal topology with two hosts and one switch"
  347.     def build( self ):
  348.         return SingleSwitchTopo.build( self, k=2 )
  349.  
  350. class LinearTopo( Topo ):
  351.     "Linear topology of k switches, with n hosts per switch."
  352.  
  353.     def build( self, k=2, n=1, **_opts):
  354.         """k: number of switches
  355.           n: number of hosts per switch"""
  356.         self.k = k
  357.         self.n = n
  358.  
  359.         if n == 1:
  360.             def genHostName( i, _j ):
  361.                 return 'h%s' % i
  362.         else:
  363.             def genHostName( i, j ):
  364.                 return 'h%ss%d' % ( j, i )
  365.  
  366.         lastSwitch = None
  367.         for i in irange( 1, k ):
  368.             # Add switch
  369.             switch = self.addSwitch( 's%s' % i )
  370.             # Add hosts to switch
  371.             for j in irange( 1, n ):
  372.                 host = self.addHost( genHostName( i, j ) )
  373.                 self.addLink( host, switch )
  374.             # Connect switch to previous
  375.             if lastSwitch:
  376.                 self.addLink( switch, lastSwitch )
  377.             lastSwitch = switch
  378.            
  379. '''
  380. # pylint: enable=arguments-differ
  381. ##### iperf #####
  382. print("hello world")
  383. h1 = net.get("h1")
  384. h2 = net.get("h2")
  385.  
  386. # Use tcpdump to record packet in background
  387. print("start to record trace in h2")
  388. h2.cmd("tcpdump -w ../oyt/h2_output.pcap &")
  389.  
  390. # Create flow via iperf
  391. print("create flow via iperf")
  392.  
  393. # TCP flow
  394. h2.cmd("iperf -s -i 1 -t 5 -p 7777 ? ../out/reslut_s.txt &")
  395. h1.cmd("iperf -c " + str(h2.IP()) + " -i 1 -t 5 -p 7777 ? ../out/reslut_c.txt &")
  396. '''
  397.  
  398.  
  399.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement