├── .gitignore ├── README.md └── multicastdemo.py /.gitignore: -------------------------------------------------------------------------------- 1 | smcroute 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mininet-multicast-routing 2 | 3 | This is a mininet setup based on: 4 | 5 | * https://fojta.wordpress.com/2014/09/24/troubleshooting-multicast-with-linux/ 6 | * https://github.com/troglobit/smcroute 7 | * https://github.com/mininet/mininet/blob/master/examples/linuxrouter.py 8 | 9 | # Requirements 10 | 11 | * Ubuntu 16.04 LTS 12 | * apt install mininet 13 | * sudo apt-get install openvswitch-testcontroller 14 | * sudo ln -s /usr/bin/ovs-testcontroller /usr/bin/controller 15 | 16 | (see https://stackoverflow.com/questions/21687357/mininet-ovs-controller-can-t-be-loaded-and-run) 17 | 18 | Install smcroute from source: 19 | 20 | ``` 21 | ./configure --prefix=/opt/smcroute --sysconfdir=/etc --localstatedir=/var 22 | make 23 | sudo make install 24 | ``` 25 | 26 | # Running demo 27 | 28 | ``` 29 | $ sudo ./multicastdemo.py 30 | *** Creating network 31 | *** Adding controller 32 | *** Adding hosts: 33 | h1 h2 h3 r0 34 | *** Adding switches: 35 | s1 s2 s3 36 | *** Adding links: 37 | (h1, s1) (h2, s2) (h3, s3) (s1, r0) (s2, r0) (s3, r0) 38 | *** Configuring hosts 39 | h1 h2 h3 r0 40 | *** Starting controller 41 | c0 42 | *** Starting 3 switches 43 | s1 s2 s3 ... 44 | *** Routing Table on Router: 45 | Kernel IP routing table 46 | Destination Gateway Genmask Flags Metric Ref Use Iface 47 | 10.0.0.0 * 255.0.0.0 U 0 0 0 r0-eth3 48 | 172.16.0.0 * 255.240.0.0 U 0 0 0 r0-eth2 49 | 192.168.1.0 * 255.255.255.0 U 0 0 0 r0-eth1 50 | *** Starting CLI: 51 | mininet> xterm r0 h1 h2 h3 52 | mininet> 53 | ``` 54 | 55 | In r0 xterm: 56 | 57 | ``` 58 | g# /opt/smcroute/sbin/smcroutectl -I smcroute-r0 show 59 | ROUTE (S,G) INBOUND PACKETS BYTES OUTBOUND 60 | (*, 239.0.0.3) r0-eth3 0000000000 0000000000 r0-eth1 r0-eth2 61 | (*, 239.0.0.2) r0-eth2 0000000000 0000000000 r0-eth1 r0-eth3 62 | (*, 239.0.0.1) r0-eth1 0000000000 0000000000 r0-eth2 r0-eth3 63 | ``` 64 | 65 | In h1 xterm: 66 | 67 | ``` 68 | # ping -t 2 239.0.0.1 69 | PING 239.0.0.1 (239.0.0.1) 56(84) bytes of data. 70 | 64 bytes from 192.168.1.100: icmp_seq=1 ttl=64 time=0.009 ms 71 | 64 bytes from 10.0.0.100: icmp_seq=1 ttl=63 time=9.36 ms (DUP!) 72 | 64 bytes from 172.16.0.100: icmp_seq=1 ttl=63 time=9.70 ms (DUP!) 73 | 64 bytes from 192.168.1.100: icmp_seq=2 ttl=64 time=0.018 ms 74 | 64 bytes from 10.0.0.100: icmp_seq=2 ttl=63 time=1.68 ms (DUP!) 75 | 64 bytes from 172.16.0.100: icmp_seq=2 ttl=63 time=2.14 ms (DUP!) 76 | # ip maddr 77 | # /opt/smcroute/sbin/smcroutectl -I smcroute-h1 join h1-eth0 239.0.0.1 78 | # /opt/smcroute/sbin/smcroutectl -I smcroute-h1 leave h1-eth0 239.0.0.1 79 | # /opt/smcroute/sbin/smcroutectl -I smcroute-h1 show 80 | ``` 81 | 82 | Hosts h2 and h3 are configured similarly 83 | 84 | * 239.0.0.1 is set up for sending from h1 85 | * 239.0.0.2 is set up for sending from h2 86 | * 239.0.0.3 is set up for sending from h3 87 | 88 | -------------------------------------------------------------------------------- /multicastdemo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | linuxrouter.py: Example network with Linux IP router 5 | 6 | This example converts a Node into a router using IP forwarding 7 | already built into Linux. 8 | 9 | The example topology creates a router and three IP subnets: 10 | 11 | - 192.168.1.0/24 (r0-eth1, IP: 192.168.1.1) 12 | - 172.16.0.0/12 (r0-eth2, IP: 172.16.0.1) 13 | - 10.0.0.0/8 (r0-eth3, IP: 10.0.0.1) 14 | 15 | Each subnet consists of a single host connected to 16 | a single switch: 17 | 18 | r0-eth1 - s1-eth1 - h1-eth0 (IP: 192.168.1.100) 19 | r0-eth2 - s2-eth1 - h2-eth0 (IP: 172.16.0.100) 20 | r0-eth3 - s3-eth1 - h3-eth0 (IP: 10.0.0.100) 21 | 22 | The example relies on default routing entries that are 23 | automatically created for each router interface, as well 24 | as 'defaultRoute' parameters for the host interfaces. 25 | 26 | Additional routes may be added to the router or hosts by 27 | executing 'ip route' or 'route' commands on the router or hosts. 28 | """ 29 | 30 | 31 | from mininet.topo import Topo 32 | from mininet.net import Mininet 33 | from mininet.node import Node 34 | from mininet.log import setLogLevel, info 35 | from mininet.cli import CLI 36 | 37 | 38 | class LinuxRouter( Node ): 39 | "A Node with IP forwarding enabled." 40 | 41 | def config( self, **params ): 42 | super( LinuxRouter, self).config( **params ) 43 | # Enable forwarding on the router 44 | self.cmd( 'sysctl net.ipv4.ip_forward=1' ) 45 | self.cmd( 'sysctl net.ipv4.icmp_echo_ignore_broadcasts=0' ) 46 | self.cmd( 'sysctl net.ipv4.conf.r0-eth1.force_igmp_version=2' ) 47 | self.cmd( 'sysctl net.ipv4.conf.r0-eth2.force_igmp_version=2' ) 48 | self.cmd( 'sysctl net.ipv4.conf.r0-eth3.force_igmp_version=2' ) 49 | self.cmd( '/opt/smcroute/sbin/smcrouted -l debug -I smcroute-r0' ) 50 | self.cmd( 'sleep 1') 51 | self.cmd( '/opt/smcroute/sbin/smcroutectl -I smcroute-r0 ' 52 | 'add r0-eth1 239.0.0.1 r0-eth2 r0-eth3' ) 53 | self.cmd( '/opt/smcroute/sbin/smcroutectl -I smcroute-r0 ' 54 | 'add r0-eth2 239.0.0.2 r0-eth1 r0-eth3' ) 55 | self.cmd( '/opt/smcroute/sbin/smcroutectl -I smcroute-r0 ' 56 | 'add r0-eth3 239.0.0.3 r0-eth1 r0-eth2' ) 57 | 58 | def terminate( self ): 59 | self.cmd( 'sysctl net.ipv4.ip_forward=0' ) 60 | self.cmd( '/opt/smcroute/sbin/smcroutectl -I smcroute-r0 kill' ) 61 | super( LinuxRouter, self ).terminate() 62 | 63 | class EdgeNode( Node ): 64 | "A Node with multicast stuff." 65 | 66 | def config( self, **params ): 67 | super( EdgeNode, self).config( **params ) 68 | intfName = self.intfNames()[0] 69 | self.cmd( 'sysctl net.ipv4.icmp_echo_ignore_broadcasts=0' ) 70 | self.cmd( 'route add -net 224.0.0.0 netmask 240.0.0.0 dev ' + intfName ) 71 | self.cmd( '/opt/smcroute/sbin/smcrouted -l debug -I smcroute-' + self.name ) 72 | self.cmd( 'sleep 1') 73 | self.cmd( '/opt/smcroute/sbin/smcroutectl -I smcroute-' + self.name + 74 | ' join ' + intfName + ' 239.0.0.1' ) 75 | self.cmd( '/opt/smcroute/sbin/smcroutectl -I smcroute-' + self.name + 76 | ' join ' + intfName + ' 239.0.0.2' ) 77 | self.cmd( '/opt/smcroute/sbin/smcroutectl -I smcroute-' + self.name + 78 | ' join ' + intfName + ' 239.0.0.3' ) 79 | 80 | def terminate( self ): 81 | self.cmd( '/opt/smcroute/sbin/smcroutectl -I smcroute-' + self.name + ' kill' ) 82 | super( EdgeNode, self ).terminate() 83 | 84 | 85 | class NetworkTopo( Topo ): 86 | "A LinuxRouter connecting three IP subnets" 87 | 88 | def build( self, **_opts ): 89 | 90 | defaultIP = '192.168.1.1/24' # IP address for r0-eth1 91 | router = self.addNode( 'r0', cls=LinuxRouter, ip=defaultIP ) 92 | 93 | s1, s2, s3 = [ self.addSwitch( s ) for s in ( 's1', 's2', 's3' ) ] 94 | 95 | self.addLink( s1, router, intfName2='r0-eth1', 96 | params2={ 'ip' : defaultIP } ) # for clarity 97 | self.addLink( s2, router, intfName2='r0-eth2', 98 | params2={ 'ip' : '172.16.0.1/12' } ) 99 | self.addLink( s3, router, intfName2='r0-eth3', 100 | params2={ 'ip' : '10.0.0.1/8' } ) 101 | 102 | h1 = self.addHost( 'h1', 103 | cls=EdgeNode, 104 | ip='192.168.1.100/24', 105 | defaultRoute='via 192.168.1.1' ) 106 | h2 = self.addHost( 'h2', 107 | cls=EdgeNode, 108 | ip='172.16.0.100/12', 109 | defaultRoute='via 172.16.0.1' ) 110 | h3 = self.addHost( 'h3', 111 | cls=EdgeNode, 112 | ip='10.0.0.100/8', 113 | defaultRoute='via 10.0.0.1' ) 114 | 115 | for h, s in [ (h1, s1), (h2, s2), (h3, s3) ]: 116 | self.addLink( h, s ) 117 | 118 | def run(): 119 | "Test linux router" 120 | topo = NetworkTopo() 121 | net = Mininet( topo=topo ) # controller is used by s1-s3 122 | net.start() 123 | 124 | """ 125 | r0 = net['r0'] 126 | r0.cmd( 'sysctl net.ipv4.conf.r0-eth1.force_igmp_version=2' ) 127 | r0.cmd( 'sysctl net.ipv4.conf.r0-eth2.force_igmp_version=2' ) 128 | r0.cmd( 'sysctl net.ipv4.conf.r0-eth3.force_igmp_version=2' ) 129 | r0.cmd( '/opt/smcroute/sbin/smcrouted -l debug -I smcroute-r0' ) 130 | r0.cmd( '/opt/smcroute/sbin/smcroutectl -I smcroute-r0 add r0-eth1 239.0.0.1 r0-eth2 r0-eth3' ) 131 | """ 132 | 133 | info( '*** Routing Table on Router:\n' ) 134 | info( net[ 'r0' ].cmd( 'route' ) ) 135 | CLI( net ) 136 | # r0.cmd( '/opt/smcroute/sbin/smcroutectl -I smcroute-r0 kill' ) 137 | net.stop() 138 | 139 | if __name__ == '__main__': 140 | setLogLevel( 'info' ) 141 | run() 142 | --------------------------------------------------------------------------------