Committed by
Yuta HIGUCHI
ONOS-3422 inter-domain cross connect
- Add network configuration about cross connect port for CO-ONOS - revised metro.py requires ecord.co app after (Change-Id: I3892e780bc6550f8a8d8be622b9fee5322c1dab5) to be loaded. - stop using onos-topo-cfg to send netcfg Change-Id: Ie90e69c4134d1f71893bf43ee6c290bdbd273aeb
Showing
3 changed files
with
62 additions
and
24 deletions
| ... | @@ -83,6 +83,7 @@ public class BasicNetworkConfigs { | ... | @@ -83,6 +83,7 @@ public class BasicNetworkConfigs { |
| 83 | return new BasicLinkConfig(); | 83 | return new BasicLinkConfig(); |
| 84 | } | 84 | } |
| 85 | }, | 85 | }, |
| 86 | + // TODO move this optical specific configuration out to optical app | ||
| 86 | new ConfigFactory<ConnectPoint, OpticalPortConfig>(CONNECT_POINT_SUBJECT_FACTORY, | 87 | new ConfigFactory<ConnectPoint, OpticalPortConfig>(CONNECT_POINT_SUBJECT_FACTORY, |
| 87 | OpticalPortConfig.class, | 88 | OpticalPortConfig.class, |
| 88 | "optical") { | 89 | "optical") { | ... | ... |
| 1 | #!/usr/bin/env python | 1 | #!/usr/bin/env python |
| 2 | 2 | ||
| 3 | +import json | ||
| 4 | + | ||
| 3 | from mininet.net import Mininet | 5 | from mininet.net import Mininet |
| 4 | from mininet.node import UserSwitch, DefaultController, RemoteController, Host | 6 | from mininet.node import UserSwitch, DefaultController, RemoteController, Host |
| 5 | from mininet.topo import Topo | 7 | from mininet.topo import Topo |
| 6 | -from mininet.log import setLogLevel, info | 8 | +from mininet.log import setLogLevel, info, error, warn |
| 7 | from mininet.cli import CLI | 9 | from mininet.cli import CLI |
| 8 | from mininet.link import OVSIntf | 10 | from mininet.link import OVSIntf |
| 11 | +from mininet.util import quietRun | ||
| 9 | 12 | ||
| 10 | from opticalUtils import LINCSwitch, LINCLink | 13 | from opticalUtils import LINCSwitch, LINCLink |
| 11 | 14 | ||
| ... | @@ -33,6 +36,7 @@ class Domain(object): | ... | @@ -33,6 +36,7 @@ class Domain(object): |
| 33 | self.__ctrls[name] = args if args else {} | 36 | self.__ctrls[name] = args if args else {} |
| 34 | return name | 37 | return name |
| 35 | 38 | ||
| 39 | + # Note: This method will return the name of the swich, not the switch object | ||
| 36 | def addSwitch(self, name, **args): | 40 | def addSwitch(self, name, **args): |
| 37 | self.__switches[name] = args if args else {} | 41 | self.__switches[name] = args if args else {} |
| 38 | return name | 42 | return name |
| ... | @@ -90,10 +94,12 @@ class OpticalDomain(Domain): | ... | @@ -90,10 +94,12 @@ class OpticalDomain(Domain): |
| 90 | oean = { "optical.regens": 0 } | 94 | oean = { "optical.regens": 0 } |
| 91 | self.addSwitch('OE%s' % i, dpid='0000ffffffffff0%s' % i, annotations=oean, cls=LINCSwitch) | 95 | self.addSwitch('OE%s' % i, dpid='0000ffffffffff0%s' % i, annotations=oean, cls=LINCSwitch) |
| 92 | 96 | ||
| 97 | + # ROADM port number OE"1" -> OE'2' = "1"'2'00 | ||
| 98 | + # leaving port number up to 100 open for use by Och port | ||
| 93 | an = { "durable": "true" } | 99 | an = { "durable": "true" } |
| 94 | - self.addLink('OE1', 'OE2', port1=50, port2=30, annotations=an, cls=LINCLink) | 100 | + self.addLink('OE1', 'OE2', port1=1200, port2=2100, annotations=an, cls=LINCLink) |
| 95 | - self.addLink('OE2', 'OE3', port1=50, port2=30, annotations=an, cls=LINCLink) | 101 | + self.addLink('OE2', 'OE3', port1=2300, port2=3200, annotations=an, cls=LINCLink) |
| 96 | - self.addLink('OE3', 'OE1', port1=50, port2=30, annotations=an, cls=LINCLink) | 102 | + self.addLink('OE3', 'OE1', port1=3100, port2=1300, annotations=an, cls=LINCLink) |
| 97 | 103 | ||
| 98 | class FabricDomain(Domain): | 104 | class FabricDomain(Domain): |
| 99 | """ | 105 | """ |
| ... | @@ -139,10 +145,11 @@ class FabricDomain(Domain): | ... | @@ -139,10 +145,11 @@ class FabricDomain(Domain): |
| 139 | domains to the core. name: the UserSwitch to connect the OVS to. | 145 | domains to the core. name: the UserSwitch to connect the OVS to. |
| 140 | """ | 146 | """ |
| 141 | self.__tether = self.addSwitch(tname, dpid=tdpid) | 147 | self.__tether = self.addSwitch(tname, dpid=tdpid) |
| 148 | + # Note: OVS port number '1' reserved for port facing the fabric | ||
| 142 | self.addLink(tname, name, port1=1) | 149 | self.addLink(tname, name, port1=1) |
| 143 | 150 | ||
| 144 | def getTether(self): | 151 | def getTether(self): |
| 145 | - """ get connection point of this fabric to the core """ | 152 | + """ get the switch name of this fabric facing the core """ |
| 146 | return self.__tether | 153 | return self.__tether |
| 147 | 154 | ||
| 148 | 155 | ||
| ... | @@ -157,10 +164,6 @@ class IpHost(Host): | ... | @@ -157,10 +164,6 @@ class IpHost(Host): |
| 157 | self.cmd(mtu) | 164 | self.cmd(mtu) |
| 158 | self.cmd('ip route add default via %s' % self.gateway) | 165 | self.cmd('ip route add default via %s' % self.gateway) |
| 159 | 166 | ||
| 160 | -# fixed port numbers for attachment points (APs) between CORD and metro domains | ||
| 161 | -OVS_AP=2 | ||
| 162 | -OE_AP=10 | ||
| 163 | - | ||
| 164 | def setup(argv): | 167 | def setup(argv): |
| 165 | domains = [] | 168 | domains = [] |
| 166 | ctlsets = sys.argv[1:] | 169 | ctlsets = sys.argv[1:] |
| ... | @@ -180,6 +183,16 @@ def setup(argv): | ... | @@ -180,6 +183,16 @@ def setup(argv): |
| 180 | for j in range (len(ctls)): | 183 | for j in range (len(ctls)): |
| 181 | f.addController('c%s%s' % (i,j), controller=RemoteController, ip=ctls[j]) | 184 | f.addController('c%s%s' % (i,j), controller=RemoteController, ip=ctls[j]) |
| 182 | 185 | ||
| 186 | + # netcfg for each domains | ||
| 187 | + # Note: Separate netcfg for domain0 is created in opticalUtils | ||
| 188 | + domainCfgs = [] | ||
| 189 | + for i in range (0,len(ctlsets)): | ||
| 190 | + cfg = {} | ||
| 191 | + cfg['devices'] = {} | ||
| 192 | + cfg['ports'] = {} | ||
| 193 | + cfg['links'] = {} | ||
| 194 | + domainCfgs.append(cfg) | ||
| 195 | + | ||
| 183 | # make/setup Mininet object | 196 | # make/setup Mininet object |
| 184 | net = Mininet() | 197 | net = Mininet() |
| 185 | for d in domains: | 198 | for d in domains: |
| ... | @@ -187,10 +200,19 @@ def setup(argv): | ... | @@ -187,10 +200,19 @@ def setup(argv): |
| 187 | d.injectInto(net) | 200 | d.injectInto(net) |
| 188 | 201 | ||
| 189 | # connect COs to core - sort of hard-wired at this moment | 202 | # connect COs to core - sort of hard-wired at this moment |
| 203 | + # adding cross-connect links | ||
| 190 | for i in range(1,len(domains)): | 204 | for i in range(1,len(domains)): |
| 191 | - an = { "bandwidth": 100000, "durable": "true" } | 205 | + # add 10 cross-connect links between domains |
| 206 | + xcPortNo=2 | ||
| 207 | + ochPortNo=10 | ||
| 208 | + for j in range(0, 10): | ||
| 209 | + an = { "bandwidth": 10, "durable": "true" } | ||
| 192 | net.addLink(domains[i].getTether(), d0.getSwitches('OE%s' % i), | 210 | net.addLink(domains[i].getTether(), d0.getSwitches('OE%s' % i), |
| 193 | - port1=OVS_AP, port2=OE_AP, speed=10000, annotations=an, cls=LINCLink) | 211 | + port1=xcPortNo+j, port2=ochPortNo+j, speed=10000, annotations=an, cls=LINCLink) |
| 212 | + | ||
| 213 | + xcId = 'of:' + domains[i].getSwitches(name=domains[i].getTether()).dpid + '/' + str(xcPortNo+j) | ||
| 214 | + ochId = 'of:' + d0.getSwitches('OE%s' % i).dpid + '/' + str(ochPortNo+j) | ||
| 215 | + domainCfgs[i]['ports'][xcId] = {'cross-connect': {'remote': ochId}} | ||
| 194 | 216 | ||
| 195 | # fire everything up | 217 | # fire everything up |
| 196 | net.build() | 218 | net.build() |
| ... | @@ -203,6 +225,22 @@ def setup(argv): | ... | @@ -203,6 +225,22 @@ def setup(argv): |
| 203 | cfgnet.controllers = d0.getControllers() | 225 | cfgnet.controllers = d0.getControllers() |
| 204 | LINCSwitch.bootOE(cfgnet, d0.getSwitches()) | 226 | LINCSwitch.bootOE(cfgnet, d0.getSwitches()) |
| 205 | 227 | ||
| 228 | + # send netcfg json to each CO-ONOS | ||
| 229 | + for i in range(1,len(domains)): | ||
| 230 | + info('*** Pushing Topology.json to CO-ONOS %d\n' % i) | ||
| 231 | + filename = 'Topology%d.json' % i | ||
| 232 | + with open(filename, 'w') as outfile: | ||
| 233 | + json.dump(domainCfgs[i], outfile, indent=4, separators=(',', ': ')) | ||
| 234 | + | ||
| 235 | + output = quietRun('%s/tools/test/bin/onos-netcfg %s %s &'\ | ||
| 236 | + % (LINCSwitch.onosDir, | ||
| 237 | + domains[i].getControllers()[0].ip, | ||
| 238 | + filename), shell=True) | ||
| 239 | + # successful output contains the two characters '{}' | ||
| 240 | + # if there is more output than this, there is an issue | ||
| 241 | + if output.strip('{}'): | ||
| 242 | + warn('***WARNING: Could not push topology file to ONOS: %s\n' % output) | ||
| 243 | + | ||
| 206 | CLI(net) | 244 | CLI(net) |
| 207 | net.stop() | 245 | net.stop() |
| 208 | LINCSwitch.shutdownOE() | 246 | LINCSwitch.shutdownOE() | ... | ... |
| ... | @@ -287,8 +287,8 @@ class LINCSwitch(OpticalSwitch): | ... | @@ -287,8 +287,8 @@ class LINCSwitch(OpticalSwitch): |
| 287 | with open("crossConnect.json", 'w') as fd: | 287 | with open("crossConnect.json", 'w') as fd: |
| 288 | json.dump(crossConnectJSON, fd, indent=4, separators=(',', ': ')) | 288 | json.dump(crossConnectJSON, fd, indent=4, separators=(',', ': ')) |
| 289 | info('*** Pushing crossConnect.json to ONOS\n') | 289 | info('*** Pushing crossConnect.json to ONOS\n') |
| 290 | - output = quietRun('%s/tools/test/bin/onos-topo-cfg %s\ | 290 | + output = quietRun('%s/tools/test/bin/onos-netcfg %s\ |
| 291 | - Topology.json network/configuration/' % (self.onosDir, self.controllers[ 0 ].ip), shell=True) | 291 | + Topology.json' % (self.onosDir, self.controllers[ 0 ].ip), shell=True) |
| 292 | 292 | ||
| 293 | def stop_oe(self): | 293 | def stop_oe(self): |
| 294 | ''' | 294 | ''' |
| ... | @@ -455,21 +455,20 @@ class LINCSwitch(OpticalSwitch): | ... | @@ -455,21 +455,20 @@ class LINCSwitch(OpticalSwitch): |
| 455 | opener.open(url) | 455 | opener.open(url) |
| 456 | urllib2.install_opener(opener) | 456 | urllib2.install_opener(opener) |
| 457 | # focus on just checking the state of devices we're interested in | 457 | # focus on just checking the state of devices we're interested in |
| 458 | - devlist = map( lambda x: x['uri'], devices ) | 458 | + # expected devices availability map |
| 459 | + devMap = dict.fromkeys(map( lambda x: x['uri'], devices ), False) | ||
| 459 | while True: | 460 | while True: |
| 460 | response = json.load(urllib2.urlopen(url)) | 461 | response = json.load(urllib2.urlopen(url)) |
| 461 | devs = response.get('devices') | 462 | devs = response.get('devices') |
| 462 | 463 | ||
| 463 | - # Wait for all devices to be registered. There is a chance that this is only a subgraph. | 464 | + # update availability map |
| 464 | - if (len(devices) == len(devs)): | ||
| 465 | - | ||
| 466 | - # Wait for all devices to available | ||
| 467 | - available = True | ||
| 468 | for d in devs: | 465 | for d in devs: |
| 469 | - if d['id'] in devlist: | 466 | + if devMap.has_key(d['id']): |
| 470 | - available &= d['available'] | 467 | + devMap[d['id']] = d['available'] |
| 471 | - if available: | 468 | + |
| 472 | - break | 469 | + # Check if all devices we're interested became available |
| 470 | + if all(devMap.viewvalues()): | ||
| 471 | + break; | ||
| 473 | 472 | ||
| 474 | if (time >= TIMEOUT): | 473 | if (time >= TIMEOUT): |
| 475 | error('***ERROR: ONOS did not register devices within %s seconds\n' % TIMEOUT) | 474 | error('***ERROR: ONOS did not register devices within %s seconds\n' % TIMEOUT) |
| ... | @@ -480,7 +479,7 @@ class LINCSwitch(OpticalSwitch): | ... | @@ -480,7 +479,7 @@ class LINCSwitch(OpticalSwitch): |
| 480 | 479 | ||
| 481 | info('*** Pushing Topology.json to ONOS\n') | 480 | info('*** Pushing Topology.json to ONOS\n') |
| 482 | for index in range(len(LINCSwitch.controllers)): | 481 | for index in range(len(LINCSwitch.controllers)): |
| 483 | - output = quietRun('%s/tools/test/bin/onos-topo-cfg %s Topology.json network/configuration/ &'\ | 482 | + output = quietRun('%s/tools/test/bin/onos-netcfg %s Topology.json &'\ |
| 484 | % (LINCSwitch.onosDir, LINCSwitch.controllers[ index ].ip), shell=True) | 483 | % (LINCSwitch.onosDir, LINCSwitch.controllers[ index ].ip), shell=True) |
| 485 | # successful output contains the two characters '{}' | 484 | # successful output contains the two characters '{}' |
| 486 | # if there is more output than this, there is an issue | 485 | # if there is more output than this, there is an issue | ... | ... |
-
Please register or login to post a comment