+++ /dev/null
-hostname r1
-log file /tmp/r1-ospf6d.log
-!
-debug ospf6 message all
-debug ospf6 lsa unknown
-debug ospf6 zebra
-debug ospf6 interface
-debug ospf6 neighbor
-debug ospf6 route table
-debug ospf6 flooding
-!
-interface r1-stubnet
- ipv6 ospf6 network broadcast
-!
-interface r1-sw5
- ipv6 ospf6 network broadcast
-!
-router ospf6
- router-id 10.0.0.1
- log-adjacency-changes detail
- redistribute static
- interface r1-stubnet area 0.0.0.0
- interface r1-sw5 area 0.0.0.0
-!
-line vty
- exec-timeout 0 0
-!
+++ /dev/null
-O fc00:1:1:1::/64 [110/10] is directly connected, r1-stubnet
-O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
-O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
-O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
-O fc00:a:a:a::/64 [110/10] is directly connected, r1-sw5
-O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
-O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
-O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
-O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
+++ /dev/null
-!
-hostname r1
-log file /tmp/r1-zebra.log
-!
-interface r1-stubnet
- ipv6 address fc00:1:1:1::1/64
-!
-interface r1-sw5
- ipv6 address fc00:a:a:a::1/64
-!
-interface lo
-!
-ipv6 route fc00:1111:1111:1111::/64 fc00:1:1:1::1234
-!
-!
-line vty
-!
+++ /dev/null
-hostname r2
-log file /tmp/r2-ospf6d.log
-!
-debug ospf6 message all
-debug ospf6 lsa unknown
-debug ospf6 zebra
-debug ospf6 interface
-debug ospf6 neighbor
-debug ospf6 route table
-debug ospf6 flooding
-!
-interface r2-stubnet
- ipv6 ospf6 network broadcast
-!
-interface r2-sw5
- ipv6 ospf6 network broadcast
-!
-router ospf6
- router-id 10.0.0.2
- log-adjacency-changes detail
- redistribute static
- interface r2-stubnet area 0.0.0.0
- interface r2-sw5 area 0.0.0.0
-!
-line vty
- exec-timeout 0 0
-!
+++ /dev/null
-O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
-O fc00:2:2:2::/64 [110/10] is directly connected, r2-stubnet
-O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
-O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
-O fc00:a:a:a::/64 [110/10] is directly connected, r2-sw5
-O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
-O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
-O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
-O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
-
+++ /dev/null
-!
-hostname r2
-log file /tmp/r2-zebra.log
-!
-interface r2-stubnet
- ipv6 address fc00:2:2:2::2/64
-!
-interface r2-sw5
- ipv6 address fc00:a:a:a::2/64
-!
-interface lo
-!
-ipv6 route fc00:2222:2222:2222::/64 fc00:2:2:2::1234
-!
-!
-line vty
-!
+++ /dev/null
-hostname r3
-log file /tmp/r3-ospf6d.log
-!
-debug ospf6 message all
-debug ospf6 lsa unknown
-debug ospf6 zebra
-debug ospf6 interface
-debug ospf6 neighbor
-debug ospf6 route table
-debug ospf6 flooding
-!
-interface r3-stubnet
- ipv6 ospf6 network broadcast
-!
-interface r3-sw5
- ipv6 ospf6 network broadcast
-!
-interface r3-sw6
- ipv6 ospf6 network broadcast
-!
-router ospf6
- router-id 10.0.0.3
- log-adjacency-changes detail
- redistribute static
- interface r3-stubnet area 0.0.0.0
- interface r3-sw5 area 0.0.0.0
- interface r3-sw6 area 0.0.0.1
-!
-line vty
- exec-timeout 0 0
-!
+++ /dev/null
-O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5
-O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5
-O fc00:3:3:3::/64 [110/10] is directly connected, r3-stubnet
-O>* fc00:4:4:4::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6
-O fc00:a:a:a::/64 [110/10] is directly connected, r3-sw5
-O fc00:b:b:b::/64 [110/10] is directly connected, r3-sw6
-O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5
-O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5
-O>* fc00:4444:4444:4444::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6
-
+++ /dev/null
-!
-hostname r3
-log file /tmp/r3-zebra.log
-!
-interface r3-stubnet
- ipv6 address fc00:3:3:3::3/64
-!
-interface r3-sw5
- ipv6 address fc00:a:a:a::3/64
-!
-interface r3-sw6
- ipv6 address fc00:b:b:b::3/64
-!
-interface lo
-!
-ipv6 route fc00:3333:3333:3333::/64 fc00:3:3:3::1234
-!
-!
-line vty
-!
+++ /dev/null
-hostname r4
-log file /tmp/r4-ospf6d.log
-!
-debug ospf6 message all
-debug ospf6 lsa unknown
-debug ospf6 zebra
-debug ospf6 interface
-debug ospf6 neighbor
-debug ospf6 route table
-debug ospf6 flooding
-!
-interface r4-stubnet
- ipv6 ospf6 network broadcast
-!
-interface r4-sw6
- ipv6 ospf6 network broadcast
-!
-router ospf6
- router-id 10.0.0.4
- log-adjacency-changes detail
- redistribute static
- interface r4-stubnet area 0.0.0.1
- interface r4-sw6 area 0.0.0.1
-!
-line vty
- exec-timeout 0 0
-!
+++ /dev/null
-O>* fc00:1:1:1::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
-O>* fc00:2:2:2::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
-O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
-O fc00:4:4:4::/64 [110/10] is directly connected, r4-stubnet
-O>* fc00:a:a:a::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
-O fc00:b:b:b::/64 [110/10] is directly connected, r4-sw6
-O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
-O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
-O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
+++ /dev/null
-!
-hostname r4
-log file /tmp/r4-zebra.log
-!
-interface r4-stubnet
- ipv6 address fc00:4:4:4::4/64
-!
-interface r4-sw6
- ipv6 address fc00:b:b:b::4/64
-!
-interface lo
-!
-ipv6 route fc00:4444:4444:4444::/64 fc00:4:4:4::1234
-!
-!
-line vty
-!
+++ /dev/null
-#!/usr/bin/env python
-
-#
-# ospf6-test1.py
-# Part of NetDEF Topology Tests
-#
-# Copyright (c) 2016 by
-# Network Device Education Foundation, Inc. ("NetDEF")
-#
-# Permission to use, copy, modify, and/or distribute this software
-# for any purpose with or without fee is hereby granted, provided
-# that the above copyright notice and this permission notice appear
-# in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
-# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
-# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
-# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
-# OF THIS SOFTWARE.
-#
-
-"""
-ospf6-test1.py:
-
- -----\
- SW1 - Stub Net 1 SW2 - Stub Net 2 \
- fc00:1:1:1::/64 fc00:2:2:2::/64 \
-\___________________/ \___________________/ |
- | | |
- | | |
- | ::1 | ::2 |
-+---------+---------+ +---------+---------+ |
-| R1 | | R2 | |
-| Quagga | | Quagga | |
-| Rtr-ID: 10.0.0.1 | | Rtr-ID: 10.0.0.2 | |
-+---------+---------+ +---------+---------+ |
- | ::1 | ::2 \
- \______ ___________/ OSPFv3
- \ / Area 0.0.0.0
- \ / /
- ~~~~~~~~~~~~~~~~~~ |
- ~~ SW5 ~~ |
- ~~ Switch ~~ |
- ~~ fc00:A:A:A::/64 ~~ |
- ~~~~~~~~~~~~~~~~~~ |
- | /---- |
- | ::3 | SW3 - Stub Net 3 |
- +---------+---------+ /-+ fc00:3:3:3::/64 |
- | R3 | / | /
- | Quagga +--/ \---- /
- | Rtr-ID: 10.0.0.3 | ::3 ___________/
- +---------+---------+ \
- | ::3 \
- | \
- ~~~~~~~~~~~~~~~~~~ |
- ~~ SW6 ~~ |
- ~~ Switch ~~ |
- ~~ fc00:B:B:B::/64 ~~ \
- ~~~~~~~~~~~~~~~~~~ OSPFv3
- | Area 0.0.0.1
- | ::4 /
- +---------+---------+ /---- |
- | R4 | | SW4 - Stub Net 4 |
- | Quagga +------+ fc00:4:4:4::/64 |
- | Rtr-ID: 10.0.0.4 | ::4 | /
- +-------------------+ \---- /
- -----/
-"""
-
-import os
-import re
-import StringIO
-import sys
-import difflib
-
-from pprint import pprint
-
-from mininet.topo import Topo
-from mininet.net import Mininet
-from mininet.node import Node, OVSSwitch, Host
-from mininet.log import setLogLevel, info
-from mininet.cli import CLI
-
-from functools import partial
-from time import sleep
-
-def int2dpid(dpid):
- "Converting Integer to DPID"
-
- try:
- dpid = hex(dpid)[2:]
- dpid = '0'*(16-len(dpid))+dpid
- return dpid
- except IndexError:
- raise Exception('Unable to derive default datapath ID - '
- 'please either specify a dpid or use a '
- 'canonical switch name such as s23.')
-class LinuxRouter(Node):
- "A Node with IPv4/IPv6 forwarding enabled."
-
- def config(self, **params):
- super(LinuxRouter, self).config(**params)
- # Enable forwarding on the router
- self.cmd('sysctl net.ipv4.ip_forward=1')
- self.cmd('sysctl net.ipv6.conf.all.forwarding=1')
- def terminate(self):
- """
- Terminate generic LinuxRouter Mininet instance
- """
- self.cmd('sysctl net.ipv4.ip_forward=0')
- self.cmd('sysctl net.ipv6.conf.all.forwarding=0')
- super(LinuxRouter, self).terminate()
-
-class QuaggaRouter(Node):
- "A Node with IPv4/IPv6 forwarding enabled and Quagga as Routing Engine"
-
- def config(self, **params):
- super(QuaggaRouter, self).config(**params)
- # Enable forwarding on the router
- self.cmd('sysctl net.ipv4.ip_forward=1')
- self.cmd('sysctl net.ipv6.conf.all.forwarding=1')
- self.cmd('chown quagga:quaggavty /etc/quagga')
- self.daemons = {'zebra': 0, 'ripd': 0, 'ripngd': 0, 'ospfd': 0,
- 'ospf6d': 0, 'isisd': 0, 'bgpd': 0, 'pimd': 0}
- def terminate(self):
- # Delete Running Quagga Daemons
- rundaemons = self.cmd('ls -1 /var/run/quagga/*.pid')
- for d in StringIO.StringIO(rundaemons):
- self.cmd('kill -7 `cat %s`' % d.rstrip())
- self.waitOutput()
- # Disable forwarding
- self.cmd('sysctl net.ipv4.ip_forward=0')
- self.cmd('sysctl net.ipv6.conf.all.forwarding=0')
- super(QuaggaRouter, self).terminate()
- def removeIPs(self):
- for interface in self.intfNames():
- self.cmd('ip address flush', interface)
- def loadConf(self, daemon, source=None):
- # print "Daemons before:", self.daemons
- if daemon in self.daemons.keys():
- self.daemons[daemon] = 1
- if source is None:
- self.cmd('touch /etc/quagga/%s.conf' % daemon)
- self.waitOutput()
- else:
- self.cmd('cp %s /etc/quagga/%s.conf' % (source, daemon))
- self.waitOutput()
- self.cmd('chmod 640 /etc/quagga/%s.conf' % daemon)
- self.waitOutput()
- self.cmd('chown quagga:quagga /etc/quagga/%s.conf' % daemon)
- self.waitOutput()
- else:
- print("No daemon %s known" % daemon)
- # print "Daemons after:", self.daemons
- def startQuagga(self):
- # Disable integrated-vtysh-config
- self.cmd('echo "no service integrated-vtysh-config" > /etc/quagga/vtysh.conf')
- with open("/etc/quagga/vtysh.conf", "w") as vtyshfile:
- vtyshfile.write('no service integrated-vtysh-config')
- self.cmd('chown quagga:quaggavty /etc/quagga/vtysh.conf')
- # Remove IP addresses from OS first - we have them in zebra.conf
- self.removeIPs()
- # Start Zebra first
- if self.daemons['zebra'] == 1:
- self.cmd('/usr/lib/quagga/zebra -d')
- self.waitOutput()
- print('%s: zebra started' % self)
- sleep(1)
- # Fix Link-Local Addresses
- # Somehow (on Mininet only), Zebra removes the IPv6 Link-Local addresses on start. Fix this
- self.cmd('for i in `ls /sys/class/net/` ; do mac=`cat /sys/class/net/$i/address`; IFS=\':\'; set $mac; unset IFS; ip address add dev $i scope link fe80::$(printf %02x $((0x$1 ^ 2)))$2:${3}ff:fe$4:$5$6/64; done')
- # Now start all the other daemons
- for daemon in self.daemons:
- if (self.daemons[daemon] == 1) and (daemon != 'zebra'):
- self.cmd('/usr/lib/quagga/%s -d' % daemon)
- self.waitOutput()
- print('%s: %s started' % (self, daemon))
-
-
-class LegacySwitch(OVSSwitch):
- "A Legacy Switch without OpenFlow"
-
- def __init__(self, name, **params):
- OVSSwitch.__init__(self, name, failMode='standalone', **params)
- self.switchIP = None
-
-class NetworkTopo(Topo):
- "A Quagga Topology with direct peering router and IXP connection"
-
- def build(self, **_opts):
-
- quaggaPrivateDirs = ['/etc/quagga',
- '/var/run/quagga',
- '/var/log']
- #
- # Define Switches first
- #
- switch = {}
- for i in range(1, 7):
- switch[i] = self.addSwitch('SW%s' % i, dpid=int2dpid(i),
- cls=LegacySwitch)
- #
- # Define Quagga Routers
- #
- router = {}
- for i in range(1, 5):
- router[i] = self.addNode('r%s' % i, cls=QuaggaRouter,
- privateDirs=quaggaPrivateDirs)
- #
- # Wire up the switches and routers
- #
- # Stub nets
- for i in range(1, 5):
- self.addLink(switch[i], router[i], intfName2='r%s-stubnet' % i)
- # Switch 5
- self.addLink(switch[5], router[1], intfName2='r1-sw5')
- self.addLink(switch[5], router[2], intfName2='r2-sw5')
- self.addLink(switch[5], router[3], intfName2='r3-sw5')
- # Switch 6
- self.addLink(switch[6], router[3], intfName2='r3-sw6')
- self.addLink(switch[6], router[4], intfName2='r4-sw6')
-
-
-def run():
- "ospf6-test1 Topology"
-
- thisDir = os.path.dirname(os.path.realpath(__file__))
- topo = NetworkTopo()
-
- net = Mininet(controller=None, topo=topo)
- net.start()
-
- # Starting Routers
- for i in range(1, 5):
- net['r%s' % i].loadConf('zebra', '%s/r%s/zebra.conf' % (thisDir, i))
- net['r%s' % i].loadConf('ospf6d', '%s/r%s/ospf6d.conf' % (thisDir, i))
- net['r%s' % i].startQuagga()
-
- print('')
-
- #
- # Stop here for all manual checks
- #
- #CLI(net)
-
- # Wait for OSPF6 to converge (All Neighbors in either Full or TwoWay State)
- print("Waiting for OSPFv3 neighbors to establish (to Full)")
- timeout = 60
- while timeout > 0:
- print("Timeout in %s: " % timeout),
- sys.stdout.flush()
- # Look for any node not yet converged
- for i in range(1, 5):
- notConverged = net['r%s' % i].cmd('vtysh -c "show ipv6 ospf neigh" 2> /dev/null | grep ^[0-9] | grep -v Full')
- if notConverged:
- print('Waiting for r%s' %i),
- sys.stdout.flush()
- break
- if notConverged:
- sleep(2)
- timeout -= 2
- print('\r \r'),
- else:
- print('\rDone ')
- print(notConverged)
- break
- else:
- # Bail out with error if a router fails to converge
- sys.stderr.write("Router r%s failed to converge\n" % i)
- ospfStatus = net['r%s' % i].cmd('vtysh -c "show ipv6 ospf neigh"')
- sys.stderr.write("Status:\n%s" % ospfStatus)
- net.stop()
- sys.exit(1)
- print("OSPFv3 converged.")
-
- print("\nwaiting 15s for routes to populate")
- sleep(15)
-
- # Verify OSPFv3 Routing Table
- print("\nVerifing OSPFv3 Routing Table")
- failures = 0
- for i in range(1, 5):
- refTableFile = '%s/r%s/show_ipv6_route.ref' % (thisDir, i)
- if os.path.isfile(refTableFile):
- # Read expected result from file
- expected = open(refTableFile).read().rstrip()
- # Fix newlines (make them all the same)
- expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
-
- # Actual output from router
- actual = net['r%s' % i].cmd('vtysh -c "show ipv6 route" 2> /dev/null | grep "^O"').rstrip()
- # Mask out Link-Local mac address portion. They are random...
- actual = re.sub(r" fe80::[0-9a-f:]+", " fe80::XXXX:XXXX:XXXX:XXXX", actual)
- # Drop timers on end of line (older Quagga Versions)
- actual = re.sub(r", [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", "", actual)
- # Fix newlines (make them all the same)
- actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
-
- # Generate Diff
- diff=difflib.unified_diff(actual, expected)
- diff=''.join(diff)
- # Empty string if it matches, otherwise diff contains unified diff
- if diff:
- sys.stderr.write('r%s failed Routing Table Check:\n%s\n' % (i, diff))
- failures += 1
- else:
- print("r%s ok" % i)
-
- #
- # Stop here for manual checks after tests are executed
- #
- # CLI(net)
-
- # End - Shutdown network
- net.stop()
-
- # Set non-zero exit status in case of failures
- if failures > 0:
- sys.stderr.write("Verification failed\n")
- sys.exit(1)
- else:
- print("Verification Successful")
-
-if __name__ == '__main__':
- setLogLevel('info')
- run()
--- /dev/null
+hostname r1
+log file /tmp/r1-ospf6d.log
+!
+debug ospf6 message all
+debug ospf6 lsa unknown
+debug ospf6 zebra
+debug ospf6 interface
+debug ospf6 neighbor
+debug ospf6 route table
+debug ospf6 flooding
+!
+interface r1-stubnet
+ ipv6 ospf6 network broadcast
+!
+interface r1-sw5
+ ipv6 ospf6 network broadcast
+!
+router ospf6
+ router-id 10.0.0.1
+ log-adjacency-changes detail
+ redistribute static
+ interface r1-stubnet area 0.0.0.0
+ interface r1-sw5 area 0.0.0.0
+!
+line vty
+ exec-timeout 0 0
+!
--- /dev/null
+O fc00:1:1:1::/64 [110/10] is directly connected, r1-stubnet
+O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
+O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
+O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
+O fc00:a:a:a::/64 [110/10] is directly connected, r1-sw5
+O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
+O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
+O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
+O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
--- /dev/null
+!
+hostname r1
+log file /tmp/r1-zebra.log
+!
+interface r1-stubnet
+ ipv6 address fc00:1:1:1::1/64
+!
+interface r1-sw5
+ ipv6 address fc00:a:a:a::1/64
+!
+interface lo
+!
+ipv6 route fc00:1111:1111:1111::/64 fc00:1:1:1::1234
+!
+!
+line vty
+!
--- /dev/null
+hostname r2
+log file /tmp/r2-ospf6d.log
+!
+debug ospf6 message all
+debug ospf6 lsa unknown
+debug ospf6 zebra
+debug ospf6 interface
+debug ospf6 neighbor
+debug ospf6 route table
+debug ospf6 flooding
+!
+interface r2-stubnet
+ ipv6 ospf6 network broadcast
+!
+interface r2-sw5
+ ipv6 ospf6 network broadcast
+!
+router ospf6
+ router-id 10.0.0.2
+ log-adjacency-changes detail
+ redistribute static
+ interface r2-stubnet area 0.0.0.0
+ interface r2-sw5 area 0.0.0.0
+!
+line vty
+ exec-timeout 0 0
+!
--- /dev/null
+O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
+O fc00:2:2:2::/64 [110/10] is directly connected, r2-stubnet
+O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
+O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
+O fc00:a:a:a::/64 [110/10] is directly connected, r2-sw5
+O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
+O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
+O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
+O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
+
--- /dev/null
+!
+hostname r2
+log file /tmp/r2-zebra.log
+!
+interface r2-stubnet
+ ipv6 address fc00:2:2:2::2/64
+!
+interface r2-sw5
+ ipv6 address fc00:a:a:a::2/64
+!
+interface lo
+!
+ipv6 route fc00:2222:2222:2222::/64 fc00:2:2:2::1234
+!
+!
+line vty
+!
--- /dev/null
+hostname r3
+log file /tmp/r3-ospf6d.log
+!
+debug ospf6 message all
+debug ospf6 lsa unknown
+debug ospf6 zebra
+debug ospf6 interface
+debug ospf6 neighbor
+debug ospf6 route table
+debug ospf6 flooding
+!
+interface r3-stubnet
+ ipv6 ospf6 network broadcast
+!
+interface r3-sw5
+ ipv6 ospf6 network broadcast
+!
+interface r3-sw6
+ ipv6 ospf6 network broadcast
+!
+router ospf6
+ router-id 10.0.0.3
+ log-adjacency-changes detail
+ redistribute static
+ interface r3-stubnet area 0.0.0.0
+ interface r3-sw5 area 0.0.0.0
+ interface r3-sw6 area 0.0.0.1
+!
+line vty
+ exec-timeout 0 0
+!
--- /dev/null
+O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5
+O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5
+O fc00:3:3:3::/64 [110/10] is directly connected, r3-stubnet
+O>* fc00:4:4:4::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6
+O fc00:a:a:a::/64 [110/10] is directly connected, r3-sw5
+O fc00:b:b:b::/64 [110/10] is directly connected, r3-sw6
+O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5
+O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5
+O>* fc00:4444:4444:4444::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6
+
--- /dev/null
+!
+hostname r3
+log file /tmp/r3-zebra.log
+!
+interface r3-stubnet
+ ipv6 address fc00:3:3:3::3/64
+!
+interface r3-sw5
+ ipv6 address fc00:a:a:a::3/64
+!
+interface r3-sw6
+ ipv6 address fc00:b:b:b::3/64
+!
+interface lo
+!
+ipv6 route fc00:3333:3333:3333::/64 fc00:3:3:3::1234
+!
+!
+line vty
+!
--- /dev/null
+hostname r4
+log file /tmp/r4-ospf6d.log
+!
+debug ospf6 message all
+debug ospf6 lsa unknown
+debug ospf6 zebra
+debug ospf6 interface
+debug ospf6 neighbor
+debug ospf6 route table
+debug ospf6 flooding
+!
+interface r4-stubnet
+ ipv6 ospf6 network broadcast
+!
+interface r4-sw6
+ ipv6 ospf6 network broadcast
+!
+router ospf6
+ router-id 10.0.0.4
+ log-adjacency-changes detail
+ redistribute static
+ interface r4-stubnet area 0.0.0.1
+ interface r4-sw6 area 0.0.0.1
+!
+line vty
+ exec-timeout 0 0
+!
--- /dev/null
+O>* fc00:1:1:1::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
+O>* fc00:2:2:2::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
+O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
+O fc00:4:4:4::/64 [110/10] is directly connected, r4-stubnet
+O>* fc00:a:a:a::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
+O fc00:b:b:b::/64 [110/10] is directly connected, r4-sw6
+O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
+O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
+O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
--- /dev/null
+!
+hostname r4
+log file /tmp/r4-zebra.log
+!
+interface r4-stubnet
+ ipv6 address fc00:4:4:4::4/64
+!
+interface r4-sw6
+ ipv6 address fc00:b:b:b::4/64
+!
+interface lo
+!
+ipv6 route fc00:4444:4444:4444::/64 fc00:4:4:4::1234
+!
+!
+line vty
+!
--- /dev/null
+#!/usr/bin/env python
+
+#
+# ospf6-test1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2016 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+ospf6-test1.py:
+
+ -----\
+ SW1 - Stub Net 1 SW2 - Stub Net 2 \
+ fc00:1:1:1::/64 fc00:2:2:2::/64 \
+\___________________/ \___________________/ |
+ | | |
+ | | |
+ | ::1 | ::2 |
++---------+---------+ +---------+---------+ |
+| R1 | | R2 | |
+| Quagga | | Quagga | |
+| Rtr-ID: 10.0.0.1 | | Rtr-ID: 10.0.0.2 | |
++---------+---------+ +---------+---------+ |
+ | ::1 | ::2 \
+ \______ ___________/ OSPFv3
+ \ / Area 0.0.0.0
+ \ / /
+ ~~~~~~~~~~~~~~~~~~ |
+ ~~ SW5 ~~ |
+ ~~ Switch ~~ |
+ ~~ fc00:A:A:A::/64 ~~ |
+ ~~~~~~~~~~~~~~~~~~ |
+ | /---- |
+ | ::3 | SW3 - Stub Net 3 |
+ +---------+---------+ /-+ fc00:3:3:3::/64 |
+ | R3 | / | /
+ | Quagga +--/ \---- /
+ | Rtr-ID: 10.0.0.3 | ::3 ___________/
+ +---------+---------+ \
+ | ::3 \
+ | \
+ ~~~~~~~~~~~~~~~~~~ |
+ ~~ SW6 ~~ |
+ ~~ Switch ~~ |
+ ~~ fc00:B:B:B::/64 ~~ \
+ ~~~~~~~~~~~~~~~~~~ OSPFv3
+ | Area 0.0.0.1
+ | ::4 /
+ +---------+---------+ /---- |
+ | R4 | | SW4 - Stub Net 4 |
+ | Quagga +------+ fc00:4:4:4::/64 |
+ | Rtr-ID: 10.0.0.4 | ::4 | /
+ +-------------------+ \---- /
+ -----/
+"""
+
+import os
+import re
+import StringIO
+import sys
+import difflib
+
+from pprint import pprint
+
+from mininet.topo import Topo
+from mininet.net import Mininet
+from mininet.node import Node, OVSSwitch, Host
+from mininet.log import setLogLevel, info
+from mininet.cli import CLI
+
+from functools import partial
+from time import sleep
+
+def int2dpid(dpid):
+ "Converting Integer to DPID"
+
+ try:
+ dpid = hex(dpid)[2:]
+ dpid = '0'*(16-len(dpid))+dpid
+ return dpid
+ except IndexError:
+ raise Exception('Unable to derive default datapath ID - '
+ 'please either specify a dpid or use a '
+ 'canonical switch name such as s23.')
+class LinuxRouter(Node):
+ "A Node with IPv4/IPv6 forwarding enabled."
+
+ def config(self, **params):
+ super(LinuxRouter, self).config(**params)
+ # Enable forwarding on the router
+ self.cmd('sysctl net.ipv4.ip_forward=1')
+ self.cmd('sysctl net.ipv6.conf.all.forwarding=1')
+ def terminate(self):
+ """
+ Terminate generic LinuxRouter Mininet instance
+ """
+ self.cmd('sysctl net.ipv4.ip_forward=0')
+ self.cmd('sysctl net.ipv6.conf.all.forwarding=0')
+ super(LinuxRouter, self).terminate()
+
+class QuaggaRouter(Node):
+ "A Node with IPv4/IPv6 forwarding enabled and Quagga as Routing Engine"
+
+ def config(self, **params):
+ super(QuaggaRouter, self).config(**params)
+ # Enable forwarding on the router
+ self.cmd('sysctl net.ipv4.ip_forward=1')
+ self.cmd('sysctl net.ipv6.conf.all.forwarding=1')
+ self.cmd('chown quagga:quaggavty /etc/quagga')
+ self.daemons = {'zebra': 0, 'ripd': 0, 'ripngd': 0, 'ospfd': 0,
+ 'ospf6d': 0, 'isisd': 0, 'bgpd': 0, 'pimd': 0}
+ def terminate(self):
+ # Delete Running Quagga Daemons
+ rundaemons = self.cmd('ls -1 /var/run/quagga/*.pid')
+ for d in StringIO.StringIO(rundaemons):
+ self.cmd('kill -7 `cat %s`' % d.rstrip())
+ self.waitOutput()
+ # Disable forwarding
+ self.cmd('sysctl net.ipv4.ip_forward=0')
+ self.cmd('sysctl net.ipv6.conf.all.forwarding=0')
+ super(QuaggaRouter, self).terminate()
+ def removeIPs(self):
+ for interface in self.intfNames():
+ self.cmd('ip address flush', interface)
+ def loadConf(self, daemon, source=None):
+ # print "Daemons before:", self.daemons
+ if daemon in self.daemons.keys():
+ self.daemons[daemon] = 1
+ if source is None:
+ self.cmd('touch /etc/quagga/%s.conf' % daemon)
+ self.waitOutput()
+ else:
+ self.cmd('cp %s /etc/quagga/%s.conf' % (source, daemon))
+ self.waitOutput()
+ self.cmd('chmod 640 /etc/quagga/%s.conf' % daemon)
+ self.waitOutput()
+ self.cmd('chown quagga:quagga /etc/quagga/%s.conf' % daemon)
+ self.waitOutput()
+ else:
+ print("No daemon %s known" % daemon)
+ # print "Daemons after:", self.daemons
+ def startQuagga(self):
+ # Disable integrated-vtysh-config
+ self.cmd('echo "no service integrated-vtysh-config" > /etc/quagga/vtysh.conf')
+ with open("/etc/quagga/vtysh.conf", "w") as vtyshfile:
+ vtyshfile.write('no service integrated-vtysh-config')
+ self.cmd('chown quagga:quaggavty /etc/quagga/vtysh.conf')
+ # Remove IP addresses from OS first - we have them in zebra.conf
+ self.removeIPs()
+ # Start Zebra first
+ if self.daemons['zebra'] == 1:
+ self.cmd('/usr/lib/quagga/zebra -d')
+ self.waitOutput()
+ print('%s: zebra started' % self)
+ sleep(1)
+ # Fix Link-Local Addresses
+ # Somehow (on Mininet only), Zebra removes the IPv6 Link-Local addresses on start. Fix this
+ self.cmd('for i in `ls /sys/class/net/` ; do mac=`cat /sys/class/net/$i/address`; IFS=\':\'; set $mac; unset IFS; ip address add dev $i scope link fe80::$(printf %02x $((0x$1 ^ 2)))$2:${3}ff:fe$4:$5$6/64; done')
+ # Now start all the other daemons
+ for daemon in self.daemons:
+ if (self.daemons[daemon] == 1) and (daemon != 'zebra'):
+ self.cmd('/usr/lib/quagga/%s -d' % daemon)
+ self.waitOutput()
+ print('%s: %s started' % (self, daemon))
+
+
+class LegacySwitch(OVSSwitch):
+ "A Legacy Switch without OpenFlow"
+
+ def __init__(self, name, **params):
+ OVSSwitch.__init__(self, name, failMode='standalone', **params)
+ self.switchIP = None
+
+class NetworkTopo(Topo):
+ "A Quagga Topology with direct peering router and IXP connection"
+
+ def build(self, **_opts):
+
+ quaggaPrivateDirs = ['/etc/quagga',
+ '/var/run/quagga',
+ '/var/log']
+ #
+ # Define Switches first
+ #
+ switch = {}
+ for i in range(1, 7):
+ switch[i] = self.addSwitch('SW%s' % i, dpid=int2dpid(i),
+ cls=LegacySwitch)
+ #
+ # Define Quagga Routers
+ #
+ router = {}
+ for i in range(1, 5):
+ router[i] = self.addNode('r%s' % i, cls=QuaggaRouter,
+ privateDirs=quaggaPrivateDirs)
+ #
+ # Wire up the switches and routers
+ #
+ # Stub nets
+ for i in range(1, 5):
+ self.addLink(switch[i], router[i], intfName2='r%s-stubnet' % i)
+ # Switch 5
+ self.addLink(switch[5], router[1], intfName2='r1-sw5')
+ self.addLink(switch[5], router[2], intfName2='r2-sw5')
+ self.addLink(switch[5], router[3], intfName2='r3-sw5')
+ # Switch 6
+ self.addLink(switch[6], router[3], intfName2='r3-sw6')
+ self.addLink(switch[6], router[4], intfName2='r4-sw6')
+
+
+def run():
+ "ospf6-test1 Topology"
+
+ thisDir = os.path.dirname(os.path.realpath(__file__))
+ topo = NetworkTopo()
+
+ net = Mininet(controller=None, topo=topo)
+ net.start()
+
+ # Starting Routers
+ for i in range(1, 5):
+ net['r%s' % i].loadConf('zebra', '%s/r%s/zebra.conf' % (thisDir, i))
+ net['r%s' % i].loadConf('ospf6d', '%s/r%s/ospf6d.conf' % (thisDir, i))
+ net['r%s' % i].startQuagga()
+
+ print('')
+
+ #
+ # Stop here for all manual checks
+ #
+ #CLI(net)
+
+ # Wait for OSPF6 to converge (All Neighbors in either Full or TwoWay State)
+ print("Waiting for OSPFv3 neighbors to establish (to Full)")
+ timeout = 60
+ while timeout > 0:
+ print("Timeout in %s: " % timeout),
+ sys.stdout.flush()
+ # Look for any node not yet converged
+ for i in range(1, 5):
+ notConverged = net['r%s' % i].cmd('vtysh -c "show ipv6 ospf neigh" 2> /dev/null | grep ^[0-9] | grep -v Full')
+ if notConverged:
+ print('Waiting for r%s' %i),
+ sys.stdout.flush()
+ break
+ if notConverged:
+ sleep(2)
+ timeout -= 2
+ print('\r \r'),
+ else:
+ print('\rDone ')
+ print(notConverged)
+ break
+ else:
+ # Bail out with error if a router fails to converge
+ sys.stderr.write("Router r%s failed to converge\n" % i)
+ ospfStatus = net['r%s' % i].cmd('vtysh -c "show ipv6 ospf neigh"')
+ sys.stderr.write("Status:\n%s" % ospfStatus)
+ net.stop()
+ sys.exit(1)
+ print("OSPFv3 converged.")
+
+ print("\nwaiting 15s for routes to populate")
+ sleep(15)
+
+ # Verify OSPFv3 Routing Table
+ print("\nVerifing OSPFv3 Routing Table")
+ failures = 0
+ for i in range(1, 5):
+ refTableFile = '%s/r%s/show_ipv6_route.ref' % (thisDir, i)
+ if os.path.isfile(refTableFile):
+ # Read expected result from file
+ expected = open(refTableFile).read().rstrip()
+ # Fix newlines (make them all the same)
+ expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
+
+ # Actual output from router
+ actual = net['r%s' % i].cmd('vtysh -c "show ipv6 route" 2> /dev/null | grep "^O"').rstrip()
+ # Mask out Link-Local mac address portion. They are random...
+ actual = re.sub(r" fe80::[0-9a-f:]+", " fe80::XXXX:XXXX:XXXX:XXXX", actual)
+ # Drop timers on end of line (older Quagga Versions)
+ actual = re.sub(r", [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", "", actual)
+ # Fix newlines (make them all the same)
+ actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
+
+ # Generate Diff
+ diff=difflib.unified_diff(actual, expected)
+ diff=''.join(diff)
+ # Empty string if it matches, otherwise diff contains unified diff
+ if diff:
+ sys.stderr.write('r%s failed Routing Table Check:\n%s\n' % (i, diff))
+ failures += 1
+ else:
+ print("r%s ok" % i)
+
+ #
+ # Stop here for manual checks after tests are executed
+ #
+ # CLI(net)
+
+ # End - Shutdown network
+ net.stop()
+
+ # Set non-zero exit status in case of failures
+ if failures > 0:
+ sys.stderr.write("Verification failed\n")
+ sys.exit(1)
+ else:
+ print("Verification Successful")
+
+if __name__ == '__main__':
+ setLogLevel('info')
+ run()