Thomas Vachuska

Consolidating null providers and making them fully configurable and integrated w…

…ith the ConfigProvider to allow arbitrary topologies.

Change-Id: I899e27a9771af4013a3ce6da7f683a4927ffb438
Showing 40 changed files with 2445 additions and 84 deletions
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.cli;
17 +
18 +import org.apache.karaf.shell.console.completer.StringsCompleter;
19 +
20 +import java.util.List;
21 +import java.util.SortedSet;
22 +
23 +/**
24 + * Abstraction of a completer with preset choices.
25 + */
26 +public abstract class AbstractChoicesCompleter extends AbstractCompleter {
27 +
28 + protected abstract List<String> choices();
29 +
30 + @Override
31 + public int complete(String buffer, int cursor, List<String> candidates) {
32 + StringsCompleter delegate = new StringsCompleter();
33 + SortedSet<String> strings = delegate.getStrings();
34 + choices().forEach(strings::add);
35 + return delegate.complete(buffer, cursor, candidates);
36 + }
37 +
38 +}
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 -package org.onosproject.cli.net; 16 +package org.onosproject.cli;
17 17
18 import org.apache.felix.service.command.CommandSession; 18 import org.apache.felix.service.command.CommandSession;
19 import org.apache.karaf.shell.console.CommandSessionHolder; 19 import org.apache.karaf.shell.console.CommandSessionHolder;
......
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.cli;
17 +
18 +import com.google.common.collect.ImmutableList;
19 +
20 +import java.util.List;
21 +
22 +/**
23 + * Start/stop command completer.
24 + */
25 +public class StartStopCompleter extends AbstractChoicesCompleter {
26 +
27 + public static final String START = "start";
28 + public static final String STOP = "stop";
29 +
30 + @Override
31 + public List<String> choices() {
32 + return ImmutableList.of(START, STOP);
33 + }
34 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.cli;
17 +
18 +import com.google.common.collect.ImmutableList;
19 +
20 +import java.util.List;
21 +
22 +/**
23 + * Up/down command completer.
24 + */
25 +public class UpDownCompleter extends AbstractChoicesCompleter {
26 +
27 + public static final String UP = "up";
28 + public static final String DOWN = "down";
29 +
30 + @Override
31 + public List<String> choices() {
32 + return ImmutableList.of(UP, DOWN);
33 + }
34 +}
...@@ -15,30 +15,20 @@ ...@@ -15,30 +15,20 @@
15 */ 15 */
16 package org.onosproject.cli.app; 16 package org.onosproject.cli.app;
17 17
18 -import org.apache.karaf.shell.console.Completer; 18 +import com.google.common.collect.ImmutableList;
19 -import org.apache.karaf.shell.console.completer.StringsCompleter; 19 +import org.onosproject.cli.AbstractChoicesCompleter;
20 20
21 import java.util.List; 21 import java.util.List;
22 -import java.util.SortedSet;
23 22
24 import static org.onosproject.cli.app.ApplicationCommand.*; 23 import static org.onosproject.cli.app.ApplicationCommand.*;
25 24
26 /** 25 /**
27 - * Application name completer. 26 + * Application command completer.
28 */ 27 */
29 -public class ApplicationCommandCompleter implements Completer { 28 +public class ApplicationCommandCompleter extends AbstractChoicesCompleter {
30 @Override 29 @Override
31 - public int complete(String buffer, int cursor, List<String> candidates) { 30 + public List<String> choices() {
32 - // Delegate string completer 31 + return ImmutableList.of(INSTALL, UNINSTALL, ACTIVATE, DEACTIVATE);
33 - StringsCompleter delegate = new StringsCompleter();
34 - SortedSet<String> strings = delegate.getStrings();
35 - strings.add(INSTALL);
36 - strings.add(UNINSTALL);
37 - strings.add(ACTIVATE);
38 - strings.add(DEACTIVATE);
39 -
40 - // Now let the completer do the work for figuring out what to offer.
41 - return delegate.complete(buffer, cursor, candidates);
42 } 32 }
43 33
44 } 34 }
......
...@@ -19,7 +19,7 @@ import org.apache.karaf.shell.console.completer.ArgumentCompleter; ...@@ -19,7 +19,7 @@ import org.apache.karaf.shell.console.completer.ArgumentCompleter;
19 import org.apache.karaf.shell.console.completer.StringsCompleter; 19 import org.apache.karaf.shell.console.completer.StringsCompleter;
20 import org.onosproject.app.ApplicationService; 20 import org.onosproject.app.ApplicationService;
21 import org.onosproject.app.ApplicationState; 21 import org.onosproject.app.ApplicationState;
22 -import org.onosproject.cli.net.AbstractCompleter; 22 +import org.onosproject.cli.AbstractCompleter;
23 import org.onosproject.core.Application; 23 import org.onosproject.core.Application;
24 24
25 import java.util.Iterator; 25 import java.util.Iterator;
......
...@@ -19,7 +19,7 @@ import org.apache.karaf.shell.console.completer.ArgumentCompleter; ...@@ -19,7 +19,7 @@ import org.apache.karaf.shell.console.completer.ArgumentCompleter;
19 import org.apache.karaf.shell.console.completer.StringsCompleter; 19 import org.apache.karaf.shell.console.completer.StringsCompleter;
20 import org.onosproject.cfg.ComponentConfigService; 20 import org.onosproject.cfg.ComponentConfigService;
21 import org.onosproject.cfg.ConfigProperty; 21 import org.onosproject.cfg.ConfigProperty;
22 -import org.onosproject.cli.net.AbstractCompleter; 22 +import org.onosproject.cli.AbstractCompleter;
23 23
24 import java.util.List; 24 import java.util.List;
25 import java.util.Set; 25 import java.util.Set;
......
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.cli.net;
17 +
18 +import org.apache.karaf.shell.console.completer.ArgumentCompleter;
19 +import org.apache.karaf.shell.console.completer.StringsCompleter;
20 +import org.onosproject.cli.AbstractCompleter;
21 +import org.onosproject.cli.AbstractShellCommand;
22 +import org.onosproject.net.ConnectPoint;
23 +import org.onosproject.net.link.LinkService;
24 +
25 +import java.util.List;
26 +import java.util.SortedSet;
27 +
28 +import static org.onosproject.cli.net.AddPointToPointIntentCommand.getDeviceId;
29 +import static org.onosproject.cli.net.AddPointToPointIntentCommand.getPortNumber;
30 +import static org.onosproject.net.DeviceId.deviceId;
31 +import static org.onosproject.net.PortNumber.portNumber;
32 +
33 +/**
34 + * Link end-point completer.
35 + */
36 +public class LinkDstCompleter extends AbstractCompleter {
37 + @Override
38 + public int complete(String buffer, int cursor, List<String> candidates) {
39 + // Delegate string completer
40 + StringsCompleter delegate = new StringsCompleter();
41 +
42 + // Fetch our service and feed it's offerings to the string completer
43 + LinkService service = AbstractShellCommand.get(LinkService.class);
44 +
45 + // Link source the previous argument.
46 + ArgumentCompleter.ArgumentList list = getArgumentList();
47 + String srcArg = list.getArguments()[list.getCursorArgumentIndex() - 1];
48 +
49 + // Generate the device ID/port number identifiers
50 + SortedSet<String> strings = delegate.getStrings();
51 + try {
52 + ConnectPoint src = new ConnectPoint(deviceId(getDeviceId(srcArg)),
53 + portNumber(getPortNumber(srcArg)));
54 + service.getEgressLinks(src)
55 + .forEach(link -> strings.add(link.dst().elementId().toString() +
56 + "/" + link.dst().port()));
57 + } catch (NumberFormatException e) {
58 + System.err.println("Invalid connect-point");
59 + }
60 +
61 + // Now let the completer do the work for figuring out what to offer.
62 + return delegate.complete(buffer, cursor, candidates);
63 + }
64 +
65 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.cli.net;
17 +
18 +import org.apache.karaf.shell.console.completer.StringsCompleter;
19 +import org.onosproject.cli.AbstractCompleter;
20 +import org.onosproject.cli.AbstractShellCommand;
21 +import org.onosproject.net.link.LinkService;
22 +
23 +import java.util.List;
24 +import java.util.SortedSet;
25 +
26 +/**
27 + * Link end-point completer.
28 + */
29 +public class LinkSrcCompleter extends AbstractCompleter {
30 + @Override
31 + public int complete(String buffer, int cursor, List<String> candidates) {
32 + // Delegate string completer
33 + StringsCompleter delegate = new StringsCompleter();
34 +
35 + // Fetch our service and feed it's offerings to the string completer
36 + LinkService service = AbstractShellCommand.get(LinkService.class);
37 +
38 + // Generate the device ID/port number identifiers
39 + SortedSet<String> strings = delegate.getStrings();
40 + service.getLinks()
41 + .forEach(link -> strings.add(link.src().elementId().toString() +
42 + "/" + link.src().port()));
43 +
44 + // Now let the completer do the work for figuring out what to offer.
45 + return delegate.complete(buffer, cursor, candidates);
46 + }
47 +
48 +}
...@@ -332,4 +332,7 @@ ...@@ -332,4 +332,7 @@
332 <bean id="ipProtocolCompleter" class="org.onosproject.cli.net.IpProtocolCompleter"/> 332 <bean id="ipProtocolCompleter" class="org.onosproject.cli.net.IpProtocolCompleter"/>
333 <bean id="driverNameCompleter" class="org.onosproject.cli.net.DriverNameCompleter"/> 333 <bean id="driverNameCompleter" class="org.onosproject.cli.net.DriverNameCompleter"/>
334 334
335 + <bean id="startStopCompleter" class="org.onosproject.cli.StartStopCompleter"/>
336 + <bean id="upDownCompleter" class="org.onosproject.cli.UpDownCompleter"/>
337 +
335 </blueprint> 338 </blueprint>
......
...@@ -20,7 +20,7 @@ import org.onosproject.net.DeviceId; ...@@ -20,7 +20,7 @@ import org.onosproject.net.DeviceId;
20 /** 20 /**
21 * Service for administering the inventory of infrastructure devices. 21 * Service for administering the inventory of infrastructure devices.
22 */ 22 */
23 -public interface DeviceAdminService { 23 +public interface DeviceAdminService extends DeviceService {
24 24
25 /** 25 /**
26 * Removes the device with the specified identifier. 26 * Removes the device with the specified identifier.
......
...@@ -21,7 +21,7 @@ import org.onosproject.net.HostId; ...@@ -21,7 +21,7 @@ import org.onosproject.net.HostId;
21 /** 21 /**
22 * Service for administering the inventory of end-station hosts. 22 * Service for administering the inventory of end-station hosts.
23 */ 23 */
24 -public interface HostAdminService { 24 +public interface HostAdminService extends HostService {
25 25
26 /** 26 /**
27 * Removes the end-station host with the specified identifier. 27 * Removes the end-station host with the specified identifier.
......
...@@ -21,7 +21,7 @@ import org.onosproject.net.DeviceId; ...@@ -21,7 +21,7 @@ import org.onosproject.net.DeviceId;
21 /** 21 /**
22 * Service for administering the inventory of infrastructure links. 22 * Service for administering the inventory of infrastructure links.
23 */ 23 */
24 -public interface LinkAdminService { 24 +public interface LinkAdminService extends LinkService {
25 25
26 /** 26 /**
27 * Removes all infrastructure links leading to and from the 27 * Removes all infrastructure links leading to and from the
......
...@@ -705,7 +705,8 @@ public class DistributedGroupStore ...@@ -705,7 +705,8 @@ public class DistributedGroupStore
705 remove(new GroupStoreKeyMapKey(deviceId, group.appCookie())); 705 remove(new GroupStoreKeyMapKey(deviceId, group.appCookie()));
706 } 706 }
707 } else { 707 } else {
708 - if (deviceAuditStatus.get(deviceId)) { 708 + Boolean audited = deviceAuditStatus.get(deviceId);
709 + if (audited != null && audited) {
709 log.debug("deviceInitialAuditCompleted: Clearing AUDIT " 710 log.debug("deviceInitialAuditCompleted: Clearing AUDIT "
710 + "status for device {}", deviceId); 711 + "status for device {}", deviceId);
711 deviceAuditStatus.put(deviceId, false); 712 deviceAuditStatus.put(deviceId, false);
...@@ -717,8 +718,8 @@ public class DistributedGroupStore ...@@ -717,8 +718,8 @@ public class DistributedGroupStore
717 @Override 718 @Override
718 public boolean deviceInitialAuditStatus(DeviceId deviceId) { 719 public boolean deviceInitialAuditStatus(DeviceId deviceId) {
719 synchronized (deviceAuditStatus) { 720 synchronized (deviceAuditStatus) {
720 - return (deviceAuditStatus.get(deviceId) != null) 721 + Boolean audited = deviceAuditStatus.get(deviceId);
721 - ? deviceAuditStatus.get(deviceId) : false; 722 + return audited != null && audited;
722 } 723 }
723 } 724 }
724 725
......
...@@ -79,7 +79,7 @@ ...@@ -79,7 +79,7 @@
79 <group> 79 <group>
80 <title>Null Providers</title> 80 <title>Null Providers</title>
81 <packages> 81 <packages>
82 - org.onosproject.provider.nil.* 82 + org.onosproject.provider.nil:org.onosproject.provider.nil.*
83 </packages> 83 </packages>
84 </group> 84 </group>
85 <group> 85 <group>
......
...@@ -131,13 +131,7 @@ ...@@ -131,13 +131,7 @@
131 <feature name="onos-null" version="@FEATURE-VERSION" 131 <feature name="onos-null" version="@FEATURE-VERSION"
132 description="ONOS Null providers"> 132 description="ONOS Null providers">
133 <feature>onos-api</feature> 133 <feature>onos-api</feature>
134 - 134 + <bundle>mvn:org.onosproject/onos-null-provider/@ONOS-VERSION</bundle>
135 - <bundle>mvn:org.onosproject/onos-null-provider-device/@ONOS-VERSION</bundle>
136 - <bundle>mvn:org.onosproject/onos-null-provider-link/@ONOS-VERSION</bundle>
137 - <bundle>mvn:org.onosproject/onos-null-provider-host/@ONOS-VERSION</bundle>
138 - <bundle>mvn:org.onosproject/onos-null-provider-packet/@ONOS-VERSION</bundle>
139 - <bundle>mvn:org.onosproject/onos-null-provider-flow/@ONOS-VERSION</bundle>
140 -
141 </feature> 135 </feature>
142 136
143 <feature name="onos-openflow" version="@FEATURE-VERSION" 137 <feature name="onos-openflow" version="@FEATURE-VERSION"
......
...@@ -26,20 +26,25 @@ ...@@ -26,20 +26,25 @@
26 <relativePath>../pom.xml</relativePath> 26 <relativePath>../pom.xml</relativePath>
27 </parent> 27 </parent>
28 28
29 - <artifactId>onos-null-providers</artifactId> 29 + <artifactId>onos-null-provider</artifactId>
30 - <packaging>pom</packaging> 30 + <packaging>bundle</packaging>
31 31
32 <description>ONOS null protocol adapters</description> 32 <description>ONOS null protocol adapters</description>
33 33
34 - <modules>
35 - <module>device</module>
36 - <module>link</module>
37 - <module>host</module>
38 - <module>packet</module>
39 - <module>flow</module>
40 - </modules>
41 -
42 <dependencies> 34 <dependencies>
35 + <dependency>
36 + <groupId>org.osgi</groupId>
37 + <artifactId>org.osgi.compendium</artifactId>
38 + </dependency>
39 + <dependency>
40 + <groupId>org.apache.karaf.shell</groupId>
41 + <artifactId>org.apache.karaf.shell.console</artifactId>
42 + </dependency>
43 + <dependency>
44 + <groupId>org.onosproject</groupId>
45 + <artifactId>onos-cli</artifactId>
46 + <version>${project.version}</version>
47 + </dependency>
43 48
44 <dependency> 49 <dependency>
45 <groupId>org.onosproject</groupId> 50 <groupId>org.onosproject</groupId>
......
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.provider.nil;
17 +
18 +/**
19 + * Linear topology with hosts on every device.
20 + */
21 +public class CentipedeTopologySimulator extends LinearTopologySimulator {
22 +
23 + /**
24 + * Creates simulated hosts.
25 + */
26 + protected void createHosts() {
27 + deviceIds.forEach(id -> createHosts(id, infrastructurePorts));
28 + }
29 +
30 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.provider.nil;
17 +
18 +/**
19 + * Topology simulator which operates on topology configured via the REST API
20 + * config service.
21 + */
22 +public class ConfiguredTopologySimulator extends TopologySimulator {
23 +
24 + @Override
25 + protected void createDevices() {
26 + deviceService.getDevices()
27 + .forEach(device -> deviceProviderService
28 + .deviceConnected(device.id(), description(device)));
29 + }
30 +
31 + @Override
32 + protected void createLinks() {
33 + linkService.getLinks()
34 + .forEach(link -> linkProviderService
35 + .linkDetected(description(link)));
36 + }
37 +
38 + @Override
39 + protected void createHosts() {
40 + hostService.getHosts()
41 + .forEach(host -> hostProviderService
42 + .hostDetected(host.id(), description(host)));
43 + }
44 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.provider.nil;
17 +
18 +import static com.google.common.base.Preconditions.checkArgument;
19 +
20 +/**
21 + * Linear topology simulator.
22 + */
23 +public class LinearTopologySimulator extends TopologySimulator {
24 +
25 + @Override
26 + protected void processTopoShape(String shape) {
27 + super.processTopoShape(shape);
28 + deviceCount = (topoShape.length == 1) ? deviceCount : Integer.parseInt(topoShape[1]);
29 + }
30 +
31 + @Override
32 + public void setUpTopology() {
33 + checkArgument(deviceCount > 1, "There must be at least 2 devices");
34 +
35 + prepareForDeviceEvents(deviceCount);
36 + createDevices();
37 + waitForDeviceEvents();
38 +
39 + createLinks();
40 + createHosts();
41 + }
42 +
43 + @Override
44 + protected void createLinks() {
45 + for (int i = 0, n = deviceCount - 1; i < n; i++) {
46 + createLink(i, i + 1);
47 + }
48 + }
49 +
50 + @Override
51 + protected void createHosts() {
52 + createHosts(deviceIds.get(0), infrastructurePorts);
53 + createHosts(deviceIds.get(deviceCount - 1), infrastructurePorts);
54 + }
55 +
56 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.provider.nil;
17 +
18 +/**
19 + * Full mesh topology with hosts at each device.
20 + */
21 +public class MeshTopologySimulator extends TopologySimulator {
22 +
23 + @Override
24 + protected void processTopoShape(String shape) {
25 + super.processTopoShape(shape);
26 + // FIXME: implement this
27 + }
28 +
29 + @Override
30 + public void setUpTopology() {
31 + // FIXME: implement this
32 + // checkArgument(FIXME, "There must be at least ...");
33 + super.setUpTopology();
34 + }
35 +
36 + @Override
37 + protected void createLinks() {
38 + }
39 +
40 + @Override
41 + protected void createHosts() {
42 + }
43 +
44 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.provider.nil;
17 +
18 +import com.google.common.collect.Sets;
19 +import org.jboss.netty.util.HashedWheelTimer;
20 +import org.jboss.netty.util.Timeout;
21 +import org.jboss.netty.util.TimerTask;
22 +import org.onlab.util.Timer;
23 +import org.onosproject.core.ApplicationId;
24 +import org.onosproject.net.DeviceId;
25 +import org.onosproject.net.flow.CompletedBatchOperation;
26 +import org.onosproject.net.flow.DefaultFlowEntry;
27 +import org.onosproject.net.flow.FlowEntry;
28 +import org.onosproject.net.flow.FlowRule;
29 +import org.onosproject.net.flow.FlowRuleBatchEntry;
30 +import org.onosproject.net.flow.FlowRuleBatchOperation;
31 +import org.onosproject.net.flow.FlowRuleProvider;
32 +import org.onosproject.net.flow.FlowRuleProviderService;
33 +import org.slf4j.Logger;
34 +
35 +import java.util.Collections;
36 +import java.util.Set;
37 +import java.util.concurrent.ConcurrentHashMap;
38 +import java.util.concurrent.ConcurrentMap;
39 +import java.util.concurrent.TimeUnit;
40 +
41 +import static org.slf4j.LoggerFactory.getLogger;
42 +
43 +/**
44 + * Null provider to accept any flow and report them.
45 + */
46 +class NullFlowRuleProvider extends NullProviders.AbstractNullProvider
47 + implements FlowRuleProvider {
48 +
49 + private final Logger log = getLogger(getClass());
50 +
51 + private ConcurrentMap<DeviceId, Set<FlowEntry>> flowTable = new ConcurrentHashMap<>();
52 +
53 + private FlowRuleProviderService providerService;
54 +
55 + private HashedWheelTimer timer = Timer.getTimer();
56 + private Timeout timeout;
57 +
58 + /**
59 + * Starts the flow rule provider simulation.
60 + *
61 + * @param providerService flow rule provider service
62 + */
63 + void start(FlowRuleProviderService providerService) {
64 + this.providerService = providerService;
65 + timeout = timer.newTimeout(new StatisticTask(), 5, TimeUnit.SECONDS);
66 + }
67 +
68 + /**
69 + * Stops the flow rule provider simulation.
70 + */
71 + void stop() {
72 + timeout.cancel();
73 + }
74 +
75 + @Override
76 + public void applyFlowRule(FlowRule... flowRules) {
77 + // FIXME: invoke executeBatch
78 + }
79 +
80 + @Override
81 + public void removeFlowRule(FlowRule... flowRules) {
82 + // FIXME: invoke executeBatch
83 + }
84 +
85 + @Override
86 + public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
87 + throw new UnsupportedOperationException("Cannot remove by appId from null provider");
88 + }
89 +
90 + @Override
91 + public void executeBatch(FlowRuleBatchOperation batch) {
92 + // TODO: consider checking mastership
93 + Set<FlowEntry> entries =
94 + flowTable.getOrDefault(batch.deviceId(),
95 + Sets.newConcurrentHashSet());
96 + for (FlowRuleBatchEntry fbe : batch.getOperations()) {
97 + switch (fbe.operator()) {
98 + case ADD:
99 + entries.add(new DefaultFlowEntry(fbe.target()));
100 + break;
101 + case REMOVE:
102 + entries.remove(new DefaultFlowEntry(fbe.target()));
103 + break;
104 + case MODIFY:
105 + FlowEntry entry = new DefaultFlowEntry(fbe.target());
106 + entries.remove(entry);
107 + entries.add(entry);
108 + break;
109 + default:
110 + log.error("Unknown flow operation: {}", fbe);
111 + }
112 + }
113 + flowTable.put(batch.deviceId(), entries);
114 + CompletedBatchOperation op =
115 + new CompletedBatchOperation(true, Collections.emptySet(),
116 + batch.deviceId());
117 + providerService.batchOperationCompleted(batch.id(), op);
118 + }
119 +
120 + // Periodically reports flow rule statistics.
121 + private class StatisticTask implements TimerTask {
122 + @Override
123 + public void run(Timeout to) throws Exception {
124 + for (DeviceId devId : flowTable.keySet()) {
125 + Set<FlowEntry> entries =
126 + flowTable.getOrDefault(devId, Collections.emptySet());
127 + providerService.pushFlowMetrics(devId, entries);
128 + }
129 + timeout = timer.newTimeout(to.getTask(), 5, TimeUnit.SECONDS);
130 + }
131 + }
132 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.provider.nil;
17 +
18 +import org.jboss.netty.util.HashedWheelTimer;
19 +import org.jboss.netty.util.Timeout;
20 +import org.jboss.netty.util.TimerTask;
21 +import org.onlab.packet.Ethernet;
22 +import org.onlab.packet.ICMP;
23 +import org.onlab.util.Timer;
24 +import org.onosproject.net.ConnectPoint;
25 +import org.onosproject.net.Device;
26 +import org.onosproject.net.PortNumber;
27 +import org.onosproject.net.device.DeviceAdminService;
28 +import org.onosproject.net.host.HostService;
29 +import org.onosproject.net.packet.DefaultInboundPacket;
30 +import org.onosproject.net.packet.DefaultPacketContext;
31 +import org.onosproject.net.packet.InboundPacket;
32 +import org.onosproject.net.packet.OutboundPacket;
33 +import org.onosproject.net.packet.PacketProvider;
34 +import org.onosproject.net.packet.PacketProviderService;
35 +import org.slf4j.Logger;
36 +
37 +import java.nio.ByteBuffer;
38 +import java.util.List;
39 +import java.util.concurrent.TimeUnit;
40 +import java.util.stream.Collectors;
41 +
42 +import static com.google.common.collect.ImmutableList.copyOf;
43 +import static java.util.concurrent.TimeUnit.SECONDS;
44 +import static org.onosproject.net.MastershipRole.MASTER;
45 +import static org.slf4j.LoggerFactory.getLogger;
46 +
47 +/**
48 + * Provider which generates simulated packets and acts as a sink for outbound
49 + * packets. To be used for benchmarking only.
50 + */
51 +class NullPacketProvider extends NullProviders.AbstractNullProvider
52 + implements PacketProvider {
53 +
54 + private static final int INITIAL_DELAY = 5;
55 + private final Logger log = getLogger(getClass());
56 +
57 + // Arbitrary host src/dst
58 + private static final int SRC_HOST = 2;
59 + private static final int DST_HOST = 5;
60 +
61 + // Time between event firing, in milliseconds
62 + private int delay;
63 +
64 + // TODO: use host service to pick legitimate hosts connected to devices
65 + private HostService hostService;
66 + private PacketProviderService providerService;
67 +
68 + private List<Device> devices;
69 + private int currentDevice = 0;
70 +
71 + private HashedWheelTimer timer = Timer.getTimer();
72 + private Timeout timeout;
73 +
74 + /**
75 + * Starts the packet generation process.
76 + *
77 + * @param packetRate packets per second
78 + * @param hostService host service
79 + * @param deviceService device service
80 + * @param providerService packet provider service
81 + */
82 + void start(int packetRate, HostService hostService,
83 + DeviceAdminService deviceService,
84 + PacketProviderService providerService) {
85 + this.hostService = hostService;
86 + this.providerService = providerService;
87 +
88 + this.devices = copyOf(deviceService.getDevices()).stream()
89 + .filter(d -> deviceService.getRole(d.id()) == MASTER)
90 + .collect(Collectors.toList());
91 +
92 + adjustRate(packetRate);
93 + timeout = timer.newTimeout(new PacketDriverTask(), INITIAL_DELAY, SECONDS);
94 + }
95 +
96 + /**
97 + * Adjusts packet rate.
98 + *
99 + * @param packetRate new packet rate
100 + */
101 + void adjustRate(int packetRate) {
102 + delay = 1000 / packetRate;
103 + log.info("Settings: packetRate={}, delay={}", packetRate, delay);
104 + }
105 +
106 + /**
107 + * Stops the packet generation process.
108 + */
109 + void stop() {
110 + if (timeout != null) {
111 + timeout.cancel();
112 + }
113 + }
114 +
115 + @Override
116 + public void emit(OutboundPacket packet) {
117 + // We don't have a network to emit to. Keep a counter here, maybe?
118 + }
119 +
120 + /**
121 + * Generates packet events at a given rate.
122 + */
123 + private class PacketDriverTask implements TimerTask {
124 +
125 + // Filler echo request
126 + ICMP icmp;
127 + Ethernet eth;
128 +
129 + public PacketDriverTask() {
130 + icmp = new ICMP();
131 + icmp.setIcmpType((byte) 8).setIcmpCode((byte) 0).setChecksum((short) 0);
132 + eth = new Ethernet();
133 + eth.setEtherType(Ethernet.TYPE_IPV4);
134 + eth.setPayload(icmp);
135 + }
136 +
137 + @Override
138 + public void run(Timeout to) {
139 + if (!devices.isEmpty()) {
140 + sendEvent(devices.get(currentDevice));
141 + currentDevice = (currentDevice + 1) % devices.size();
142 + timeout = timer.newTimeout(to.getTask(), delay, TimeUnit.MILLISECONDS);
143 + }
144 + }
145 +
146 + private void sendEvent(Device device) {
147 + // Make it look like things came from ports attached to hosts
148 + eth.setSourceMACAddress("00:00:10:00:00:0" + SRC_HOST)
149 + .setDestinationMACAddress("00:00:10:00:00:0" + DST_HOST);
150 + InboundPacket inPkt = new DefaultInboundPacket(
151 + new ConnectPoint(device.id(), PortNumber.portNumber(SRC_HOST)),
152 + eth, ByteBuffer.wrap(eth.serialize()));
153 + providerService.processPacket(new NullPacketContext(inPkt, null));
154 + }
155 + }
156 +
157 + // Minimal PacketContext to make core and applications happy.
158 + private final class NullPacketContext extends DefaultPacketContext {
159 + private NullPacketContext(InboundPacket inPkt, OutboundPacket outPkt) {
160 + super(System.currentTimeMillis(), inPkt, outPkt, false);
161 + }
162 +
163 + @Override
164 + public void send() {
165 + // We don't send anything out.
166 + }
167 + }
168 +
169 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.provider.nil;
17 +
18 +import org.apache.felix.scr.annotations.Activate;
19 +import org.apache.felix.scr.annotations.Component;
20 +import org.apache.felix.scr.annotations.Deactivate;
21 +import org.apache.felix.scr.annotations.Modified;
22 +import org.apache.felix.scr.annotations.Property;
23 +import org.apache.felix.scr.annotations.Reference;
24 +import org.apache.felix.scr.annotations.ReferenceCardinality;
25 +import org.apache.felix.scr.annotations.Service;
26 +import org.onlab.osgi.DefaultServiceDirectory;
27 +import org.onosproject.cfg.ComponentConfigService;
28 +import org.onosproject.cluster.ClusterService;
29 +import org.onosproject.cluster.NodeId;
30 +import org.onosproject.mastership.MastershipAdminService;
31 +import org.onosproject.net.ConnectPoint;
32 +import org.onosproject.net.DeviceId;
33 +import org.onosproject.net.Host;
34 +import org.onosproject.net.MastershipRole;
35 +import org.onosproject.net.device.DeviceAdminService;
36 +import org.onosproject.net.device.DeviceProvider;
37 +import org.onosproject.net.device.DeviceProviderRegistry;
38 +import org.onosproject.net.device.DeviceProviderService;
39 +import org.onosproject.net.flow.FlowRuleProviderRegistry;
40 +import org.onosproject.net.flow.FlowRuleProviderService;
41 +import org.onosproject.net.host.HostProvider;
42 +import org.onosproject.net.host.HostProviderRegistry;
43 +import org.onosproject.net.host.HostProviderService;
44 +import org.onosproject.net.host.HostService;
45 +import org.onosproject.net.link.LinkProvider;
46 +import org.onosproject.net.link.LinkProviderRegistry;
47 +import org.onosproject.net.link.LinkProviderService;
48 +import org.onosproject.net.link.LinkService;
49 +import org.onosproject.net.packet.PacketProviderRegistry;
50 +import org.onosproject.net.packet.PacketProviderService;
51 +import org.onosproject.net.provider.AbstractProvider;
52 +import org.onosproject.net.provider.ProviderId;
53 +import org.osgi.service.component.ComponentContext;
54 +import org.slf4j.Logger;
55 +
56 +import java.util.Dictionary;
57 +import java.util.Properties;
58 +
59 +import static com.google.common.base.Strings.isNullOrEmpty;
60 +import static org.onlab.util.Tools.delay;
61 +import static org.onlab.util.Tools.get;
62 +import static org.onosproject.net.DeviceId.deviceId;
63 +import static org.onosproject.net.MastershipRole.MASTER;
64 +import static org.onosproject.net.MastershipRole.NONE;
65 +import static org.slf4j.LoggerFactory.getLogger;
66 +
67 +/**
68 + * Provider of a fake network environment, i.e. devices, links, hosts, etc.
69 + * To be used for benchmarking only.
70 + */
71 +@Component(immediate = true)
72 +@Service(value = NullProviders.class)
73 +public class NullProviders {
74 +
75 + private static final Logger log = getLogger(NullProviders.class);
76 +
77 + static final String SCHEME = "null";
78 + static final String PROVIDER_ID = "org.onosproject.provider.nil";
79 +
80 + private static final String FORMAT =
81 + "Settings: enabled={}, topoShape={}, deviceCount={}, " +
82 + "hostCount={}, packetRate={}, mutationRate={}";
83 +
84 +
85 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 + protected ClusterService clusterService;
87 +
88 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 + protected MastershipAdminService mastershipService;
90 +
91 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 + protected ComponentConfigService cfgService;
93 +
94 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 + protected DeviceAdminService deviceService;
96 +
97 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 + protected HostService hostService;
99 +
100 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 + protected LinkService linkService;
102 +
103 +
104 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 + protected DeviceProviderRegistry deviceProviderRegistry;
106 +
107 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 + protected HostProviderRegistry hostProviderRegistry;
109 +
110 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 + protected LinkProviderRegistry linkProviderRegistry;
112 +
113 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 + protected FlowRuleProviderRegistry flowRuleProviderRegistry;
115 +
116 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 + protected PacketProviderRegistry packetProviderRegistry;
118 +
119 +
120 + private final NullDeviceProvider deviceProvider = new NullDeviceProvider();
121 + private final NullLinkProvider linkProvider = new NullLinkProvider();
122 + private final NullHostProvider hostProvider = new NullHostProvider();
123 + private final NullFlowRuleProvider flowRuleProvider = new NullFlowRuleProvider();
124 + private final NullPacketProvider packetProvider = new NullPacketProvider();
125 + private final TopologyMutationDriver topologyMutationDriver = new TopologyMutationDriver();
126 +
127 + private DeviceProviderService deviceProviderService;
128 + private HostProviderService hostProviderService;
129 + private LinkProviderService linkProviderService;
130 + private FlowRuleProviderService flowRuleProviderService;
131 + private PacketProviderService packetProviderService;
132 +
133 + private TopologySimulator simulator;
134 +
135 + @Property(name = "enabled", boolValue = false,
136 + label = "Enables or disables the provider")
137 + private boolean enabled = false;
138 +
139 + private static final String DEFAULT_TOPO_SHAPE = "configured";
140 + @Property(name = "topoShape", value = DEFAULT_TOPO_SHAPE,
141 + label = "Topology shape: configured, linear, reroute, tree, spineleaf, mesh")
142 + private String topoShape = DEFAULT_TOPO_SHAPE;
143 +
144 + private static final int DEFAULT_DEVICE_COUNT = 10;
145 + @Property(name = "deviceCount", intValue = DEFAULT_DEVICE_COUNT,
146 + label = "Number of devices to generate")
147 + private int deviceCount = DEFAULT_DEVICE_COUNT;
148 +
149 + private static final int DEFAULT_HOST_COUNT = 5;
150 + @Property(name = "hostCount", intValue = DEFAULT_HOST_COUNT,
151 + label = "Number of host to generate per device")
152 + private int hostCount = DEFAULT_HOST_COUNT;
153 +
154 + private static final int DEFAULT_PACKET_RATE = 5;
155 + @Property(name = "packetRate", intValue = DEFAULT_PACKET_RATE,
156 + label = "Packet-in/s rate; 0 for no packets")
157 + private int packetRate = DEFAULT_PACKET_RATE;
158 +
159 + private static final double DEFAULT_MUTATION_RATE = 0;
160 + @Property(name = "mutationRate", doubleValue = DEFAULT_MUTATION_RATE,
161 + label = "Link event/s topology mutation rate; 0 for no mutations")
162 + private double mutationRate = DEFAULT_MUTATION_RATE;
163 +
164 + private static final String DEFAULT_MASTERSHIP = "random";
165 + @Property(name = "mastership", value = DEFAULT_MASTERSHIP,
166 + label = "Mastership given as 'random' or 'node1=dpid,dpid/node2=dpid,...'")
167 + private String mastership = DEFAULT_MASTERSHIP;
168 +
169 +
170 + @Activate
171 + public void activate(ComponentContext context) {
172 + cfgService.registerProperties(getClass());
173 +
174 + deviceProviderService = deviceProviderRegistry.register(deviceProvider);
175 + hostProviderService = hostProviderRegistry.register(hostProvider);
176 + linkProviderService = linkProviderRegistry.register(linkProvider);
177 + flowRuleProviderService = flowRuleProviderRegistry.register(flowRuleProvider);
178 + packetProviderService = packetProviderRegistry.register(packetProvider);
179 + log.info("Started");
180 + }
181 +
182 + @Deactivate
183 + public void deactivate(ComponentContext context) {
184 + cfgService.unregisterProperties(getClass(), false);
185 + tearDown();
186 +
187 + deviceProviderRegistry.unregister(deviceProvider);
188 + hostProviderRegistry.unregister(hostProvider);
189 + linkProviderRegistry.unregister(linkProvider);
190 + flowRuleProviderRegistry.unregister(flowRuleProvider);
191 + packetProviderRegistry.unregister(packetProvider);
192 +
193 + deviceProviderService = null;
194 + hostProviderService = null;
195 + linkProviderService = null;
196 + flowRuleProviderService = null;
197 + packetProviderService = null;
198 +
199 + log.info("Stopped");
200 + }
201 +
202 + @Modified
203 + public void modified(ComponentContext context) {
204 + Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
205 +
206 + boolean newEnabled;
207 + int newDeviceCount, newHostCount, newPacketRate;
208 + double newMutationRate;
209 + String newTopoShape, newMastership;
210 + try {
211 + String s = get(properties, "enabled");
212 + newEnabled = isNullOrEmpty(s) ? enabled : Boolean.parseBoolean(s.trim());
213 +
214 + newTopoShape = get(properties, "topoShape");
215 + newMastership = get(properties, "mastership");
216 +
217 + s = get(properties, "deviceCount");
218 + newDeviceCount = isNullOrEmpty(s) ? deviceCount : Integer.parseInt(s.trim());
219 +
220 + s = get(properties, "hostCount");
221 + newHostCount = isNullOrEmpty(s) ? hostCount : Integer.parseInt(s.trim());
222 +
223 + s = get(properties, "packetRate");
224 + newPacketRate = isNullOrEmpty(s) ? packetRate : Integer.parseInt(s.trim());
225 +
226 + s = get(properties, "mutationRate");
227 + newMutationRate = isNullOrEmpty(s) ? mutationRate : Double.parseDouble(s.trim());
228 +
229 + } catch (NumberFormatException e) {
230 + log.warn(e.getMessage());
231 + newEnabled = enabled;
232 + newTopoShape = topoShape;
233 + newDeviceCount = deviceCount;
234 + newHostCount = hostCount;
235 + newPacketRate = packetRate;
236 + newMutationRate = mutationRate;
237 + newMastership = mastership;
238 + }
239 +
240 + // Any change in the following parameters implies hard restart
241 + if (newEnabled != enabled || !newTopoShape.equals(topoShape) ||
242 + newDeviceCount != deviceCount || newHostCount != hostCount) {
243 + enabled = newEnabled;
244 + topoShape = newTopoShape;
245 + deviceCount = newDeviceCount;
246 + hostCount = newHostCount;
247 + packetRate = newPacketRate;
248 + mutationRate = newMutationRate;
249 + restartSimulation();
250 + }
251 +
252 + // Any change in the following parameters implies just a rate change
253 + if (newPacketRate != packetRate || newMutationRate != mutationRate) {
254 + packetRate = newPacketRate;
255 + mutationRate = newMutationRate;
256 + adjustRates();
257 + }
258 +
259 + // Any change in mastership implies just reassignments.
260 + if (!newMastership.equals(mastership)) {
261 + mastership = newMastership;
262 + reassignMastership();
263 + }
264 +
265 + log.info(FORMAT, enabled, topoShape, deviceCount, hostCount,
266 + packetRate, mutationRate);
267 + }
268 +
269 + /**
270 + * Severs the link between the specified end-points in both directions.
271 + *
272 + * @param one link endpoint
273 + * @param two link endpoint
274 + */
275 + public void severLink(ConnectPoint one, ConnectPoint two) {
276 + if (enabled) {
277 + topologyMutationDriver.severLink(one, two);
278 + }
279 + }
280 +
281 + /**
282 + * Severs the link between the specified end-points in both directions.
283 + *
284 + * @param one link endpoint
285 + * @param two link endpoint
286 + */
287 + public void repairLink(ConnectPoint one, ConnectPoint two) {
288 + if (enabled) {
289 + topologyMutationDriver.repairLink(one, two);
290 + }
291 + }
292 +
293 + // Resets simulation based on the current configuration parameters.
294 + private void restartSimulation() {
295 + tearDown();
296 + if (enabled) {
297 + setUp();
298 + }
299 + }
300 +
301 + // Sets up the topology simulation and all providers.
302 + private void setUp() {
303 + simulator = selectSimulator(topoShape);
304 + simulator.init(topoShape, deviceCount, hostCount,
305 + new DefaultServiceDirectory(),
306 + deviceProviderService, hostProviderService,
307 + linkProviderService);
308 + simulator.setUpTopology();
309 + flowRuleProvider.start(flowRuleProviderService);
310 + packetProvider.start(packetRate, hostService, deviceService,
311 + packetProviderService);
312 + topologyMutationDriver.start(mutationRate, linkService, deviceService,
313 + linkProviderService);
314 + }
315 +
316 + // Selects the simulator based on the specified name.
317 + private TopologySimulator selectSimulator(String topoShape) {
318 + if (topoShape.matches("linear([,].*|$)")) {
319 + return new LinearTopologySimulator();
320 + } else if (topoShape.matches("centipede([,].*|$)")) {
321 + return new CentipedeTopologySimulator();
322 + } else if (topoShape.matches("reroute([,].*|$)")) {
323 + return new RerouteTopologySimulator();
324 + } else if (topoShape.matches("tree([,].*|$)")) {
325 + return new TreeTopologySimulator();
326 + } else if (topoShape.matches("spineleaf([,].*|$)")) {
327 + return new SpineLeafTopologySimulator();
328 + } else if (topoShape.matches("mesh([,].*|$)")) {
329 + return new MeshTopologySimulator();
330 + } else {
331 + return new ConfiguredTopologySimulator();
332 + }
333 + }
334 +
335 + // Shuts down the topology simulator and all providers.
336 + private void tearDown() {
337 + if (simulator != null) {
338 + topologyMutationDriver.stop();
339 + packetProvider.stop();
340 + flowRuleProvider.stop();
341 + delay(500);
342 + rejectMastership();
343 + simulator.tearDownTopology();
344 + simulator = null;
345 + }
346 + }
347 +
348 + // Changes packet and mutation rates.
349 + private void adjustRates() {
350 + packetProvider.adjustRate(packetRate);
351 + topologyMutationDriver.adjustRate(mutationRate);
352 + }
353 +
354 + // Re-assigns mastership roles.
355 + private void reassignMastership() {
356 + if (mastership.equals(DEFAULT_MASTERSHIP)) {
357 + mastershipService.balanceRoles();
358 + } else {
359 + NodeId localNode = clusterService.getLocalNode().id();
360 + rejectMastership();
361 + String[] nodeSpecs = mastership.split("/");
362 + for (int i = 0; i < nodeSpecs.length; i++) {
363 + String[] specs = nodeSpecs[i].split("=");
364 + if (specs[0].equals(localNode.toString())) {
365 + String[] ids = specs[1].split(",");
366 + for (String id : ids) {
367 + mastershipService.setRole(localNode, deviceId(id), MASTER);
368 + }
369 + break;
370 + }
371 + }
372 + }
373 + }
374 +
375 + // Rejects mastership of all devices.
376 + private void rejectMastership() {
377 + NodeId localNode = clusterService.getLocalNode().id();
378 + deviceService.getDevices()
379 + .forEach(device -> mastershipService.setRole(localNode, device.id(),
380 + NONE));
381 + }
382 +
383 + // Null provider base class.
384 + abstract static class AbstractNullProvider extends AbstractProvider {
385 + protected AbstractNullProvider() {
386 + super(new ProviderId(SCHEME, PROVIDER_ID));
387 + }
388 + }
389 +
390 + // Device provider facade.
391 + private class NullDeviceProvider extends AbstractNullProvider implements DeviceProvider {
392 + @Override
393 + public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
394 + deviceProviderService.receivedRoleReply(deviceId, newRole, newRole);
395 + }
396 +
397 + @Override
398 + public boolean isReachable(DeviceId deviceId) {
399 + return topoShape.equals("configured") || deviceService.isAvailable(deviceId);
400 + }
401 +
402 + @Override
403 + public void triggerProbe(DeviceId deviceId) {
404 + }
405 + }
406 +
407 + // Host provider facade.
408 + private class NullHostProvider extends AbstractNullProvider implements HostProvider {
409 + @Override
410 + public void triggerProbe(Host host) {
411 + }
412 + }
413 +
414 + // Host provider facade.
415 + private class NullLinkProvider extends AbstractNullProvider implements LinkProvider {
416 + }
417 +
418 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.provider.nil;
17 +
18 +import static com.google.common.base.Preconditions.checkArgument;
19 +
20 +/**
21 + * Re-routable linear topology simulator with an alternate path in the middle.
22 + */
23 +public class RerouteTopologySimulator extends LinearTopologySimulator {
24 +
25 + @Override
26 + protected void processTopoShape(String shape) {
27 + super.processTopoShape(shape);
28 + infrastructurePorts = 3;
29 + deviceCount = (topoShape.length == 1) ? deviceCount : Integer.parseInt(topoShape[1]);
30 + }
31 +
32 + @Override
33 + public void setUpTopology() {
34 + checkArgument(deviceCount > 2, "There must be at least 3 devices");
35 + super.setUpTopology();
36 + }
37 +
38 + @Override
39 + protected void createLinks() {
40 + for (int i = 0, n = deviceCount - 2; i < n; i++) {
41 + createLink(i, i + 1);
42 + }
43 + int middle = (deviceCount - 1) / 2;
44 + int alternate = deviceCount - 1;
45 + createLink(middle - 1, alternate);
46 + createLink(middle, alternate);
47 + }
48 +
49 + @Override
50 + protected void createHosts() {
51 + createHosts(deviceIds.get(0), infrastructurePorts);
52 + createHosts(deviceIds.get(deviceCount - 2), infrastructurePorts);
53 + }
54 +
55 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.provider.nil;
17 +
18 +/**
19 + * Spine-leaf topology with hosts at the leaf devices.
20 + */
21 +public class SpineLeafTopologySimulator extends TopologySimulator {
22 +
23 + @Override
24 + protected void processTopoShape(String shape) {
25 + super.processTopoShape(shape);
26 + // FIXME: implement this
27 + }
28 +
29 + @Override
30 + public void setUpTopology() {
31 + // checkArgument(FIXME, "There must be at least one spine tier");
32 + super.setUpTopology();
33 + }
34 +
35 + @Override
36 + protected void createLinks() {
37 + }
38 +
39 + @Override
40 + protected void createHosts() {
41 + }
42 +
43 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.provider.nil;
17 +
18 +import com.google.common.collect.Lists;
19 +import org.onosproject.net.ConnectPoint;
20 +import org.onosproject.net.device.DeviceService;
21 +import org.onosproject.net.link.DefaultLinkDescription;
22 +import org.onosproject.net.link.LinkDescription;
23 +import org.onosproject.net.link.LinkProviderService;
24 +import org.onosproject.net.link.LinkService;
25 +import org.slf4j.Logger;
26 +import org.slf4j.LoggerFactory;
27 +
28 +import java.util.List;
29 +import java.util.Random;
30 +import java.util.concurrent.ExecutorService;
31 +import java.util.stream.Collectors;
32 +
33 +import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
34 +import static org.onlab.util.Tools.delay;
35 +import static org.onlab.util.Tools.groupedThreads;
36 +import static org.onosproject.net.Link.Type.DIRECT;
37 +import static org.onosproject.net.MastershipRole.MASTER;
38 +import static org.onosproject.provider.nil.TopologySimulator.description;
39 +
40 +/**
41 + * Drives topology mutations at a specified rate of events per second.
42 + */
43 +class TopologyMutationDriver implements Runnable {
44 +
45 + private final Logger log = LoggerFactory.getLogger(getClass());
46 +
47 + private static final int WAIT_DELAY = 2_000;
48 + private static final int MAX_DOWN_LINKS = 5;
49 +
50 + private final Random random = new Random();
51 +
52 + private volatile boolean stopped = true;
53 +
54 + private double mutationRate;
55 + private int millis, nanos;
56 +
57 + private LinkService linkService;
58 + private DeviceService deviceService;
59 + private LinkProviderService linkProviderService;
60 +
61 + private List<LinkDescription> activeLinks;
62 + private List<LinkDescription> inactiveLinks;
63 +
64 + private final ExecutorService executor =
65 + newSingleThreadScheduledExecutor(groupedThreads("onos/null", "topo-mutator"));
66 +
67 + /**
68 + * Starts the mutation process.
69 + *
70 + * @param mutationRate link events per second
71 + * @param linkService link service
72 + * @param deviceService device service
73 + * @param linkProviderService link provider service
74 + */
75 + void start(double mutationRate,
76 + LinkService linkService, DeviceService deviceService,
77 + LinkProviderService linkProviderService) {
78 + stopped = false;
79 + this.linkService = linkService;
80 + this.deviceService = deviceService;
81 + this.linkProviderService = linkProviderService;
82 + activeLinks = reduceLinks();
83 + inactiveLinks = Lists.newArrayList();
84 + adjustRate(mutationRate);
85 + executor.submit(this);
86 + }
87 +
88 + /**
89 + * Adjusts the topology mutation rate.
90 + *
91 + * @param mutationRate new topology mutation rate
92 + */
93 + void adjustRate(double mutationRate) {
94 + this.mutationRate = mutationRate;
95 + if (mutationRate > 0) {
96 + this.millis = (int) (1_000 / mutationRate / 2);
97 + this.nanos = (int) (1_000_000 / mutationRate / 2) % 1_000_000;
98 + } else {
99 + this.millis = 0;
100 + this.nanos = 0;
101 + }
102 + log.info("Settings: millis={}, nanos={}", millis, nanos);
103 + }
104 +
105 + /**
106 + * Stops the mutation process.
107 + */
108 + void stop() {
109 + stopped = true;
110 + }
111 +
112 + /**
113 + * Severs the link between the specified end-points in both directions.
114 + *
115 + * @param one link endpoint
116 + * @param two link endpoint
117 + */
118 + void severLink(ConnectPoint one, ConnectPoint two) {
119 + LinkDescription link = new DefaultLinkDescription(one, two, DIRECT);
120 + linkProviderService.linkVanished(link);
121 + linkProviderService.linkVanished(reverse(link));
122 +
123 + }
124 +
125 + /**
126 + * Repairs the link between the specified end-points in both directions.
127 + *
128 + * @param one link endpoint
129 + * @param two link endpoint
130 + */
131 + void repairLink(ConnectPoint one, ConnectPoint two) {
132 + LinkDescription link = new DefaultLinkDescription(one, two, DIRECT);
133 + linkProviderService.linkDetected(link);
134 + linkProviderService.linkDetected(reverse(link));
135 + }
136 +
137 + @Override
138 + public void run() {
139 + delay(WAIT_DELAY);
140 +
141 + while (!stopped) {
142 + if (mutationRate > 0 && inactiveLinks.isEmpty()) {
143 + primeInactiveLinks();
144 + } else if (mutationRate <= 0 && !inactiveLinks.isEmpty()) {
145 + repairInactiveLinks();
146 + } else if (inactiveLinks.isEmpty()) {
147 + delay(WAIT_DELAY);
148 +
149 + } else {
150 + activeLinks.add(repairLink());
151 + pause();
152 + inactiveLinks.add(severLink());
153 + pause();
154 + }
155 + }
156 + }
157 +
158 + // Primes the inactive links with a few random links.
159 + private void primeInactiveLinks() {
160 + for (int i = 0, n = Math.min(MAX_DOWN_LINKS, activeLinks.size()); i < n; i++) {
161 + inactiveLinks.add(severLink());
162 + }
163 + }
164 +
165 + // Repairs all inactive links.
166 + private void repairInactiveLinks() {
167 + while (!inactiveLinks.isEmpty()) {
168 + repairLink();
169 + }
170 + }
171 +
172 + // Picks a random active link and severs it.
173 + private LinkDescription severLink() {
174 + LinkDescription link = getRandomLink(activeLinks);
175 + linkProviderService.linkVanished(link);
176 + linkProviderService.linkVanished(reverse(link));
177 + return link;
178 + }
179 +
180 + // Picks a random inactive link and repairs it.
181 + private LinkDescription repairLink() {
182 + LinkDescription link = getRandomLink(inactiveLinks);
183 + linkProviderService.linkDetected(link);
184 + linkProviderService.linkDetected(reverse(link));
185 + return link;
186 + }
187 +
188 + // Produces a reverse of the specified link.
189 + private LinkDescription reverse(LinkDescription link) {
190 + return new DefaultLinkDescription(link.dst(), link.src(), link.type());
191 + }
192 +
193 + // Returns a random link from the specified list of links.
194 + private LinkDescription getRandomLink(List<LinkDescription> links) {
195 + return links.remove(random.nextInt(links.size()));
196 + }
197 +
198 + // Reduces the given list of links to just a single link in each original pair.
199 + private List<LinkDescription> reduceLinks() {
200 + List<LinkDescription> links = Lists.newArrayList();
201 + linkService.getLinks().forEach(link -> links.add(description(link)));
202 + return links.stream()
203 + .filter(this::isOurLink)
204 + .filter(this::isRightDirection)
205 + .collect(Collectors.toList());
206 + }
207 +
208 + // Returns true if the specified link is ours.
209 + private boolean isOurLink(LinkDescription linkDescription) {
210 + return deviceService.getRole(linkDescription.src().deviceId()) == MASTER;
211 + }
212 +
213 + // Returns true if the link source is greater than the link destination.
214 + private boolean isRightDirection(LinkDescription link) {
215 + return link.src().deviceId().toString().compareTo(link.dst().deviceId().toString()) > 0;
216 + }
217 +
218 + // Pauses the current thread for the pre-computed time of millis & nanos.
219 + private void pause() {
220 + delay(millis, nanos);
221 + }
222 +
223 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.provider.nil;
17 +
18 +import com.google.common.collect.Lists;
19 +import org.onlab.osgi.ServiceDirectory;
20 +import org.onlab.packet.ChassisId;
21 +import org.onlab.packet.IpAddress;
22 +import org.onlab.packet.MacAddress;
23 +import org.onlab.packet.VlanId;
24 +import org.onosproject.cluster.ClusterService;
25 +import org.onosproject.cluster.NodeId;
26 +import org.onosproject.mastership.MastershipService;
27 +import org.onosproject.net.ConnectPoint;
28 +import org.onosproject.net.Device;
29 +import org.onosproject.net.DeviceId;
30 +import org.onosproject.net.Host;
31 +import org.onosproject.net.HostId;
32 +import org.onosproject.net.HostLocation;
33 +import org.onosproject.net.Link;
34 +import org.onosproject.net.Port;
35 +import org.onosproject.net.PortNumber;
36 +import org.onosproject.net.device.DefaultDeviceDescription;
37 +import org.onosproject.net.device.DefaultPortDescription;
38 +import org.onosproject.net.device.DeviceAdminService;
39 +import org.onosproject.net.device.DeviceDescription;
40 +import org.onosproject.net.device.DeviceEvent;
41 +import org.onosproject.net.device.DeviceListener;
42 +import org.onosproject.net.device.DeviceProviderService;
43 +import org.onosproject.net.device.PortDescription;
44 +import org.onosproject.net.host.DefaultHostDescription;
45 +import org.onosproject.net.host.HostDescription;
46 +import org.onosproject.net.host.HostProviderService;
47 +import org.onosproject.net.host.HostService;
48 +import org.onosproject.net.link.DefaultLinkDescription;
49 +import org.onosproject.net.link.LinkProviderService;
50 +import org.onosproject.net.link.LinkService;
51 +import org.slf4j.Logger;
52 +import org.slf4j.LoggerFactory;
53 +
54 +import java.util.List;
55 +import java.util.concurrent.CountDownLatch;
56 +import java.util.concurrent.TimeUnit;
57 +
58 +import static org.onlab.util.Tools.toHex;
59 +import static org.onosproject.net.HostId.hostId;
60 +import static org.onosproject.net.Link.Type.DIRECT;
61 +import static org.onosproject.net.PortNumber.portNumber;
62 +import static org.onosproject.net.device.DeviceEvent.Type.*;
63 +import static org.onosproject.provider.nil.NullProviders.SCHEME;
64 +
65 +/**
66 + * Abstraction of a provider capable to simulate some network topology.
67 + */
68 +public abstract class TopologySimulator {
69 +
70 + protected final Logger log = LoggerFactory.getLogger(getClass());
71 +
72 + protected String[] topoShape;
73 + protected int deviceCount;
74 + protected int hostCount;
75 +
76 + protected ServiceDirectory directory;
77 + protected NodeId localNode;
78 +
79 + protected ClusterService clusterService;
80 + protected MastershipService mastershipService;
81 +
82 + protected DeviceAdminService deviceService;
83 + protected HostService hostService;
84 + protected LinkService linkService;
85 +
86 + protected DeviceProviderService deviceProviderService;
87 + protected HostProviderService hostProviderService;
88 + protected LinkProviderService linkProviderService;
89 +
90 + protected int maxWaitSeconds = 1;
91 + protected int infrastructurePorts = 2;
92 + protected CountDownLatch deviceLatch;
93 +
94 + protected final List<DeviceId> deviceIds = Lists.newArrayList();
95 +
96 + private DeviceListener deviceEventCounter = new DeviceEventCounter();
97 +
98 + /**
99 + * Initializes a new topology simulator with access to the specified service
100 + * directory and various provider services.
101 + *
102 + * @param topoShape topology shape specifier
103 + * @param deviceCount number of devices in the topology
104 + * @param hostCount number of hosts per device
105 + * @param directory service directory
106 + * @param deviceProviderService device provider service
107 + * @param hostProviderService host provider service
108 + * @param linkProviderService link provider service
109 + */
110 + protected void init(String topoShape, int deviceCount, int hostCount,
111 + ServiceDirectory directory,
112 + DeviceProviderService deviceProviderService,
113 + HostProviderService hostProviderService,
114 + LinkProviderService linkProviderService) {
115 + this.deviceCount = deviceCount;
116 + this.hostCount = hostCount;
117 + this.directory = directory;
118 +
119 + this.clusterService = directory.get(ClusterService.class);
120 + this.mastershipService = directory.get(MastershipService.class);
121 +
122 + this.deviceService = directory.get(DeviceAdminService.class);
123 + this.hostService = directory.get(HostService.class);
124 + this.linkService = directory.get(LinkService.class);
125 + this.deviceProviderService = deviceProviderService;
126 + this.hostProviderService = hostProviderService;
127 + this.linkProviderService = linkProviderService;
128 +
129 + localNode = clusterService.getLocalNode().id();
130 +
131 + processTopoShape(topoShape);
132 + }
133 +
134 + /**
135 + * Processes the topology shape specifier.
136 + *
137 + * @param shape topology shape specifier
138 + */
139 + protected void processTopoShape(String shape) {
140 + this.topoShape = shape.split(",");
141 + }
142 +
143 + /**
144 + * Sets up network topology simulation.
145 + */
146 + public void setUpTopology() {
147 + prepareForDeviceEvents(deviceCount);
148 + createDevices();
149 + waitForDeviceEvents();
150 +
151 + createLinks();
152 + createHosts();
153 + }
154 +
155 + /**
156 + * Creates simulated devices.
157 + */
158 + protected void createDevices() {
159 + for (int i = 0; i < deviceCount; i++) {
160 + createDevice(i + 1);
161 + }
162 + }
163 +
164 + /**
165 + * Creates simulated links.
166 + */
167 + protected abstract void createLinks();
168 +
169 + /**
170 + * Creates simulated hosts.
171 + */
172 + protected abstract void createHosts();
173 +
174 + /**
175 + * Creates simulated device.
176 + *
177 + * @param i index of the device id in the list.
178 + */
179 + protected void createDevice(int i) {
180 + DeviceId id = DeviceId.deviceId(SCHEME + ":" + toHex(i));
181 + DeviceDescription desc =
182 + new DefaultDeviceDescription(id.uri(), Device.Type.SWITCH,
183 + "ON.Lab", "0.1", "0.1", "1234",
184 + new ChassisId(i));
185 + deviceProviderService.deviceConnected(id, desc);
186 + deviceProviderService.updatePorts(id, buildPorts(hostCount + infrastructurePorts));
187 + deviceIds.add(id);
188 + }
189 +
190 + /**
191 + * Creates simulated link between two devices.
192 + *
193 + * @param i index of one simulated device
194 + * @param j index of another simulated device
195 + */
196 + protected void createLink(int i, int j) {
197 + ConnectPoint one = new ConnectPoint(deviceIds.get(i), PortNumber.portNumber(1));
198 + ConnectPoint two = new ConnectPoint(deviceIds.get(j), PortNumber.portNumber(2));
199 + linkProviderService.linkDetected(new DefaultLinkDescription(one, two, DIRECT));
200 + linkProviderService.linkDetected(new DefaultLinkDescription(two, one, DIRECT));
201 + }
202 +
203 + /**
204 + * Creates simularted hosts for the specified device.
205 + *
206 + * @param deviceId device identifier
207 + * @param portOffset port offset where to start attaching hosts
208 + */
209 + protected void createHosts(DeviceId deviceId, int portOffset) {
210 + String s = deviceId.toString();
211 + byte dByte = Byte.parseByte(s.substring(s.length() - 1), 16);
212 + // TODO: this limits the simulation to 256 devices & 256 hosts/device.
213 + byte[] macBytes = new byte[]{0, 0, 0, 0, dByte, 0};
214 + byte[] ipBytes = new byte[]{(byte) 192, (byte) 168, dByte, 0};
215 +
216 + for (int i = 0; i < hostCount; i++) {
217 + int port = portOffset + i + 1;
218 + macBytes[5] = (byte) (i + 1);
219 + ipBytes[3] = (byte) (i + 1);
220 + HostId id = hostId(MacAddress.valueOf(macBytes), VlanId.NONE);
221 + IpAddress ip = IpAddress.valueOf(IpAddress.Version.INET, ipBytes);
222 + hostProviderService.hostDetected(id, description(id, ip, deviceId, port));
223 + }
224 + }
225 +
226 + /**
227 + * Prepares to count device added/available/removed events.
228 + *
229 + * @param count number of events to count
230 + */
231 + protected void prepareForDeviceEvents(int count) {
232 + deviceLatch = new CountDownLatch(count);
233 + deviceService.addListener(deviceEventCounter);
234 + }
235 +
236 + /**
237 + * Waits for all expected device added/available/removed events.
238 + */
239 + protected void waitForDeviceEvents() {
240 + try {
241 + deviceLatch.await(maxWaitSeconds, TimeUnit.SECONDS);
242 + } catch (InterruptedException e) {
243 + log.warn("Device events did not arrive in time");
244 + }
245 + deviceService.removeListener(deviceEventCounter);
246 + }
247 +
248 +
249 + /**
250 + * Tears down network topology simulation.
251 + */
252 + public void tearDownTopology() {
253 + removeHosts();
254 + removeLinks();
255 + removeDevices();
256 + }
257 +
258 + /**
259 + * Removes any hosts previously advertised by this provider.
260 + */
261 + protected void removeHosts() {
262 + hostService.getHosts()
263 + .forEach(host -> hostProviderService.hostVanished(host.id()));
264 + }
265 +
266 + /**
267 + * Removes any links previously advertised by this provider.
268 + */
269 + protected void removeLinks() {
270 + linkService.getLinks()
271 + .forEach(link -> linkProviderService.linkVanished(description(link)));
272 + }
273 +
274 + /**
275 + * Removes any devices previously advertised by this provider.
276 + */
277 + protected void removeDevices() {
278 + prepareForDeviceEvents(deviceService.getDeviceCount());
279 + deviceService.getDevices()
280 + .forEach(device -> deviceService.removeDevice(device.id()));
281 + waitForDeviceEvents();
282 + }
283 +
284 +
285 + /**
286 + * Produces a device description from the given device.
287 + *
288 + * @param device device to copy
289 + * @return device description
290 + */
291 + static DeviceDescription description(Device device) {
292 + return new DefaultDeviceDescription(device.id().uri(), device.type(),
293 + device.manufacturer(),
294 + device.hwVersion(), device.swVersion(),
295 + device.serialNumber(), device.chassisId());
296 + }
297 +
298 + /**
299 + * Produces a link description from the given link.
300 + *
301 + * @param link link to copy
302 + * @return link description
303 + */
304 + static DefaultLinkDescription description(Link link) {
305 + return new DefaultLinkDescription(link.src(), link.dst(), link.type());
306 + }
307 +
308 + /**
309 + * Produces a host description from the given host.
310 + *
311 + * @param host host to copy
312 + * @return host description
313 + */
314 + static DefaultHostDescription description(Host host) {
315 + return new DefaultHostDescription(host.mac(), host.vlan(), host.location(),
316 + host.ipAddresses());
317 + }
318 +
319 + /**
320 + * Generates a host description from the given id and location information.
321 + *
322 + * @param hostId host identifier
323 + * @param ip host IP
324 + * @param deviceId edge device
325 + * @param port edge port
326 + * @return host description
327 + */
328 + static HostDescription description(HostId hostId, IpAddress ip,
329 + DeviceId deviceId, int port) {
330 + HostLocation location = new HostLocation(deviceId, portNumber(port), 0L);
331 + return new DefaultHostDescription(hostId.mac(), hostId.vlanId(), location, ip);
332 + }
333 +
334 + /**
335 + * Generates a list of a configured number of ports.
336 + *
337 + * @param portCount number of ports
338 + * @return list of ports
339 + */
340 + protected List<PortDescription> buildPorts(int portCount) {
341 + List<PortDescription> ports = Lists.newArrayList();
342 + for (int i = 0; i < portCount; i++) {
343 + ports.add(new DefaultPortDescription(PortNumber.portNumber(i), true,
344 + Port.Type.COPPER, 0));
345 + }
346 + return ports;
347 + }
348 +
349 + // Counts down number of device added/available/removed events.
350 + private class DeviceEventCounter implements DeviceListener {
351 + @Override
352 + public void event(DeviceEvent event) {
353 + DeviceEvent.Type type = event.type();
354 + if (type == DEVICE_ADDED || type == DEVICE_REMOVED ||
355 + type == DEVICE_AVAILABILITY_CHANGED) {
356 + deviceLatch.countDown();
357 + }
358 + }
359 + }
360 +}
...\ No newline at end of file ...\ No newline at end of file
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.provider.nil;
17 +
18 +import static com.google.common.base.Preconditions.checkArgument;
19 +
20 +/**
21 + * Tree topology with hosts at the leaf devices.
22 + */
23 +public class TreeTopologySimulator extends TopologySimulator {
24 +
25 + private int[] tierMultiplier;
26 + private int[] tierDeviceCount;
27 + private int[] tierOffset;
28 +
29 + @Override
30 + protected void processTopoShape(String shape) {
31 + super.processTopoShape(shape);
32 + tierOffset = new int[topoShape.length];
33 + tierMultiplier = new int[topoShape.length];
34 + tierDeviceCount = new int[topoShape.length];
35 +
36 + deviceCount = 1;
37 +
38 + tierOffset[0] = 0;
39 + tierMultiplier[0] = 1;
40 + tierDeviceCount[0] = deviceCount;
41 +
42 + for (int i = 1; i < topoShape.length; i++) {
43 + tierOffset[i] = deviceCount;
44 + tierMultiplier[i] = Integer.parseInt(topoShape[i]);
45 + tierDeviceCount[i] = tierDeviceCount[i - 1] * tierMultiplier[i];
46 + deviceCount = deviceCount + tierDeviceCount[i];
47 + }
48 + }
49 +
50 + @Override
51 + public void setUpTopology() {
52 + checkArgument(tierDeviceCount.length > 0, "There must be at least one tree tier");
53 + super.setUpTopology();
54 + }
55 +
56 + @Override
57 + protected void createLinks() {
58 + for (int t = 1; t < tierOffset.length; t++) {
59 + int child = tierOffset[t];
60 + for (int parent = tierOffset[t - 1]; parent < tierOffset[t]; parent++) {
61 + for (int i = 0; i < tierMultiplier[t]; i++) {
62 + createLink(parent, child);
63 + child++;
64 + }
65 + }
66 + }
67 + }
68 +
69 + @Override
70 + protected void createHosts() {
71 + for (int i = tierOffset[tierOffset.length - 1]; i < deviceCount; i++) {
72 + createHosts(deviceIds.get(i), hostCount);
73 + }
74 + }
75 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.provider.nil.cli;
17 +
18 +import org.apache.karaf.shell.commands.Argument;
19 +import org.apache.karaf.shell.commands.Command;
20 +import org.onosproject.cfg.ComponentConfigService;
21 +import org.onosproject.cli.AbstractShellCommand;
22 +import org.onosproject.provider.nil.NullProviders;
23 +
24 +import static org.onosproject.cli.StartStopCompleter.START;
25 +
26 +/**
27 + * Starts or stops topology simulation.
28 + */
29 +@Command(scope = "onos", name = "null-simulation",
30 + description = "Starts or stops topology simulation")
31 +public class NullControlCommand extends AbstractShellCommand {
32 +
33 + @Argument(index = 0, name = "cmd", description = "Control command: start/stop",
34 + required = true, multiValued = false)
35 + String cmd = null;
36 +
37 + @Argument(index = 1, name = "topoShape",
38 + description = "Topology shape: e.g. configured, linear, reroute, centipede, tree, spineleaf, mesh",
39 + required = false, multiValued = false)
40 + String topoShape = null;
41 +
42 + @Override
43 + protected void execute() {
44 + ComponentConfigService service = get(ComponentConfigService.class);
45 + if (topoShape != null) {
46 + service.setProperty(NullProviders.class.getName(), "topoShape", topoShape);
47 + }
48 + service.setProperty(NullProviders.class.getName(), "enabled",
49 + cmd.equals(START) ? "true" : "false");
50 + }
51 +
52 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.provider.nil.cli;
17 +
18 +import org.apache.karaf.shell.commands.Argument;
19 +import org.apache.karaf.shell.commands.Command;
20 +import org.onosproject.cli.AbstractShellCommand;
21 +import org.onosproject.net.ConnectPoint;
22 +import org.onosproject.net.DeviceId;
23 +import org.onosproject.net.PortNumber;
24 +import org.onosproject.provider.nil.NullProviders;
25 +
26 +import static org.onosproject.cli.UpDownCompleter.DOWN;
27 +import static org.onosproject.cli.UpDownCompleter.UP;
28 +import static org.onosproject.cli.net.AddPointToPointIntentCommand.getDeviceId;
29 +import static org.onosproject.cli.net.AddPointToPointIntentCommand.getPortNumber;
30 +import static org.onosproject.net.DeviceId.deviceId;
31 +import static org.onosproject.net.PortNumber.portNumber;
32 +
33 +/**
34 + * Servers or repairs a simulated link.
35 + */
36 +@Command(scope = "onos", name = "null-link",
37 + description = "Severs or repairs a simulated link")
38 +public class NullLinkCommand extends AbstractShellCommand {
39 +
40 + @Argument(index = 0, name = "one", description = "One link end-point as device/port",
41 + required = true, multiValued = false)
42 + String one = null;
43 +
44 + @Argument(index = 1, name = "two", description = "Another link end-point as device/port",
45 + required = true, multiValued = false)
46 + String two = null;
47 +
48 + @Argument(index = 2, name = "cmd", description = "up/down",
49 + required = true, multiValued = false)
50 + String cmd = null;
51 +
52 +
53 + @Override
54 + protected void execute() {
55 + NullProviders service = get(NullProviders.class);
56 +
57 + try {
58 + DeviceId oneId = deviceId(getDeviceId(one));
59 + PortNumber onePort = portNumber(getPortNumber(one));
60 + ConnectPoint onePoint = new ConnectPoint(oneId, onePort);
61 +
62 + DeviceId twoId = deviceId(getDeviceId(two));
63 + PortNumber twoPort = portNumber(getPortNumber(two));
64 + ConnectPoint twoPoint = new ConnectPoint(twoId, twoPort);
65 +
66 + if (cmd.equals(UP)) {
67 + service.repairLink(onePoint, twoPoint);
68 + } else if (cmd.equals(DOWN)) {
69 + service.severLink(onePoint, twoPoint);
70 + } else {
71 + error("Illegal command %s; must be up or down", cmd);
72 + }
73 + } catch (NumberFormatException e) {
74 + error("Invalid port number specified", e);
75 + }
76 + }
77 +
78 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.provider.nil.cli;
17 +
18 +import com.google.common.collect.ImmutableList;
19 +import org.onosproject.cli.AbstractChoicesCompleter;
20 +
21 +import java.util.List;
22 +
23 +/**
24 + * Topology shape completer.
25 + */
26 +public class TopologyShapeCompleter extends AbstractChoicesCompleter {
27 + @Override
28 + public List<String> choices() {
29 + return ImmutableList.of("configured", "linear", "reroute", "centipede",
30 + "tree", "spineleaf", "mesh");
31 + }
32 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +/**
18 + * Null provider CLI commands and completers.
19 + */
20 +package org.onosproject.provider.nil.cli;
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +/**
18 + * Set of null south-bound providers which permit simulating a network
19 + * topology using fake devices, links, hosts, etc.
20 + */
21 +package org.onosproject.provider.nil;
1 +<!--
2 + ~ Copyright 2015 Open Networking Laboratory
3 + ~
4 + ~ Licensed under the Apache License, Version 2.0 (the "License");
5 + ~ you may not use this file except in compliance with the License.
6 + ~ You may obtain a copy of the License at
7 + ~
8 + ~ http://www.apache.org/licenses/LICENSE-2.0
9 + ~
10 + ~ Unless required by applicable law or agreed to in writing, software
11 + ~ distributed under the License is distributed on an "AS IS" BASIS,
12 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + ~ See the License for the specific language governing permissions and
14 + ~ limitations under the License.
15 + -->
16 +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
17 +
18 + <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
19 + <command>
20 + <action class="org.onosproject.provider.nil.cli.NullControlCommand"/>
21 + <completers>
22 + <ref component-id="startStopCompleter"/>
23 + <ref component-id="topoShapeCompleter"/>
24 + <null/>
25 + </completers>
26 + </command>
27 + <command>
28 + <action class="org.onosproject.provider.nil.cli.NullLinkCommand"/>
29 + <completers>
30 + <ref component-id="linkSrcCompleter"/>
31 + <ref component-id="linkDstCompleter"/>
32 + <ref component-id="upDownCompleter"/>
33 + <null/>
34 + </completers>
35 + </command>
36 + </command-bundle>
37 +
38 + <bean id="startStopCompleter" class="org.onosproject.cli.StartStopCompleter"/>
39 + <bean id="upDownCompleter" class="org.onosproject.cli.UpDownCompleter"/>
40 + <bean id="topoShapeCompleter" class="org.onosproject.provider.nil.cli.TopologyShapeCompleter"/>
41 + <bean id="linkSrcCompleter" class="org.onosproject.cli.net.LinkSrcCompleter"/>
42 + <bean id="linkDstCompleter" class="org.onosproject.cli.net.LinkDstCompleter"/>
43 +
44 +</blueprint>
1 +{
2 + "devices": [
3 + { "alias": "s1", "uri": "null:0000000000000001", "mac": "000000000001", "annotations": { "name": "CMBR", "latitude": 42.373730, "longitude": -71.109734 }, "type": "SWITCH" },
4 + { "alias": "s2", "uri": "null:0000000000000002", "mac": "000000000002", "annotations": { "name": "CHCG", "latitude": 41.877461, "longitude": -87.642892 }, "type": "SWITCH" },
5 + { "alias": "s3", "uri": "null:0000000000000003", "mac": "000000000003", "annotations": { "name": "CLEV", "latitude": 41.498928, "longitude": -81.695217 }, "type": "SWITCH" },
6 + { "alias": "s4", "uri": "null:0000000000000004", "mac": "000000000004", "annotations": { "name": "RLGH", "latitude": 35.780150, "longitude": -78.644026 }, "type": "SWITCH" },
7 + { "alias": "s5", "uri": "null:0000000000000005", "mac": "000000000005", "annotations": { "name": "ATLN", "latitude": 33.749017, "longitude": -84.394168 }, "type": "SWITCH" },
8 + { "alias": "s6", "uri": "null:0000000000000006", "mac": "000000000006", "annotations": { "name": "PHLA", "latitude": 39.952906, "longitude": -75.172278 }, "type": "SWITCH" },
9 + { "alias": "s7", "uri": "null:0000000000000007", "mac": "000000000007", "annotations": { "name": "WASH", "latitude": 38.906696, "longitude": -77.035509 }, "type": "SWITCH" },
10 + { "alias": "s8", "uri": "null:0000000000000008", "mac": "000000000008", "annotations": { "name": "NSVL", "latitude": 36.166410, "longitude": -86.787305 }, "type": "SWITCH" },
11 + { "alias": "s9", "uri": "null:0000000000000009", "mac": "000000000009", "annotations": { "name": "STLS", "latitude": 38.626418, "longitude": -90.198143 }, "type": "SWITCH" },
12 + { "alias": "s10", "uri": "null:000000000000000a", "mac": "00000000000a", "annotations": { "name": "NWOR", "latitude": 29.951475, "longitude": -90.078434 }, "type": "SWITCH" },
13 + { "alias": "s11", "uri": "null:000000000000000b", "mac": "00000000000b", "annotations": { "name": "HSTN", "latitude": 29.763249, "longitude": -95.368332 }, "type": "SWITCH" },
14 + { "alias": "s12", "uri": "null:000000000000000c", "mac": "00000000000c", "annotations": { "name": "SNAN", "latitude": 29.424331, "longitude": -98.491745 }, "type": "SWITCH" },
15 + { "alias": "s13", "uri": "null:000000000000000d", "mac": "00000000000d", "annotations": { "name": "DLLS", "latitude": 32.777665, "longitude": -96.802064 }, "type": "SWITCH" },
16 + { "alias": "s14", "uri": "null:000000000000000e", "mac": "00000000000e", "annotations": { "name": "ORLD", "latitude": 28.538641, "longitude": -81.381110 }, "type": "SWITCH" },
17 + { "alias": "s15", "uri": "null:000000000000000f", "mac": "00000000000f", "annotations": { "name": "DNVR", "latitude": 39.736623, "longitude": -104.984887 }, "type": "SWITCH" },
18 + { "alias": "s16", "uri": "null:0000000000000010", "mac": "000000000010", "annotations": { "name": "KSCY", "latitude": 39.100725, "longitude": -94.581228 }, "type": "SWITCH" },
19 + { "alias": "s17", "uri": "null:0000000000000011", "mac": "000000000011", "annotations": { "name": "SNFN", "latitude": 37.779751, "longitude": -122.409791 }, "type": "SWITCH" },
20 + { "alias": "s18", "uri": "null:0000000000000012", "mac": "000000000012", "annotations": { "name": "SCRM", "latitude": 38.581001, "longitude": -121.497844 }, "type": "SWITCH" },
21 + { "alias": "s19", "uri": "null:0000000000000013", "mac": "000000000013", "annotations": { "name": "PTLD", "latitude": 45.523317, "longitude": -122.677768 }, "type": "SWITCH" },
22 + { "alias": "s20", "uri": "null:0000000000000014", "mac": "000000000014", "annotations": { "name": "STTL", "latitude": 47.607326, "longitude": -122.331786 }, "type": "SWITCH" },
23 + { "alias": "s21", "uri": "null:0000000000000015", "mac": "000000000015", "annotations": { "name": "SLKC", "latitude": 40.759577, "longitude": -111.895079 }, "type": "SWITCH" },
24 + { "alias": "s22", "uri": "null:0000000000000016", "mac": "000000000016", "annotations": { "name": "LA03", "latitude": 34.056346, "longitude": -118.235951 }, "type": "SWITCH" },
25 + { "alias": "s23", "uri": "null:0000000000000017", "mac": "000000000017", "annotations": { "name": "SNDG", "latitude": 32.714564, "longitude": -117.153528 }, "type": "SWITCH" },
26 + { "alias": "s24", "uri": "null:0000000000000018", "mac": "000000000018", "annotations": { "name": "PHNX", "latitude": 33.448289, "longitude": -112.076299 }, "type": "SWITCH" },
27 + { "alias": "s25", "uri": "null:0000000000000019", "mac": "000000000019", "annotations": { "name": "NY54", "latitude": 40.728270, "longitude": -73.994483 }, "type": "SWITCH" }
28 + ],
29 +
30 + "hosts": [
31 + { "alias": "h1", "mac": "00:00:00:00:00:01", "vlan": -1, "location": "null:0000000000000001/1", "ip": "10.0.0.1", "annotations": { "name": "CMBR", "latitude": 43.355715, "longitude": -69.528243 } },
32 + { "alias": "h2", "mac": "00:00:00:00:00:02", "vlan": -1, "location": "null:0000000000000002/1", "ip": "10.0.0.2", "annotations": { "name": "CHCG", "latitude": 43.632679, "longitude": -88.772526 } },
33 + { "alias": "h3", "mac": "00:00:00:00:00:03", "vlan": -1, "location": "null:0000000000000003/1", "ip": "10.0.0.3", "annotations": { "name": "CLEV", "latitude": 42.756945, "longitude": -79.831317 } },
34 + { "alias": "h4", "mac": "00:00:00:00:00:04", "vlan": -1, "location": "null:0000000000000004/1", "ip": "10.0.0.4", "annotations": { "name": "RLGH", "latitude": 36.972249, "longitude": -76.667163 } },
35 + { "alias": "h5", "mac": "00:00:00:00:00:05", "vlan": -1, "location": "null:0000000000000005/1", "ip": "10.0.0.5", "annotations": { "name": "ATLN", "latitude": 35.427493, "longitude": -83.885831 } },
36 + { "alias": "h6", "mac": "00:00:00:00:00:06", "vlan": -1, "location": "null:0000000000000006/1", "ip": "10.0.0.6", "annotations": { "name": "PHLA", "latitude": 39.208113, "longitude": -73.421341 } },
37 + { "alias": "h7", "mac": "00:00:00:00:00:07", "vlan": -1, "location": "null:0000000000000007/1", "ip": "10.0.0.7", "annotations": { "name": "WASH", "latitude": 40.133860, "longitude": -79.238299 } },
38 + { "alias": "h8", "mac": "00:00:00:00:00:08", "vlan": -1, "location": "null:0000000000000008/1", "ip": "10.0.0.8", "annotations": { "name": "NSVL", "latitude": 37.407589, "longitude": -84.415068 } },
39 + { "alias": "h9", "mac": "00:00:00:00:00:09", "vlan": -1, "location": "null:0000000000000009/1", "ip": "10.0.0.9", "annotations": { "name": "STLS", "latitude": 40.066810, "longitude": -90.932405 } },
40 + { "alias": "h10", "mac": "00:00:00:00:00:0a", "vlan": -1, "location": "null:000000000000000a/1", "ip": "10.0.0.10", "annotations": { "name": "NWOR", "latitude": 31.470982, "longitude": -88.779353 } },
41 + { "alias": "h11", "mac": "00:00:00:00:00:0b", "vlan": -1, "location": "null:000000000000000b/1", "ip": "10.0.0.11", "annotations": { "name": "HSTN", "latitude": 31.136858, "longitude": -94.351656 } },
42 + { "alias": "h12", "mac": "00:00:00:00:00:0c", "vlan": -1, "location": "null:000000000000000c/1", "ip": "10.0.0.12", "annotations": { "name": "SNAN", "latitude": 28.040975, "longitude": -99.169527 } },
43 + { "alias": "h13", "mac": "00:00:00:00:00:0d", "vlan": -1, "location": "null:000000000000000d/1", "ip": "10.0.0.13", "annotations": { "name": "DLLS", "latitude": 31.899825, "longitude": -99.287263 } },
44 + { "alias": "h14", "mac": "00:00:00:00:00:0e", "vlan": -1, "location": "null:000000000000000e/1", "ip": "10.0.0.14", "annotations": { "name": "ORLD", "latitude": 26.670509, "longitude": -81.291920 } },
45 + { "alias": "h15", "mac": "00:00:00:00:00:0f", "vlan": -1, "location": "null:000000000000000f/1", "ip": "10.0.0.15", "annotations": { "name": "DNVR", "latitude": 40.888148, "longitude": -103.459878 } },
46 + { "alias": "h16", "mac": "00:00:00:00:00:10", "vlan": -1, "location": "null:0000000000000010/1", "ip": "10.0.0.16", "annotations": { "name": "KSCY", "latitude": 40.545088, "longitude": -93.734002 } },
47 + { "alias": "h17", "mac": "00:00:00:00:00:11", "vlan": -1, "location": "null:0000000000000011/1", "ip": "10.0.0.17", "annotations": { "name": "SNFN", "latitude": 39.081743, "longitude": -124.330172 } },
48 + { "alias": "h18", "mac": "00:00:00:00:00:12", "vlan": -1, "location": "null:0000000000000012/1", "ip": "10.0.0.18", "annotations": { "name": "SCRM", "latitude": 40.107468, "longitude": -120.424689 } },
49 + { "alias": "h19", "mac": "00:00:00:00:00:13", "vlan": -1, "location": "null:0000000000000013/1", "ip": "10.0.0.19", "annotations": { "name": "PTLD", "latitude": 44.383051, "longitude": -124.767594 } },
50 + { "alias": "h20", "mac": "00:00:00:00:00:14", "vlan": -1, "location": "null:0000000000000014/1", "ip": "10.0.0.20", "annotations": { "name": "STTL", "latitude": 48.832627, "longitude": -120.298441 } },
51 + { "alias": "h21", "mac": "00:00:00:00:00:15", "vlan": -1, "location": "null:0000000000000015/1", "ip": "10.0.0.21", "annotations": { "name": "SLKC", "latitude": 42.301734, "longitude": -111.217297 } },
52 + { "alias": "h22", "mac": "00:00:00:00:00:16", "vlan": -1, "location": "null:0000000000000016/1", "ip": "10.0.0.22", "annotations": { "name": "LA03", "latitude": 33.224634, "longitude": -121.532943 } },
53 + { "alias": "h23", "mac": "00:00:00:00:00:17", "vlan": -1, "location": "null:0000000000000017/1", "ip": "10.0.0.23", "annotations": { "name": "SNDG", "latitude": 31.834607, "longitude": -118.847982 } },
54 + { "alias": "h24", "mac": "00:00:00:00:00:18", "vlan": -1, "location": "null:0000000000000018/1", "ip": "10.0.0.24", "annotations": { "name": "PHNX", "latitude": 34.662290, "longitude": -110.946662 } },
55 + { "alias": "h25", "mac": "00:00:00:00:00:19", "vlan": -1, "location": "null:0000000000000019/1", "ip": "10.0.0.25", "annotations": { "name": "NY54", "latitude": 42.395459, "longitude": -75.293563 } }
56 + ],
57 +
58 + "links": [
59 + { "src": "null:0000000000000019/2", "dst": "null:0000000000000001/2", "annotations": { "durable": "true" }},
60 + { "src": "null:0000000000000019/3", "dst": "null:0000000000000002/10", "annotations": { "durable": "true" }},
61 + { "src": "null:0000000000000019/4", "dst": "null:0000000000000006/3", "annotations": { "durable": "true" }},
62 + { "src": "null:0000000000000019/5", "dst": "null:0000000000000007/2", "annotations": { "durable": "true" }},
63 + { "src": "null:0000000000000001/2", "dst": "null:0000000000000006/4", "annotations": { "durable": "true" }},
64 + { "src": "null:0000000000000002/2", "dst": "null:0000000000000003/5", "annotations": { "durable": "true" }},
65 + { "src": "null:0000000000000002/3", "dst": "null:0000000000000006/5", "annotations": { "durable": "true" }},
66 + { "src": "null:0000000000000002/4", "dst": "null:0000000000000009/2", "annotations": { "durable": "true" }},
67 + { "src": "null:0000000000000002/5", "dst": "null:000000000000000f/5", "annotations": { "durable": "true" }},
68 + { "src": "null:0000000000000002/6", "dst": "null:0000000000000010/3", "annotations": { "durable": "true" }},
69 + { "src": "null:0000000000000002/7", "dst": "null:0000000000000011/7", "annotations": { "durable": "true" }},
70 + { "src": "null:0000000000000002/8", "dst": "null:0000000000000014/2", "annotations": { "durable": "true" }},
71 + { "src": "null:0000000000000002/9", "dst": "null:0000000000000015/3", "annotations": { "durable": "true" }},
72 + { "src": "null:0000000000000003/2", "dst": "null:0000000000000008/4", "annotations": { "durable": "true" }},
73 + { "src": "null:0000000000000003/3", "dst": "null:0000000000000009/5", "annotations": { "durable": "true" }},
74 + { "src": "null:0000000000000003/4", "dst": "null:0000000000000006/6", "annotations": { "durable": "true" }},
75 + { "src": "null:0000000000000004/2", "dst": "null:0000000000000005/7", "annotations": { "durable": "true" }},
76 + { "src": "null:0000000000000004/3", "dst": "null:0000000000000007/3", "annotations": { "durable": "true" }},
77 + { "src": "null:0000000000000005/2", "dst": "null:0000000000000007/4", "annotations": { "durable": "true" }},
78 + { "src": "null:0000000000000005/3", "dst": "null:0000000000000008/5", "annotations": { "durable": "true" }},
79 + { "src": "null:0000000000000005/4", "dst": "null:0000000000000009/3", "annotations": { "durable": "true" }},
80 + { "src": "null:0000000000000005/5", "dst": "null:000000000000000d/6", "annotations": { "durable": "true" }},
81 + { "src": "null:0000000000000005/6", "dst": "null:000000000000000e/2", "annotations": { "durable": "true" }},
82 + { "src": "null:0000000000000006/2", "dst": "null:0000000000000007/4", "annotations": { "durable": "true" }},
83 + { "src": "null:0000000000000008/2", "dst": "null:0000000000000009/6", "annotations": { "durable": "true" }},
84 + { "src": "null:0000000000000008/3", "dst": "null:000000000000000d/7", "annotations": { "durable": "true" }},
85 + { "src": "null:0000000000000009/2", "dst": "null:000000000000000d/8", "annotations": { "durable": "true" }},
86 + { "src": "null:0000000000000009/3", "dst": "null:0000000000000010/4", "annotations": { "durable": "true" }},
87 + { "src": "null:0000000000000009/4", "dst": "null:0000000000000016/5", "annotations": { "durable": "true" }},
88 + { "src": "null:000000000000000a/2", "dst": "null:000000000000000b/5", "annotations": { "durable": "true" }},
89 + { "src": "null:000000000000000a/3", "dst": "null:000000000000000d/9", "annotations": { "durable": "true" }},
90 + { "src": "null:000000000000000a/4", "dst": "null:000000000000000e/3", "annotations": { "durable": "true" }},
91 + { "src": "null:000000000000000b/2", "dst": "null:000000000000000c/4", "annotations": { "durable": "true" }},
92 + { "src": "null:000000000000000b/3", "dst": "null:000000000000000d/10", "annotations": { "durable": "true" }},
93 + { "src": "null:000000000000000b/4", "dst": "null:000000000000000e/4", "annotations": { "durable": "true" }},
94 + { "src": "null:000000000000000c/2", "dst": "null:0000000000000018/2", "annotations": { "durable": "true" }},
95 + { "src": "null:000000000000000c/3", "dst": "null:000000000000000d/6", "annotations": { "durable": "true" }},
96 + { "src": "null:000000000000000d/2", "dst": "null:000000000000000f/5", "annotations": { "durable": "true" }},
97 + { "src": "null:000000000000000d/3", "dst": "null:0000000000000010/5", "annotations": { "durable": "true" }},
98 + { "src": "null:000000000000000d/4", "dst": "null:0000000000000011/8", "annotations": { "durable": "true" }},
99 + { "src": "null:000000000000000d/5", "dst": "null:0000000000000016/6", "annotations": { "durable": "true" }},
100 + { "src": "null:000000000000000f/2", "dst": "null:0000000000000010/6", "annotations": { "durable": "true" }},
101 + { "src": "null:000000000000000f/3", "dst": "null:0000000000000011/9", "annotations": { "durable": "true" }},
102 + { "src": "null:000000000000000f/4", "dst": "null:0000000000000015/4", "annotations": { "durable": "true" }},
103 + { "src": "null:0000000000000010/2", "dst": "null:0000000000000011/10", "annotations": { "durable": "true" }},
104 + { "src": "null:0000000000000011/2", "dst": "null:0000000000000012/3", "annotations": { "durable": "true" }},
105 + { "src": "null:0000000000000011/3", "dst": "null:0000000000000013/3", "annotations": { "durable": "true" }},
106 + { "src": "null:0000000000000011/4", "dst": "null:0000000000000014/3", "annotations": { "durable": "true" }},
107 + { "src": "null:0000000000000011/5", "dst": "null:0000000000000015/4", "annotations": { "durable": "true" }},
108 + { "src": "null:0000000000000011/6", "dst": "null:0000000000000016/7", "annotations": { "durable": "true" }},
109 + { "src": "null:0000000000000012/2", "dst": "null:0000000000000015/5", "annotations": { "durable": "true" }},
110 + { "src": "null:0000000000000013/2", "dst": "null:0000000000000014/4", "annotations": { "durable": "true" }},
111 + { "src": "null:0000000000000015/2", "dst": "null:0000000000000016/8", "annotations": { "durable": "true" }},
112 + { "src": "null:0000000000000016/2", "dst": "null:0000000000000017/3", "annotations": { "durable": "true" }},
113 + { "src": "null:0000000000000016/3", "dst": "null:0000000000000018/3", "annotations": { "durable": "true" }},
114 + { "src": "null:0000000000000017/2", "dst": "null:0000000000000018/5", "annotations": { "durable": "true" }}
115 + ]
116 +}
...@@ -192,6 +192,20 @@ public abstract class Tools { ...@@ -192,6 +192,20 @@ public abstract class Tools {
192 } 192 }
193 193
194 /** 194 /**
195 + * Suspends the current thread for a specified number of millis and nanos.
196 + *
197 + * @param ms number of millis
198 + * @param nanos number of nanos
199 + */
200 + public static void delay(int ms, int nanos) {
201 + try {
202 + Thread.sleep(ms, nanos);
203 + } catch (InterruptedException e) {
204 + throw new RuntimeException("Interrupted", e);
205 + }
206 + }
207 +
208 + /**
195 * Slurps the contents of a file into a list of strings, one per line. 209 * Slurps the contents of a file into a list of strings, one per line.
196 * 210 *
197 * @param path file path 211 * @param path file path
......
...@@ -16,6 +16,11 @@ ...@@ -16,6 +16,11 @@
16 package org.onosproject.rest; 16 package org.onosproject.rest;
17 17
18 import com.fasterxml.jackson.databind.JsonNode; 18 import com.fasterxml.jackson.databind.JsonNode;
19 +import com.google.common.collect.Lists;
20 +import org.onlab.packet.ChassisId;
21 +import org.onlab.packet.IpAddress;
22 +import org.onlab.packet.MacAddress;
23 +import org.onlab.packet.VlanId;
19 import org.onosproject.net.ConnectPoint; 24 import org.onosproject.net.ConnectPoint;
20 import org.onosproject.net.DefaultAnnotations; 25 import org.onosproject.net.DefaultAnnotations;
21 import org.onosproject.net.Device; 26 import org.onosproject.net.Device;
...@@ -30,9 +35,12 @@ import org.onosproject.net.SparseAnnotations; ...@@ -30,9 +35,12 @@ import org.onosproject.net.SparseAnnotations;
30 import org.onosproject.net.device.DefaultDeviceDescription; 35 import org.onosproject.net.device.DefaultDeviceDescription;
31 import org.onosproject.net.device.DefaultPortDescription; 36 import org.onosproject.net.device.DefaultPortDescription;
32 import org.onosproject.net.device.DeviceDescription; 37 import org.onosproject.net.device.DeviceDescription;
38 +import org.onosproject.net.device.DeviceEvent;
39 +import org.onosproject.net.device.DeviceListener;
33 import org.onosproject.net.device.DeviceProvider; 40 import org.onosproject.net.device.DeviceProvider;
34 import org.onosproject.net.device.DeviceProviderRegistry; 41 import org.onosproject.net.device.DeviceProviderRegistry;
35 import org.onosproject.net.device.DeviceProviderService; 42 import org.onosproject.net.device.DeviceProviderService;
43 +import org.onosproject.net.device.DeviceService;
36 import org.onosproject.net.device.PortDescription; 44 import org.onosproject.net.device.PortDescription;
37 import org.onosproject.net.host.DefaultHostDescription; 45 import org.onosproject.net.host.DefaultHostDescription;
38 import org.onosproject.net.host.HostProvider; 46 import org.onosproject.net.host.HostProvider;
...@@ -43,10 +51,8 @@ import org.onosproject.net.link.LinkProvider; ...@@ -43,10 +51,8 @@ import org.onosproject.net.link.LinkProvider;
43 import org.onosproject.net.link.LinkProviderRegistry; 51 import org.onosproject.net.link.LinkProviderRegistry;
44 import org.onosproject.net.link.LinkProviderService; 52 import org.onosproject.net.link.LinkProviderService;
45 import org.onosproject.net.provider.ProviderId; 53 import org.onosproject.net.provider.ProviderId;
46 -import org.onlab.packet.ChassisId; 54 +import org.slf4j.Logger;
47 -import org.onlab.packet.IpAddress; 55 +import org.slf4j.LoggerFactory;
48 -import org.onlab.packet.MacAddress;
49 -import org.onlab.packet.VlanId;
50 56
51 import java.net.URI; 57 import java.net.URI;
52 import java.util.ArrayList; 58 import java.util.ArrayList;
...@@ -54,37 +60,60 @@ import java.util.HashSet; ...@@ -54,37 +60,60 @@ import java.util.HashSet;
54 import java.util.Iterator; 60 import java.util.Iterator;
55 import java.util.List; 61 import java.util.List;
56 import java.util.Set; 62 import java.util.Set;
63 +import java.util.concurrent.CountDownLatch;
64 +import java.util.concurrent.TimeUnit;
65 +import java.util.stream.Collectors;
57 66
58 import static com.google.common.base.Preconditions.checkNotNull; 67 import static com.google.common.base.Preconditions.checkNotNull;
59 import static org.onosproject.net.DeviceId.deviceId; 68 import static org.onosproject.net.DeviceId.deviceId;
60 import static org.onosproject.net.PortNumber.portNumber; 69 import static org.onosproject.net.PortNumber.portNumber;
70 +import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
71 +import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED;
61 72
62 /** 73 /**
63 * Provider of devices and links parsed from a JSON configuration structure. 74 * Provider of devices and links parsed from a JSON configuration structure.
64 */ 75 */
65 class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider { 76 class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
66 77
78 + private final Logger log = LoggerFactory.getLogger(getClass());
79 +
67 private static final ProviderId PID = 80 private static final ProviderId PID =
68 new ProviderId("cfg", "org.onosproject.rest", true); 81 new ProviderId("cfg", "org.onosproject.rest", true);
69 82
83 + private static final String UNKNOWN = "unknown";
84 +
85 + private CountDownLatch deviceLatch;
86 +
70 private final JsonNode cfg; 87 private final JsonNode cfg;
88 + private final DeviceService deviceService;
89 +
71 private final DeviceProviderRegistry deviceProviderRegistry; 90 private final DeviceProviderRegistry deviceProviderRegistry;
72 private final LinkProviderRegistry linkProviderRegistry; 91 private final LinkProviderRegistry linkProviderRegistry;
73 private final HostProviderRegistry hostProviderRegistry; 92 private final HostProviderRegistry hostProviderRegistry;
74 93
94 + private DeviceProviderService deviceProviderService;
95 + private LinkProviderService linkProviderService;
96 + private HostProviderService hostProviderService;
97 +
98 + private DeviceListener deviceEventCounter = new DeviceEventCounter();
99 + private List<ConnectPoint> connectPoints = Lists.newArrayList();
100 +
75 /** 101 /**
76 * Creates a new configuration provider. 102 * Creates a new configuration provider.
77 * 103 *
78 * @param cfg JSON configuration 104 * @param cfg JSON configuration
105 + * @param deviceService device service
79 * @param deviceProviderRegistry device provider registry 106 * @param deviceProviderRegistry device provider registry
80 * @param linkProviderRegistry link provider registry 107 * @param linkProviderRegistry link provider registry
81 * @param hostProviderRegistry host provider registry 108 * @param hostProviderRegistry host provider registry
82 */ 109 */
83 ConfigProvider(JsonNode cfg, 110 ConfigProvider(JsonNode cfg,
111 + DeviceService deviceService,
84 DeviceProviderRegistry deviceProviderRegistry, 112 DeviceProviderRegistry deviceProviderRegistry,
85 LinkProviderRegistry linkProviderRegistry, 113 LinkProviderRegistry linkProviderRegistry,
86 HostProviderRegistry hostProviderRegistry) { 114 HostProviderRegistry hostProviderRegistry) {
87 this.cfg = checkNotNull(cfg, "Configuration cannot be null"); 115 this.cfg = checkNotNull(cfg, "Configuration cannot be null");
116 + this.deviceService = checkNotNull(deviceService, "Device service cannot be null");
88 this.deviceProviderRegistry = checkNotNull(deviceProviderRegistry, "Device provider registry cannot be null"); 117 this.deviceProviderRegistry = checkNotNull(deviceProviderRegistry, "Device provider registry cannot be null");
89 this.linkProviderRegistry = checkNotNull(linkProviderRegistry, "Link provider registry cannot be null"); 118 this.linkProviderRegistry = checkNotNull(linkProviderRegistry, "Link provider registry cannot be null");
90 this.hostProviderRegistry = checkNotNull(hostProviderRegistry, "Host provider registry cannot be null"); 119 this.hostProviderRegistry = checkNotNull(hostProviderRegistry, "Host provider registry cannot be null");
...@@ -94,56 +123,74 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider { ...@@ -94,56 +123,74 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
94 * Parses the given JSON and provides links as configured. 123 * Parses the given JSON and provides links as configured.
95 */ 124 */
96 void parse() { 125 void parse() {
126 + try {
127 + register();
97 parseDevices(); 128 parseDevices();
98 parseLinks(); 129 parseLinks();
99 parseHosts(); 130 parseHosts();
131 + addMissingPorts();
132 + } finally {
133 + unregister();
134 + }
135 + }
136 +
137 + private void register() {
138 + deviceProviderService = deviceProviderRegistry.register(this);
139 + linkProviderService = linkProviderRegistry.register(this);
140 + hostProviderService = hostProviderRegistry.register(this);
141 + }
142 +
143 + private void unregister() {
144 + deviceProviderRegistry.unregister(this);
145 + linkProviderRegistry.unregister(this);
146 + hostProviderRegistry.unregister(this);
100 } 147 }
101 148
102 // Parses the given JSON and provides devices. 149 // Parses the given JSON and provides devices.
103 private void parseDevices() { 150 private void parseDevices() {
104 try { 151 try {
105 - DeviceProviderService dps = deviceProviderRegistry.register(this);
106 JsonNode nodes = cfg.get("devices"); 152 JsonNode nodes = cfg.get("devices");
107 if (nodes != null) { 153 if (nodes != null) {
154 + prepareForDeviceEvents(nodes.size());
108 for (JsonNode node : nodes) { 155 for (JsonNode node : nodes) {
109 - parseDevice(dps, node); 156 + parseDevice(node);
110 } 157 }
111 } 158 }
112 } finally { 159 } finally {
113 - deviceProviderRegistry.unregister(this); 160 + waitForDeviceEvents();
114 } 161 }
115 } 162 }
116 163
117 // Parses the given node with device data and supplies the device. 164 // Parses the given node with device data and supplies the device.
118 - private void parseDevice(DeviceProviderService dps, JsonNode node) { 165 + private void parseDevice(JsonNode node) {
119 URI uri = URI.create(get(node, "uri")); 166 URI uri = URI.create(get(node, "uri"));
120 - Device.Type type = Device.Type.valueOf(get(node, "type")); 167 + Device.Type type = Device.Type.valueOf(get(node, "type", "SWITCH"));
121 - String mfr = get(node, "mfr"); 168 + String mfr = get(node, "mfr", UNKNOWN);
122 - String hw = get(node, "hw"); 169 + String hw = get(node, "hw", UNKNOWN);
123 - String sw = get(node, "sw"); 170 + String sw = get(node, "sw", UNKNOWN);
124 - String serial = get(node, "serial"); 171 + String serial = get(node, "serial", UNKNOWN);
125 - ChassisId cid = new ChassisId(get(node, "mac")); 172 + ChassisId cid = new ChassisId(get(node, "mac", "000000000000"));
126 SparseAnnotations annotations = annotations(node.get("annotations")); 173 SparseAnnotations annotations = annotations(node.get("annotations"));
127 174
128 DeviceDescription desc = 175 DeviceDescription desc =
129 new DefaultDeviceDescription(uri, type, mfr, hw, sw, serial, 176 new DefaultDeviceDescription(uri, type, mfr, hw, sw, serial,
130 cid, annotations); 177 cid, annotations);
131 DeviceId deviceId = deviceId(uri); 178 DeviceId deviceId = deviceId(uri);
132 - dps.deviceConnected(deviceId, desc); 179 + deviceProviderService.deviceConnected(deviceId, desc);
133 180
134 JsonNode ports = node.get("ports"); 181 JsonNode ports = node.get("ports");
135 if (ports != null) { 182 if (ports != null) {
136 - parsePorts(dps, deviceId, ports); 183 + parsePorts(deviceId, ports);
137 } 184 }
138 } 185 }
139 186
140 // Parses the given node with list of device ports. 187 // Parses the given node with list of device ports.
141 - private void parsePorts(DeviceProviderService dps, DeviceId deviceId, JsonNode nodes) { 188 + private void parsePorts(DeviceId deviceId, JsonNode nodes) {
142 List<PortDescription> ports = new ArrayList<>(); 189 List<PortDescription> ports = new ArrayList<>();
143 for (JsonNode node : nodes) { 190 for (JsonNode node : nodes) {
144 ports.add(parsePort(node)); 191 ports.add(parsePort(node));
145 } 192 }
146 - dps.updatePorts(deviceId, ports); 193 + deviceProviderService.updatePorts(deviceId, ports);
147 } 194 }
148 195
149 // Parses the given node with port information. 196 // Parses the given node with port information.
...@@ -156,43 +203,41 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider { ...@@ -156,43 +203,41 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
156 203
157 // Parses the given JSON and provides links as configured. 204 // Parses the given JSON and provides links as configured.
158 private void parseLinks() { 205 private void parseLinks() {
159 - try {
160 - LinkProviderService lps = linkProviderRegistry.register(this);
161 JsonNode nodes = cfg.get("links"); 206 JsonNode nodes = cfg.get("links");
162 if (nodes != null) { 207 if (nodes != null) {
163 for (JsonNode node : nodes) { 208 for (JsonNode node : nodes) {
164 - parseLink(lps, node, false); 209 + parseLink(node, false);
165 if (!node.has("halfplex")) { 210 if (!node.has("halfplex")) {
166 - parseLink(lps, node, true); 211 + parseLink(node, true);
167 - }
168 } 212 }
169 } 213 }
170 - } finally {
171 - linkProviderRegistry.unregister(this);
172 } 214 }
173 } 215 }
174 216
175 // Parses the given node with link data and supplies the link. 217 // Parses the given node with link data and supplies the link.
176 - private void parseLink(LinkProviderService lps, JsonNode node, boolean reverse) { 218 + private void parseLink(JsonNode node, boolean reverse) {
177 ConnectPoint src = connectPoint(get(node, "src")); 219 ConnectPoint src = connectPoint(get(node, "src"));
178 ConnectPoint dst = connectPoint(get(node, "dst")); 220 ConnectPoint dst = connectPoint(get(node, "dst"));
179 - Link.Type type = Link.Type.valueOf(get(node, "type")); 221 + Link.Type type = Link.Type.valueOf(get(node, "type", "DIRECT"));
180 SparseAnnotations annotations = annotations(node.get("annotations")); 222 SparseAnnotations annotations = annotations(node.get("annotations"));
181 223
182 DefaultLinkDescription desc = reverse ? 224 DefaultLinkDescription desc = reverse ?
183 new DefaultLinkDescription(dst, src, type, annotations) : 225 new DefaultLinkDescription(dst, src, type, annotations) :
184 new DefaultLinkDescription(src, dst, type, annotations); 226 new DefaultLinkDescription(src, dst, type, annotations);
185 - lps.linkDetected(desc); 227 + linkProviderService.linkDetected(desc);
228 +
229 + connectPoints.add(src);
230 + connectPoints.add(dst);
186 } 231 }
187 232
188 // Parses the given JSON and provides hosts as configured. 233 // Parses the given JSON and provides hosts as configured.
189 private void parseHosts() { 234 private void parseHosts() {
190 try { 235 try {
191 - HostProviderService hps = hostProviderRegistry.register(this);
192 JsonNode nodes = cfg.get("hosts"); 236 JsonNode nodes = cfg.get("hosts");
193 if (nodes != null) { 237 if (nodes != null) {
194 for (JsonNode node : nodes) { 238 for (JsonNode node : nodes) {
195 - parseHost(hps, node); 239 + parseHost(node);
240 + parseHost(node); // FIXME: hack to make sure host positions take
196 } 241 }
197 } 242 }
198 } finally { 243 } finally {
...@@ -201,14 +246,14 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider { ...@@ -201,14 +246,14 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
201 } 246 }
202 247
203 // Parses the given node with host data and supplies the host. 248 // Parses the given node with host data and supplies the host.
204 - private void parseHost(HostProviderService hps, JsonNode node) { 249 + private void parseHost(JsonNode node) {
205 MacAddress mac = MacAddress.valueOf(get(node, "mac")); 250 MacAddress mac = MacAddress.valueOf(get(node, "mac"));
206 - VlanId vlanId = VlanId.vlanId(node.get("vlan").shortValue()); 251 + VlanId vlanId = VlanId.vlanId((short) node.get("vlan").asInt(VlanId.UNTAGGED));
207 HostId hostId = HostId.hostId(mac, vlanId); 252 HostId hostId = HostId.hostId(mac, vlanId);
208 SparseAnnotations annotations = annotations(node.get("annotations")); 253 SparseAnnotations annotations = annotations(node.get("annotations"));
209 HostLocation location = new HostLocation(connectPoint(get(node, "location")), 0); 254 HostLocation location = new HostLocation(connectPoint(get(node, "location")), 0);
210 255
211 - String[] ipStrings = get(node, "ip").split(","); 256 + String[] ipStrings = get(node, "ip", "").split(",");
212 Set<IpAddress> ips = new HashSet<>(); 257 Set<IpAddress> ips = new HashSet<>();
213 for (String ip : ipStrings) { 258 for (String ip : ipStrings) {
214 ips.add(IpAddress.valueOf(ip.trim())); 259 ips.add(IpAddress.valueOf(ip.trim()));
...@@ -216,9 +261,45 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider { ...@@ -216,9 +261,45 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
216 261
217 DefaultHostDescription desc = 262 DefaultHostDescription desc =
218 new DefaultHostDescription(mac, vlanId, location, ips, annotations); 263 new DefaultHostDescription(mac, vlanId, location, ips, annotations);
219 - hps.hostDetected(hostId, desc); 264 + hostProviderService.hostDetected(hostId, desc);
265 +
266 + connectPoints.add(location);
267 + }
268 +
269 + // Adds any missing device ports for configured links and host locations.
270 + private void addMissingPorts() {
271 + deviceService.getDevices().forEach(this::addMissingPorts);
220 } 272 }
221 273
274 + // Adds any missing device ports.
275 + private void addMissingPorts(Device device) {
276 + List<Port> ports = deviceService.getPorts(device.id());
277 + Set<ConnectPoint> existing = ports.stream()
278 + .map(p -> new ConnectPoint(device.id(), p.number()))
279 + .collect(Collectors.toSet());
280 + Set<ConnectPoint> missing = connectPoints.stream()
281 + .filter(cp -> !existing.contains(cp))
282 + .collect(Collectors.toSet());
283 +
284 + if (!missing.isEmpty()) {
285 + List<PortDescription> newPorts = Lists.newArrayList();
286 + ports.forEach(p -> newPorts.add(description(p)));
287 + missing.forEach(cp -> newPorts.add(description(cp)));
288 + deviceProviderService.updatePorts(device.id(), newPorts);
289 + }
290 + }
291 +
292 + // Creates a port description from the specified port.
293 + private PortDescription description(Port p) {
294 + return new DefaultPortDescription(p.number(), p.isEnabled(), p.type(), p.portSpeed());
295 + }
296 +
297 + // Creates a port description from the specified connection point.
298 + private PortDescription description(ConnectPoint cp) {
299 + return new DefaultPortDescription(cp.port(), true);
300 + }
301 +
302 +
222 // Produces set of annotations from the given JSON node. 303 // Produces set of annotations from the given JSON node.
223 private SparseAnnotations annotations(JsonNode node) { 304 private SparseAnnotations annotations(JsonNode node) {
224 if (node == null) { 305 if (node == null) {
...@@ -246,12 +327,18 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider { ...@@ -246,12 +327,18 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
246 return node.path(name).asText(); 327 return node.path(name).asText();
247 } 328 }
248 329
249 - @Override 330 + // Returns string form of the named property in the given JSON object.
250 - public void triggerProbe(DeviceId deviceId) { 331 + private String get(JsonNode node, String name, String defaultValue) {
332 + return node.path(name).asText(defaultValue);
251 } 333 }
252 334
253 @Override 335 @Override
254 public void roleChanged(DeviceId device, MastershipRole newRole) { 336 public void roleChanged(DeviceId device, MastershipRole newRole) {
337 + deviceProviderService.receivedRoleReply(device, newRole, newRole);
338 + }
339 +
340 + @Override
341 + public void triggerProbe(DeviceId deviceId) {
255 } 342 }
256 343
257 @Override 344 @Override
...@@ -265,6 +352,40 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider { ...@@ -265,6 +352,40 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
265 352
266 @Override 353 @Override
267 public boolean isReachable(DeviceId device) { 354 public boolean isReachable(DeviceId device) {
268 - return false; 355 + return true;
269 } 356 }
357 +
358 + /**
359 + * Prepares to count device added/available/removed events.
360 + *
361 + * @param count number of events to count
362 + */
363 + protected void prepareForDeviceEvents(int count) {
364 + deviceLatch = new CountDownLatch(count);
365 + deviceService.addListener(deviceEventCounter);
366 + }
367 +
368 + /**
369 + * Waits for all expected device added/available/removed events.
370 + */
371 + protected void waitForDeviceEvents() {
372 + try {
373 + deviceLatch.await(2, TimeUnit.SECONDS);
374 + } catch (InterruptedException e) {
375 + log.warn("Device events did not arrive in time");
376 + }
377 + deviceService.removeListener(deviceEventCounter);
378 + }
379 +
380 + // Counts down number of device added/available/removed events.
381 + private class DeviceEventCounter implements DeviceListener {
382 + @Override
383 + public void event(DeviceEvent event) {
384 + DeviceEvent.Type type = event.type();
385 + if (type == DEVICE_ADDED || type == DEVICE_AVAILABILITY_CHANGED) {
386 + deviceLatch.countDown();
387 + }
388 + }
389 + }
390 +
270 } 391 }
......
...@@ -18,6 +18,7 @@ package org.onosproject.rest; ...@@ -18,6 +18,7 @@ package org.onosproject.rest;
18 import com.fasterxml.jackson.databind.JsonNode; 18 import com.fasterxml.jackson.databind.JsonNode;
19 import com.fasterxml.jackson.databind.ObjectMapper; 19 import com.fasterxml.jackson.databind.ObjectMapper;
20 import org.onosproject.net.device.DeviceProviderRegistry; 20 import org.onosproject.net.device.DeviceProviderRegistry;
21 +import org.onosproject.net.device.DeviceService;
21 import org.onosproject.net.host.HostProviderRegistry; 22 import org.onosproject.net.host.HostProviderRegistry;
22 import org.onosproject.net.link.LinkProviderRegistry; 23 import org.onosproject.net.link.LinkProviderRegistry;
23 import org.onlab.rest.BaseResource; 24 import org.onlab.rest.BaseResource;
...@@ -40,9 +41,9 @@ import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; ...@@ -40,9 +41,9 @@ import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
40 * devices, ports and links. 41 * devices, ports and links.
41 */ 42 */
42 @Path("config") 43 @Path("config")
43 -public class ConfigResource extends BaseResource { 44 +public class ConfigWebResource extends BaseResource {
44 45
45 - private static Logger log = LoggerFactory.getLogger(ConfigResource.class); 46 + private static Logger log = LoggerFactory.getLogger(ConfigWebResource.class);
46 47
47 @POST 48 @POST
48 @Path("topology") 49 @Path("topology")
...@@ -52,7 +53,8 @@ public class ConfigResource extends BaseResource { ...@@ -52,7 +53,8 @@ public class ConfigResource extends BaseResource {
52 try { 53 try {
53 ObjectMapper mapper = new ObjectMapper(); 54 ObjectMapper mapper = new ObjectMapper();
54 JsonNode cfg = mapper.readTree(input); 55 JsonNode cfg = mapper.readTree(input);
55 - new ConfigProvider(cfg, get(DeviceProviderRegistry.class), 56 + new ConfigProvider(cfg, get(DeviceService.class),
57 + get(DeviceProviderRegistry.class),
56 get(LinkProviderRegistry.class), 58 get(LinkProviderRegistry.class),
57 get(HostProviderRegistry.class)).parse(); 59 get(HostProviderRegistry.class)).parse();
58 return Response.ok().build(); 60 return Response.ok().build();
......
...@@ -72,7 +72,7 @@ ...@@ -72,7 +72,7 @@
72 org.onosproject.rest.IntentsWebResource, 72 org.onosproject.rest.IntentsWebResource,
73 org.onosproject.rest.FlowsWebResource, 73 org.onosproject.rest.FlowsWebResource,
74 org.onosproject.rest.TopologyWebResource, 74 org.onosproject.rest.TopologyWebResource,
75 - org.onosproject.rest.ConfigResource, 75 + org.onosproject.rest.ConfigWebResource,
76 org.onosproject.rest.PathsWebResource 76 org.onosproject.rest.PathsWebResource
77 </param-value> 77 </param-value>
78 </init-param> 78 </init-param>
......