[AETHER-76] Impelentation of a new Trellis Troubleshoot Tool (T3) for offline mode
- For the performance improvement, T3 offline mode uses snapshots of the network states
called Network Information Base (NIB) instead of runtime interactions with ONOS core
during troubleshooting a Trellis system.
- Partially tested with some mininet topos for trellis
(https://github.com/opennetworkinglab/routing/tree/master/trellis).
- Usage instruction docs (https://docs.trellisfabric.org/troubleshooting.html).
Change-Id: Ice608f77aa96bfbcadfff34991c4a1b6d93125b6
(cherry picked from commit eaa6329aba67c2577fdca7d3ddf230611e82f9f7)
diff --git a/apps/mcast/cli/BUILD b/apps/mcast/cli/BUILD
index 9a9d616..553eb5b 100644
--- a/apps/mcast/cli/BUILD
+++ b/apps/mcast/cli/BUILD
@@ -1,4 +1,4 @@
-COMPILE_DEPS = CORE_DEPS + CLI + REST + [
+COMPILE_DEPS = CORE_DEPS + JACKSON + CLI + REST + [
"//core/store/serializers:onos-core-serializers",
"//apps/mcast/api:onos-apps-mcast-api",
]
diff --git a/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastShowHostCommand.java b/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastShowHostCommand.java
index 7ab5da0..2261378 100644
--- a/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastShowHostCommand.java
+++ b/apps/mcast/cli/src/main/java/org/onosproject/mcast/cli/McastShowHostCommand.java
@@ -15,6 +15,8 @@
*/
package org.onosproject.mcast.cli;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.karaf.shell.api.action.Command;
import org.apache.karaf.shell.api.action.Completion;
import org.apache.karaf.shell.api.action.Option;
@@ -29,7 +31,6 @@
import java.util.Comparator;
import java.util.Map;
import java.util.Set;
-import java.util.stream.Collectors;
import static com.google.common.base.Strings.isNullOrEmpty;
@@ -41,7 +42,9 @@
public class McastShowHostCommand extends AbstractShellCommand {
// Format for group line
- private static final String FORMAT_MAPPING = "origin=%s, group=%s, source IP=%s, sources=%s, sinks=%s";
+ private static final String FORMAT_MAPPING = "origin=%s, group=%s, source IP=%s, sources=%s, sinks=%s\n";
+ private StringBuilder routesBuilder = new StringBuilder();
+ private ArrayNode routesNode = mapper().createArrayNode();
@Option(name = "-gAddr", aliases = "--groupAddress",
description = "IP Address of the multicast group",
@@ -65,41 +68,43 @@
.findAny().orElse(null);
// If it exists
if (mcastRoute != null) {
- printRoute(mcastService, mcastRoute);
+ prepareResult(mcastService, mcastRoute);
}
- return;
+ } else {
+ routes.stream()
+ .filter(mcastRoute -> mcastRoute.group().isIp4())
+ .sorted(Comparator.comparing(McastRoute::group))
+ .forEach(route -> {
+ prepareResult(mcastService, route);
+ });
+ routes.stream()
+ .filter(mcastRoute -> mcastRoute.group().isIp6())
+ .sorted(Comparator.comparing(McastRoute::group))
+ .forEach(route -> {
+ prepareResult(mcastService, route);
+ });
}
- // Filter ipv4
- Set<McastRoute> ipv4Routes = routes.stream()
- .filter(mcastRoute -> mcastRoute.group().isIp4())
- .collect(Collectors.toSet());
- // Print ipv4 first
- ipv4Routes.stream()
- .sorted(Comparator.comparing(McastRoute::group))
- .forEach(route -> {
- printRoute(mcastService, route);
- });
- // Filter ipv6
- Set<McastRoute> ipv6Routes = routes.stream()
- .filter(mcastRoute -> mcastRoute.group().isIp6())
- .collect(Collectors.toSet());
- // Then print ipv6
- ipv6Routes.stream()
- .sorted(Comparator.comparing(McastRoute::group))
- .forEach(route -> {
- printRoute(mcastService, route);
- });
+ if (outputJson()) {
+ print("%s", routesNode);
+ } else {
+ print("%s", routesBuilder.toString());
+ }
}
- private void printRoute(MulticastRouteService mcastService, McastRoute route) {
- Map<HostId, Set<ConnectPoint>> sinks = mcastService.routeData(route).sinks();
- Map<HostId, Set<ConnectPoint>> sources = mcastService.routeData(route).sources();
- String srcIp = "*";
- if (route.source().isPresent()) {
- srcIp = route.source().get().toString();
+ private void prepareResult(MulticastRouteService mcastService, McastRoute route) {
+ if (outputJson()) {
+ // McastHostRouteCodec is used to encode McastRoute
+ ObjectNode routeNode = jsonForEntity(route, McastRoute.class);
+ routesNode.add(routeNode);
+ } else {
+ Map<HostId, Set<ConnectPoint>> sinks = mcastService.routeData(route).sinks();
+ Map<HostId, Set<ConnectPoint>> sources = mcastService.routeData(route).sources();
+ String srcIp = "*";
+ if (route.source().isPresent()) {
+ srcIp = route.source().get().toString();
+ }
+ routesBuilder.append(String.format(FORMAT_MAPPING, route.type(), route.group(), srcIp, sources, sinks));
}
-
- print(FORMAT_MAPPING, route.type(), route.group(), srcIp, sources, sinks);
}
}
diff --git a/apps/route-service/app/src/main/java/org/onosproject/routeservice/cli/RoutesListCommand.java b/apps/route-service/app/src/main/java/org/onosproject/routeservice/cli/RoutesListCommand.java
index e2cb714..cb7ff17 100644
--- a/apps/route-service/app/src/main/java/org/onosproject/routeservice/cli/RoutesListCommand.java
+++ b/apps/route-service/app/src/main/java/org/onosproject/routeservice/cli/RoutesListCommand.java
@@ -23,6 +23,7 @@
import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.routeservice.ResolvedRoute;
+import org.onosproject.routeservice.Route;
import org.onosproject.routeservice.RouteInfo;
import org.onosproject.routeservice.RouteService;
import org.onosproject.routeservice.RouteTableId;
@@ -113,23 +114,17 @@
routes.stream()
.flatMap(ri -> ri.allRoutes().stream())
- .forEach(r -> result.add(json(mapper, r)));
-
- return result;
- }
-
- /**
- * Produces JSON object for a route.
- *
- * @param mapper the JSON object mapper to use
- * @param route the route with the data
- * @return JSON object for the route
- */
- private ObjectNode json(ObjectMapper mapper, ResolvedRoute route) {
- ObjectNode result = mapper.createObjectNode();
-
- result.put("prefix", route.prefix().toString());
- result.put("nextHop", route.nextHop().toString());
+ .forEach(r -> {
+ // use RouteCodec to encode the Route object inside ResolvedRoute
+ ObjectNode routeNode = jsonForEntity(r.route(), Route.class);
+ if (r.nextHopMac() != null) {
+ routeNode.put("nextHopMac", r.nextHopMac().toString());
+ }
+ if (r.nextHopVlan() != null) {
+ routeNode.put("nextHopVlan", r.nextHopVlan().toString());
+ }
+ result.add(routeNode);
+ });
return result;
}
diff --git a/apps/t3/app/src/main/java/org/onosproject/t3/api/DeviceNib.java b/apps/t3/app/src/main/java/org/onosproject/t3/api/DeviceNib.java
new file mode 100644
index 0000000..618724a
--- /dev/null
+++ b/apps/t3/app/src/main/java/org/onosproject/t3/api/DeviceNib.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.t3.api;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Represents Network Information Base (NIB) for devices
+ * and supports alternative functions to
+ * {@link org.onosproject.net.device.DeviceService} for offline data.
+ */
+public class DeviceNib {
+
+ private Map<Device, Set<Port>> devicePortMap;
+
+ // use the singleton helper to create the instance
+ protected DeviceNib() {
+ }
+
+ /**
+ * Sets a map of device : ports of the device.
+ *
+ * @param devicePortMap device-ports map
+ */
+ public void setDevicePortMap(Map<Device, Set<Port>> devicePortMap) {
+ this.devicePortMap = devicePortMap;
+ }
+
+ /**
+ * Returns the device-ports map.
+ *
+ * @return device-ports map
+ */
+ public Map<Device, Set<Port>> getDevicePortMap() {
+ return ImmutableMap.copyOf(devicePortMap);
+ }
+
+ /**
+ * Returns the device with the specified identifier.
+ *
+ * @param deviceId device identifier
+ * @return device or null if one with the given identifier is not known
+ */
+ public Device getDevice(DeviceId deviceId) {
+ return devicePortMap.keySet().stream()
+ .filter(device -> device.id().equals(deviceId))
+ .findFirst().orElse(null);
+ }
+
+ /**
+ * Returns the port with the specified connect point.
+ *
+ * @param cp connect point
+ * @return device port
+ */
+ public Port getPort(ConnectPoint cp) {
+ return devicePortMap.get(getDevice(cp.deviceId())).stream()
+ .filter(port -> port.number().equals(cp.port()))
+ .findFirst().orElse(null);
+ }
+
+ /**
+ * Returns the list of ports associated with the device.
+ *
+ * @param deviceId device identifier
+ * @return list of ports
+ */
+ public List<Port> getPorts(DeviceId deviceId) {
+ return ImmutableList.copyOf(devicePortMap.get(getDevice(deviceId)));
+ }
+
+ /**
+ * Indicates whether or not the device is presently online and available.
+ * Availability, unlike reachability, denotes whether ANY node in the
+ * cluster can discover that this device is in an operational state,
+ * this does not necessarily mean that there exists a node that can
+ * control this device.
+ *
+ * @param deviceId device identifier
+ * @return true if the device is available
+ */
+ public boolean isAvailable(DeviceId deviceId) {
+ Device device = getDevice(deviceId);
+ // TODO: may need an extra REST API to get availableDevices from DeviceService, not from device annotations
+ return device.annotations().value("available").equals("true") ? true : false;
+ }
+
+ /**
+ * Returns the singleton instance of devices NIB.
+ *
+ * @return instance of devices NIB
+ */
+ public static DeviceNib getInstance() {
+ return DeviceNib.SingletonHelper.INSTANCE;
+ }
+
+ private static class SingletonHelper {
+ private static final DeviceNib INSTANCE = new DeviceNib();
+ }
+
+}
diff --git a/apps/t3/app/src/main/java/org/onosproject/t3/api/DriverNib.java b/apps/t3/app/src/main/java/org/onosproject/t3/api/DriverNib.java
new file mode 100644
index 0000000..4c88a20
--- /dev/null
+++ b/apps/t3/app/src/main/java/org/onosproject/t3/api/DriverNib.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.t3.api;
+
+import com.google.common.collect.ImmutableMap;
+import org.onosproject.net.DeviceId;
+
+import java.util.Map;
+
+/**
+ * Represents Network Information Base (NIB) for drivers
+ * and supports alternative functions to
+ * {@link org.onosproject.net.driver.DriverService} for offline data.
+ */
+public class DriverNib {
+
+ private Map<DeviceId, String> deviceDriverMap;
+
+ // use the singleton helper to create the instance
+ protected DriverNib() {
+ }
+
+ /**
+ * Sets a map of device id : driver name.
+ *
+ * @param deviceDriverMap device-driver map
+ */
+ public void setDeviceDriverMap(Map<DeviceId, String> deviceDriverMap) {
+ this.deviceDriverMap = deviceDriverMap;
+ }
+
+ /**
+ * Returns the device-driver map.
+ *
+ * @return device-driver map
+ */
+ public Map<DeviceId, String> getDeviceDriverMap() {
+ return ImmutableMap.copyOf(deviceDriverMap);
+ }
+
+ /**
+ * Returns a driver name of the given device.
+ *
+ * @param deviceId the device id
+ * @return the driver name
+ */
+ public String getDriverName(DeviceId deviceId) {
+ return deviceDriverMap.get(deviceId);
+ }
+
+ /**
+ * Returns the singleton instance of drivers NIB.
+ *
+ * @return instance of drivers NIB
+ */
+ public static DriverNib getInstance() {
+ return DriverNib.SingletonHelper.INSTANCE;
+ }
+
+ private static class SingletonHelper {
+ private static final DriverNib INSTANCE = new DriverNib();
+ }
+
+}
diff --git a/apps/t3/app/src/main/java/org/onosproject/t3/api/EdgePortNib.java b/apps/t3/app/src/main/java/org/onosproject/t3/api/EdgePortNib.java
new file mode 100644
index 0000000..f24668f
--- /dev/null
+++ b/apps/t3/app/src/main/java/org/onosproject/t3/api/EdgePortNib.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.t3.api;
+
+import com.google.common.collect.ImmutableMap;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Represents Network Information Base (NIB) for edge ports
+ * and supports alternative functions to
+ * {@link org.onosproject.net.edge.EdgePortService} for offline data.
+ */
+public class EdgePortNib {
+
+ private Map<DeviceId, Set<ConnectPoint>> edgePorts;
+
+ // use the singleton helper to create the instance
+ protected EdgePortNib() {
+ }
+
+ /**
+ * Sets a map of device id : edge ports of the device.
+ *
+ * @param edgePorts device-edge ports map
+ */
+ public void setEdgePorts(Map<DeviceId, Set<ConnectPoint>> edgePorts) {
+ this.edgePorts = edgePorts;
+ }
+
+ /**
+ * Returns the device-edge ports map.
+ * @return device-edge ports map
+ */
+ public Map<DeviceId, Set<ConnectPoint>> getEdgePorts() {
+ return ImmutableMap.copyOf(edgePorts);
+ }
+
+ /**
+ * Indicates whether or not the specified connection point is an edge point.
+ *
+ * @param point connection point
+ * @return true if edge point
+ */
+ public boolean isEdgePoint(ConnectPoint point) {
+ Set<ConnectPoint> connectPoints = edgePorts.get(point.deviceId());
+ return connectPoints != null && connectPoints.contains(point);
+ }
+
+ /**
+ * Returns the singleton instance of edge ports NIB.
+ *
+ * @return instance of edge ports NIB
+ */
+ public static EdgePortNib getInstance() {
+ return EdgePortNib.SingletonHelper.INSTANCE;
+ }
+
+ private static class SingletonHelper {
+ private static final EdgePortNib INSTANCE = new EdgePortNib();
+ }
+
+}
diff --git a/apps/t3/app/src/main/java/org/onosproject/t3/api/FlowNib.java b/apps/t3/app/src/main/java/org/onosproject/t3/api/FlowNib.java
new file mode 100644
index 0000000..aecb57c
--- /dev/null
+++ b/apps/t3/app/src/main/java/org/onosproject/t3/api/FlowNib.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.t3.api;
+
+import com.google.common.collect.ImmutableSet;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.FlowEntry;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Represents Network Information Base (NIB) for flows
+ * and supports alternative functions to
+ * {@link org.onosproject.net.flow.FlowRuleService} for offline data.
+ */
+public class FlowNib {
+
+ // TODO with method optimization, store into subdivided structures at the first load
+ private Set<FlowEntry> flows;
+
+ // use the singleton helper to create the instance
+ protected FlowNib() {
+ }
+
+ /**
+ * Sets a set of flows.
+ *
+ * @param flows flow set
+ */
+ public void setFlows(Set<FlowEntry> flows) {
+ this.flows = flows;
+ }
+
+ /**
+ * Returns the set of flows.
+ *
+ * @return flow set
+ */
+ public Set<FlowEntry> getFlows() {
+ return ImmutableSet.copyOf(flows);
+ }
+
+ /**
+ * Returns a list of rules filtered by device id and flow state.
+ *
+ * @param deviceId the device id to lookup
+ * @param flowState the flow state to lookup
+ * @return collection of flow entries
+ */
+ public Iterable<FlowEntry> getFlowEntriesByState(DeviceId deviceId, FlowEntry.FlowEntryState flowState) {
+ Set<FlowEntry> flowsFiltered = flows.stream()
+ .filter(flow -> flow.state() == flowState
+ && flow.deviceId().equals(deviceId))
+ .collect(Collectors.toSet());
+ return flowsFiltered != null ? ImmutableSet.copyOf(flowsFiltered) : ImmutableSet.of();
+ }
+
+ /**
+ * Returns the singleton instance of flows NIB.
+ *
+ * @return instance of flows NIB
+ */
+ public static FlowNib getInstance() {
+ return SingletonHelper.INSTANCE;
+ }
+
+ private static class SingletonHelper {
+ private static final FlowNib INSTANCE = new FlowNib();
+ }
+
+}
diff --git a/apps/t3/app/src/main/java/org/onosproject/t3/api/GroupNib.java b/apps/t3/app/src/main/java/org/onosproject/t3/api/GroupNib.java
new file mode 100644
index 0000000..64d6575
--- /dev/null
+++ b/apps/t3/app/src/main/java/org/onosproject/t3/api/GroupNib.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.t3.api;
+
+import com.google.common.collect.ImmutableSet;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.group.Group;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Represents Network Information Base (NIB) for groups
+ * and supports alternative functions to
+ * {@link org.onosproject.net.group.GroupService} for offline data.
+ */
+public class GroupNib {
+
+ // TODO with method optimization, store into subdivided structures at the first load
+ private Set<Group> groups;
+
+ // use the singleton helper to create the instance
+ protected GroupNib() {
+ }
+
+ /**
+ * Sets a set of groups.
+ *
+ * @param groups group set
+ */
+ public void setGroups(Set<Group> groups) {
+ this.groups = groups;
+ }
+
+ /**
+ * Returns the set of groups.
+ *
+ * @return group set
+ */
+ public Set<Group> getGroups() {
+ return ImmutableSet.copyOf(groups);
+ }
+
+ /**
+ * Returns all groups associated with the given device.
+ *
+ * @param deviceId device ID to get groups for
+ * @return iterable of device's groups
+ */
+ public Iterable<Group> getGroups(DeviceId deviceId) {
+ Set<Group> groupsFiltered = groups.stream()
+ .filter(g -> g.deviceId().equals(deviceId))
+ .collect(Collectors.toSet());
+ return groupsFiltered != null ? ImmutableSet.copyOf(groupsFiltered) : ImmutableSet.of();
+ }
+
+ /**
+ * Returns the singleton instance of groups NIB.
+ *
+ * @return instance of groups NIB
+ */
+ public static GroupNib getInstance() {
+ return GroupNib.SingletonHelper.INSTANCE;
+ }
+
+ private static class SingletonHelper {
+ private static final GroupNib INSTANCE = new GroupNib();
+ }
+
+}
diff --git a/apps/t3/app/src/main/java/org/onosproject/t3/api/HostNib.java b/apps/t3/app/src/main/java/org/onosproject/t3/api/HostNib.java
new file mode 100644
index 0000000..5b5eab2
--- /dev/null
+++ b/apps/t3/app/src/main/java/org/onosproject/t3/api/HostNib.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.t3.api;
+
+import com.google.common.collect.ImmutableSet;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Represents Network Information Base (NIB) for hosts
+ * and supports alternative functions to
+ * {@link org.onosproject.net.host.HostService} for offline data.
+ */
+public class HostNib {
+
+ // TODO with method optimization, store into subdivided structures at the first load
+ private Set<Host> hosts;
+
+ // use the singleton helper to create the instance
+ protected HostNib() {
+ }
+
+ /**
+ * Sets a set of hosts.
+ *
+ * @param hosts host set
+ */
+ public void setHosts(Set<Host> hosts) {
+ this.hosts = hosts;
+ }
+
+ /**
+ * Returns the set of hosts.
+ *
+ * @return host set
+ */
+ public Set<Host> getHosts() {
+ return ImmutableSet.copyOf(hosts);
+ }
+
+ /**
+ * Returns the host with the specified identifier.
+ *
+ * @param hostId host identifier
+ * @return host or null if one with the given identifier is not known
+ */
+ public Host getHost(HostId hostId) {
+ return hosts.stream()
+ .filter(host -> host.id().equals(hostId))
+ .findFirst().orElse(null);
+ }
+
+ /**
+ * Returns the set of hosts whose most recent location is the specified
+ * connection point.
+ *
+ * @param connectPoint connection point
+ * @return set of hosts connected to the connection point
+ */
+ public Set<Host> getConnectedHosts(ConnectPoint connectPoint) {
+ // TODO extend this method to support matching on auxLocations as well
+ Set<Host> connectedHosts = hosts.stream()
+ .filter(host -> host.locations().contains(connectPoint))
+ .collect(Collectors.toSet());
+ return connectedHosts != null ? ImmutableSet.copyOf(connectedHosts) : ImmutableSet.of();
+ }
+
+ /**
+ * Returns the set of hosts that have the specified IP address.
+ *
+ * @param ip ip address
+ * @return set of hosts with the given IP
+ */
+ public Set<Host> getHostsByIp(IpAddress ip) {
+ Set<Host> hostsByIp = hosts.stream()
+ .filter(host -> host.ipAddresses().contains(ip))
+ .collect(Collectors.toSet());
+ return hostsByIp != null ? ImmutableSet.copyOf(hostsByIp) : ImmutableSet.of();
+ }
+
+ /**
+ * Returns the set of hosts that have the specified MAC address.
+ *
+ * @param mac mac address
+ * @return set of hosts with the given mac
+ */
+ public Set<Host> getHostsByMac(MacAddress mac) {
+ Set<Host> hostsByMac = hosts.stream()
+ .filter(host -> host.mac().equals(mac))
+ .collect(Collectors.toSet());
+ return hostsByMac != null ? ImmutableSet.copyOf(hostsByMac) : ImmutableSet.of();
+ }
+
+ /**
+ * Returns the singleton instance of hosts NIB.
+ *
+ * @return instance of hosts NIB
+ */
+ public static HostNib getInstance() {
+ return HostNib.SingletonHelper.INSTANCE;
+ }
+
+ private static class SingletonHelper {
+ private static final HostNib INSTANCE = new HostNib();
+ }
+
+}
diff --git a/apps/t3/app/src/main/java/org/onosproject/t3/api/LinkNib.java b/apps/t3/app/src/main/java/org/onosproject/t3/api/LinkNib.java
new file mode 100644
index 0000000..02acb54
--- /dev/null
+++ b/apps/t3/app/src/main/java/org/onosproject/t3/api/LinkNib.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.t3.api;
+
+import com.google.common.collect.ImmutableSet;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Link;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Represents Network Information Base (NIB) for links
+ * and supports alternative functions to
+ * {@link org.onosproject.net.link.LinkService} for offline data.
+ */
+public class LinkNib {
+
+ // TODO with method optimization, store into subdivided structures at the first load
+ private Set<Link> links;
+
+ // use the singleton helper to create the instance
+ protected LinkNib() {
+ }
+
+ /**
+ * Sets a set of links.
+ *
+ * @param links link set
+ */
+ public void setLinks(Set<Link> links) {
+ this.links = links;
+ }
+
+ /**
+ * Returns the set of links.
+ *
+ * @return link set
+ */
+ public Set<Link> getLinks() {
+ return ImmutableSet.copyOf(links);
+ }
+
+ /**
+ * Returns set of all infrastructure links leading from the specified
+ * connection point.
+ *
+ * @param connectPoint connection point
+ * @return set of device egress links
+ */
+ public Set<Link> getEgressLinks(ConnectPoint connectPoint) {
+ Set<Link> egressLinks = links.stream()
+ .filter(link -> connectPoint.equals(link.src()))
+ .collect(Collectors.toSet());
+ return egressLinks != null ? ImmutableSet.copyOf(egressLinks) : ImmutableSet.of();
+ }
+
+ /**
+ * Returns the singleton instance of links NIB.
+ *
+ * @return instance of links NIB
+ */
+ public static LinkNib getInstance() {
+ return LinkNib.SingletonHelper.INSTANCE;
+ }
+
+ private static class SingletonHelper {
+ private static final LinkNib INSTANCE = new LinkNib();
+ }
+
+}
diff --git a/apps/t3/app/src/main/java/org/onosproject/t3/api/MastershipNib.java b/apps/t3/app/src/main/java/org/onosproject/t3/api/MastershipNib.java
new file mode 100644
index 0000000..5101d52
--- /dev/null
+++ b/apps/t3/app/src/main/java/org/onosproject/t3/api/MastershipNib.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.t3.api;
+
+import com.google.common.collect.ImmutableMap;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.net.DeviceId;
+
+import java.util.Map;
+
+/**
+ * Represents Network Information Base (NIB) for mastership
+ * and supports alternative functions to
+ * {@link org.onosproject.mastership.MastershipService} for offline data.
+ */
+public class MastershipNib {
+
+ private Map<DeviceId, NodeId> deviceMasterMap;
+
+ // use the singleton helper to create the instance
+ protected MastershipNib() {
+ }
+
+ /**
+ * Sets a map of device id : master node id.
+ *
+ * @param deviceMasterMap device-master map
+ */
+ public void setDeviceMasterMap(Map<DeviceId, NodeId> deviceMasterMap) {
+ this.deviceMasterMap = deviceMasterMap;
+ }
+
+ /**
+ * Returns the device-master map.
+ *
+ * @return device-master map
+ */
+ public Map<DeviceId, NodeId> getDeviceMasterMap() {
+ return ImmutableMap.copyOf(deviceMasterMap);
+ }
+
+ /**
+ * Returns the current master for a given device.
+ *
+ * @param deviceId the identifier of the device
+ * @return the ID of the master controller for the device
+ */
+ public NodeId getMasterFor(DeviceId deviceId) {
+ return deviceMasterMap.get(deviceId);
+ }
+
+ /**
+ * Returns the singleton instance of mastership NIB.
+ *
+ * @return instance of mastership NIB
+ */
+ public static MastershipNib getInstance() {
+ return MastershipNib.SingletonHelper.INSTANCE;
+ }
+
+ private static class SingletonHelper {
+ private static final MastershipNib INSTANCE = new MastershipNib();
+ }
+
+}
diff --git a/apps/t3/app/src/main/java/org/onosproject/t3/api/MulticastRouteNib.java b/apps/t3/app/src/main/java/org/onosproject/t3/api/MulticastRouteNib.java
new file mode 100644
index 0000000..b9d106d
--- /dev/null
+++ b/apps/t3/app/src/main/java/org/onosproject/t3/api/MulticastRouteNib.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.t3.api;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import org.onosproject.mcast.api.McastRoute;
+import org.onosproject.mcast.api.McastRouteData;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Represents Network Information Base (NIB) for multicast routes
+ * and supports alternative functions to
+ * {@link org.onosproject.mcast.api.MulticastRouteService} for offline data.
+ */
+public class MulticastRouteNib {
+
+ private Map<McastRoute, McastRouteData> mcastRoutes;
+
+ // use the singleton helper to create the instance
+ protected MulticastRouteNib() {
+ }
+
+ public void setMcastRoutes(Map<McastRoute, McastRouteData> mcastRoutes) {
+ this.mcastRoutes = mcastRoutes;
+ }
+
+ public Map<McastRoute, McastRouteData> getMcastRoutes() {
+ return ImmutableMap.copyOf(mcastRoutes);
+ }
+
+ /**
+ * Gets all Multicast routes in the system.
+ *
+ * @return set of Multicast routes
+ */
+ public Set<McastRoute> getRoutes() {
+ return ImmutableSet.copyOf(mcastRoutes.keySet());
+ }
+
+ /**
+ * Return the Multicast data for this route.
+ *
+ * @param route route
+ * @return the mcast route data
+ */
+ public McastRouteData routeData(McastRoute route) {
+ return mcastRoutes.get(route);
+ }
+
+ /**
+ * Returns the singleton instance of multicast routes NIB.
+ *
+ * @return instance of multicast routes NIB
+ */
+ public static MulticastRouteNib getInstance() {
+ return MulticastRouteNib.SingletonHelper.INSTANCE;
+ }
+
+ private static class SingletonHelper {
+ private static final MulticastRouteNib INSTANCE = new MulticastRouteNib();
+ }
+
+}
diff --git a/apps/t3/app/src/main/java/org/onosproject/t3/api/NetworkConfigNib.java b/apps/t3/app/src/main/java/org/onosproject/t3/api/NetworkConfigNib.java
new file mode 100644
index 0000000..9624fb7
--- /dev/null
+++ b/apps/t3/app/src/main/java/org/onosproject/t3/api/NetworkConfigNib.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.t3.api;
+
+import com.google.common.collect.ImmutableMap;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.config.basics.InterfaceConfig;
+import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
+import org.slf4j.Logger;
+
+import java.util.Map;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Represents Network Information Base (NIB) for network configurations
+ * and supports alternative functions to
+ * {@link org.onosproject.net.config.NetworkConfigService} for offline data.
+ */
+public class NetworkConfigNib {
+
+ private static final Logger log = getLogger(NetworkConfigNib.class);
+
+ // Map of str ConnectPoint : InterfaceConfig
+ private Map<String, Config> portConfigMap;
+ // Map of str DeviceId : SegmentRoutingDeviceConfig
+ private Map<String, Config> deviceConfigMap;
+
+ // use the singleton helper to create the instance
+ protected NetworkConfigNib() {
+ }
+
+ /**
+ * Sets a map of port : configuration to the port.
+ *
+ * @param portConfigMap port-config map
+ */
+ public void setPortConfigMap(Map<String, Config> portConfigMap) {
+ this.portConfigMap = portConfigMap;
+ }
+
+ /**
+ * Sets a map of device : configuration to the device.
+ *
+ * @param deviceConfigMap device-config map
+ */
+ public void setDeviceConfigMap(Map<String, Config> deviceConfigMap) {
+ this.deviceConfigMap = deviceConfigMap;
+ }
+
+ /**
+ * Returns the port-config map.
+ *
+ * @return port-config map
+ */
+ public Map<Object, Object> getPortConfigMap() {
+ return ImmutableMap.copyOf(portConfigMap);
+ }
+
+ /**
+ * Returns the device-config map.
+ *
+ * @return device-config map
+ */
+ public Map<Object, Object> getDeviceConfigMap() {
+ return ImmutableMap.copyOf(deviceConfigMap);
+ }
+
+ /**
+ * Returns the configuration for the specified subject and configuration
+ * class if one is available; null otherwise.
+ *
+ * @param subject configuration subject
+ * @param configClass configuration class
+ * @param <S> type of subject
+ * @param <C> type of configuration
+ * @return configuration or null if one is not available
+ */
+ public <S, C extends Config<S>> C getConfig(S subject, Class<C> configClass) {
+ if (configClass.equals(InterfaceConfig.class)) {
+ return (C) portConfigMap.get(subject.toString());
+ } else if (configClass.equals(SegmentRoutingDeviceConfig.class)) {
+ return (C) deviceConfigMap.get(subject.toString());
+ } else {
+ log.warn("Given configuration {} is not supported", configClass.toString());
+ return null;
+ }
+ }
+
+ /**
+ * Returns the singleton instance of multicast routes NIB.
+ *
+ * @return instance of multicast routes NIB
+ */
+ public static NetworkConfigNib getInstance() {
+ return NetworkConfigNib.SingletonHelper.INSTANCE;
+ }
+
+ private static class SingletonHelper {
+ private static final NetworkConfigNib INSTANCE = new NetworkConfigNib();
+ }
+
+}
diff --git a/apps/t3/app/src/main/java/org/onosproject/t3/api/RouteNib.java b/apps/t3/app/src/main/java/org/onosproject/t3/api/RouteNib.java
new file mode 100644
index 0000000..3edabd3
--- /dev/null
+++ b/apps/t3/app/src/main/java/org/onosproject/t3/api/RouteNib.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.t3.api;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.routeservice.ResolvedRoute;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Represents Network Information Base (NIB) for routes
+ * and supports alternative functions to
+ * {@link org.onosproject.routeservice.RouteService} for offline data.
+ */
+public class RouteNib {
+
+ // TODO with method optimization, store into subdivided structures at the first load
+ // unresolved Route is treated as ResolvedRoute with nextHopMac null
+ Set<ResolvedRoute> routes;
+
+ // use the singleton helper to create the instance
+ protected RouteNib() {
+ }
+
+ /**
+ * Sets a set of routes.
+ *
+ * @param routes route set
+ */
+ public void setRoutes(Set<ResolvedRoute> routes) {
+ this.routes = routes;
+ }
+
+ /**
+ * Returns the set of routes.
+ *
+ * @return route set
+ */
+ public Set<ResolvedRoute> getRoutes() {
+ return routes;
+ }
+
+ /**
+ * Performs a longest prefix lookup on the given IP address.
+ *
+ * @param ip IP address to look up
+ * @return most specific matching route, if one exists
+ */
+ public Optional<ResolvedRoute> longestPrefixLookup(IpAddress ip) {
+ return routes.stream()
+ .filter(r -> r.prefix().contains(ip))
+ .max(Comparator.comparing(r -> r.prefix().prefixLength()));
+ }
+
+ /**
+ * Returns all resolved routes stored for the given prefix, including the
+ * best selected route.
+ *
+ * @param prefix IP prefix to look up routes for
+ * @return all stored resolved routes for this prefix
+ */
+ public Collection<ResolvedRoute> getAllResolvedRoutes(IpPrefix prefix) {
+ return routes.stream()
+ .filter(r -> r.prefix().contains(prefix)
+ && r.nextHopMac() != null
+ && r.nextHopVlan() != null)
+ .collect(Collectors.toCollection(ArrayList::new));
+ }
+
+ /**
+ * Returns the singleton instance of multicast routes NIB.
+ *
+ * @return instance of multicast routes NIB
+ */
+ public static RouteNib getInstance() {
+ return RouteNib.SingletonHelper.INSTANCE;
+ }
+
+ private static class SingletonHelper {
+ private static final RouteNib INSTANCE = new RouteNib();
+ }
+
+}
diff --git a/apps/t3/app/src/main/java/org/onosproject/t3/api/TroubleshootService.java b/apps/t3/app/src/main/java/org/onosproject/t3/api/TroubleshootService.java
index a21baf5..9838e04 100644
--- a/apps/t3/app/src/main/java/org/onosproject/t3/api/TroubleshootService.java
+++ b/apps/t3/app/src/main/java/org/onosproject/t3/api/TroubleshootService.java
@@ -83,4 +83,17 @@
* @return a list of trace result
*/
List<Set<StaticPacketTrace>> getMulitcastTrace(VlanId vlanId);
+
+ /**
+ * Checks the availability of all NIBs of the manager.
+ *
+ * @return true if any NIB objects is unavailable
+ */
+ boolean checkNibsUnavailable();
+
+ /**
+ * Applies created NIBs to the manager.
+ */
+ void applyNibs();
+
}
diff --git a/apps/t3/app/src/main/java/org/onosproject/t3/cli/TroubleshootLoadFileCommand.java b/apps/t3/app/src/main/java/org/onosproject/t3/cli/TroubleshootLoadFileCommand.java
new file mode 100644
index 0000000..36c22d3
--- /dev/null
+++ b/apps/t3/app/src/main/java/org/onosproject/t3/cli/TroubleshootLoadFileCommand.java
@@ -0,0 +1,482 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.t3.cli;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.Lists;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.cli.PlaceholderCompleter;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.mcast.api.McastRoute;
+import org.onosproject.mcast.api.McastRouteData;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.Link;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.config.basics.InterfaceConfig;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.group.Group;
+import org.onosproject.routeservice.ResolvedRoute;
+import org.onosproject.routeservice.Route;
+import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
+import org.onosproject.t3.api.DeviceNib;
+import org.onosproject.t3.api.DriverNib;
+import org.onosproject.t3.api.EdgePortNib;
+import org.onosproject.t3.api.FlowNib;
+import org.onosproject.t3.api.GroupNib;
+import org.onosproject.t3.api.HostNib;
+import org.onosproject.t3.api.LinkNib;
+import org.onosproject.t3.api.MastershipNib;
+import org.onosproject.t3.api.MulticastRouteNib;
+import org.onosproject.t3.api.NetworkConfigNib;
+import org.onosproject.t3.api.RouteNib;
+import org.onosproject.t3.api.TroubleshootService;
+import org.slf4j.Logger;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Reads network states from JSON files of onos-diagnostics
+ * and sets them to corresponding Network Information Bases (NIBs).
+ */
+@Service
+@Command(scope = "onos", name = "t3-load-file",
+ description = "Command to create a snapshot (cache) of network states called Network Information Bases (NIBs) "
+ + "from onos-diagnostics dump files")
+public class TroubleshootLoadFileCommand extends AbstractShellCommand {
+
+ private static final Logger log = getLogger(TroubleshootLoadFileCommand.class);
+
+ public static final String ERROR_NULL = "Some NIBs are not ready to trace. " +
+ "Make sure t3-troubleshoot-load-file is done correctly";
+
+ @Argument(index = 0, name = "rootDir", description = "Specify the location of the directory " +
+ "where the dump files of a given instance have been extracted (e.g. /tmp/onos-diags/127.0.0.1)",
+ required = true, multiValued = false)
+ @Completion(PlaceholderCompleter.class)
+ String rootDir;
+
+ @Override
+ protected void doExecute() {
+
+ if (!rootDir.endsWith("/")) {
+ rootDir = rootDir + "/";
+ }
+ print("Load target files in: %s", rootDir);
+
+ try {
+ // fills each NIB (singleton) instance with the contents of the corresponding dump file
+ // the file names are defined in the onos-diagnostics script
+ createFlowNib(rootDir + "flows.json");
+ createGroupNib(rootDir + "groups.json");
+ createLinkNib(rootDir + "links.json");
+ createHostNib(rootDir + "hosts.json");
+ createDeviceNib(rootDir + "ports.json");
+ createDriverNib(rootDir + "device-drivers.json");
+ createMastershipNib(rootDir + "masters.json");
+ createEdgePortNib(rootDir + "edge-ports.json");
+ createRouteNib(rootDir + "routes.json");
+ createNetworkConfigNib(rootDir + "netcfg.json");
+ createMulticastRouteNib(rootDir + "mcast-host-show.json");
+ } catch (IOException e) {
+ print("Error in creating NIB: %s", e.getMessage());
+ log.error("Nib creation error", e);
+ return;
+ }
+
+ TroubleshootService service = get(TroubleshootService.class);
+ service.applyNibs();
+ if (service.checkNibsUnavailable()) {
+ print(ERROR_NULL);
+ return;
+ }
+ }
+
+ /**
+ * Fetches multicast route-related information and creates the multicast route NIB.
+ *
+ * @param fileName absolute path of JSON file to read
+ */
+ private void createMulticastRouteNib(String fileName) throws IOException {
+ InputStream stream = new FileInputStream(new File(fileName));
+ JsonNode jsonTree = mapper().readTree(stream);
+ Map<McastRoute, McastRouteData> mcastRoutes = new HashMap<>();
+
+ // note: the parsing structure depends on McastShowHostCommand
+ jsonTree.forEach(mcastRouteNode -> {
+ // use McastHostRouteCodec to decode McastRoute
+ McastRoute mcastRoute = codec(McastRoute.class)
+ .decode((ObjectNode) mcastRouteNode, this);
+ // create McastRouteData that stores sources and sinks of McastRoute
+ McastRouteData mcastRouteData = McastRouteData.empty();
+ if (mcastRouteNode.get("sources") != null) {
+ JsonNode sourcesNode = mcastRouteNode.get("sources");
+ sourcesNode.fields().forEachRemaining(sourceEntry -> {
+ HostId hostId = HostId.hostId(sourceEntry.getKey());
+ Set<ConnectPoint> sources = mapper().convertValue(
+ sourceEntry.getValue(), new TypeReference<Set<ConnectPoint>>() { });
+ mcastRouteData.addSources(hostId, sources);
+ });
+ }
+ if (mcastRouteNode.get("sinks") != null) {
+ JsonNode sinksNode = mcastRouteNode.get("sinks");
+ sinksNode.fields().forEachRemaining(sinkEntry -> {
+ HostId hostId = HostId.hostId(sinkEntry.getKey());
+ Set<ConnectPoint> sinks = mapper().convertValue(
+ sinkEntry.getValue(), new TypeReference<Set<ConnectPoint>>() { });
+ mcastRouteData.addSinks(hostId, sinks);
+ });
+ }
+ mcastRoutes.put(mcastRoute, mcastRouteData);
+ });
+
+ MulticastRouteNib mcastRouteNib = MulticastRouteNib.getInstance();
+ mcastRouteNib.setMcastRoutes(mcastRoutes);
+ print("the number of mcast routes: %d", mcastRouteNib.getMcastRoutes().size());
+
+ stream.close();
+ }
+
+ /**
+ * Fetches network config-related information and creates the network config NIB.
+ *
+ * @param fileName absolute path of JSON file to read
+ */
+ private void createNetworkConfigNib(String fileName) throws IOException {
+ InputStream stream = new FileInputStream(new File(fileName));
+ JsonNode jsonTree = mapper().readTree(stream);
+ Map<String, Config> portConfigMap = new HashMap<>();
+ Map<String, Config> deviceConfigMap = new HashMap<>();
+
+ // note: the parsing structure depends on NetworkConfigCommand
+ // TODO: improve the code quality by referring to target json
+ jsonTree.fields().forEachRemaining(e -> {
+ if (e.getKey().equals("ports")) {
+ JsonNode portConfigsNode = e.getValue();
+ portConfigsNode.fields().forEachRemaining(portConfigEntry -> {
+ String key = portConfigEntry.getKey();
+ InterfaceConfig config = new InterfaceConfig();
+ config.init(ConnectPoint.fromString(key), "interfaces",
+ portConfigEntry.getValue().get("interfaces"), mapper(), null);
+ portConfigMap.put(key, config);
+ });
+ } else if (e.getKey().equals("devices")) {
+ JsonNode deviceConfigsNode = e.getValue();
+ deviceConfigsNode.fields().forEachRemaining(deviceConfigEntry -> {
+ String key = deviceConfigEntry.getKey();
+ SegmentRoutingDeviceConfig config = new SegmentRoutingDeviceConfig();
+ config.init(DeviceId.deviceId(key), "segmentrouting",
+ deviceConfigEntry.getValue().get("segmentrouting"), mapper(), null);
+ deviceConfigMap.put(key, config);
+ });
+ } else {
+ log.warn("Given configuration subject {} is not supported", e.getKey());
+ }
+ });
+
+ NetworkConfigNib networkConfigNib = NetworkConfigNib.getInstance();
+ networkConfigNib.setPortConfigMap(portConfigMap);
+ networkConfigNib.setDeviceConfigMap(deviceConfigMap);
+ print("the number of network configurations: %d",
+ networkConfigNib.getPortConfigMap().size() + networkConfigNib.getDeviceConfigMap().size());
+
+ stream.close();
+ }
+
+ /**
+ * Fetches route-related information and creates the route NIB.
+ *
+ * @param fileName absolute path of JSON file to read
+ */
+ private void createRouteNib(String fileName) throws IOException {
+ InputStream stream = new FileInputStream(new File(fileName));
+ JsonNode jsonTree = mapper().readTree(stream);
+ Set<ResolvedRoute> routes = new HashSet<>();
+
+ // note: the parsing structure depends on RoutesListCommand
+ jsonTree.fields().forEachRemaining(e -> {
+ ArrayNode routesNode = (ArrayNode) e.getValue();
+ routesNode.forEach(routeNode -> {
+ Route route = codec(Route.class).decode((ObjectNode) routeNode, this);
+ // parse optional fields needed for ResolvedRoute
+ MacAddress nextHopMac = (null == routeNode.get("nextHopMac")) ?
+ null : MacAddress.valueOf(routeNode.get("nextHopMac").asText());
+ VlanId nextHopVlan = (null == routeNode.get("nextHopVlan")) ?
+ null : VlanId.vlanId(routeNode.get("nextHopVlan").asText());
+ routes.add(new ResolvedRoute(route, nextHopMac, nextHopVlan));
+ });
+ });
+
+ RouteNib routeNib = RouteNib.getInstance();
+ routeNib.setRoutes(routes);
+ print("the number of routes: %d", routeNib.getRoutes().size());
+
+ stream.close();
+ }
+
+ /**
+ * Fetches edge port-related information and creates the edge port NIB.
+ *
+ * @param fileName absolute path of JSON file to read
+ */
+ private void createEdgePortNib(String fileName) throws IOException {
+ InputStream stream = new FileInputStream(new File(fileName));
+ JsonNode jsonTree = mapper().readTree(stream);
+ Map<DeviceId, Set<ConnectPoint>> edgePorts = new HashMap<>();
+
+ // note: the parsing structure depends on EdgePortsListCommand
+ jsonTree.forEach(jsonNode -> {
+ DeviceId deviceId = DeviceId.deviceId(jsonNode.fieldNames().next());
+ PortNumber portNumber = PortNumber.portNumber(
+ jsonNode.get(deviceId.toString()).asText());
+ if (!edgePorts.containsKey(deviceId)) {
+ edgePorts.put(deviceId, new HashSet<>());
+ }
+ edgePorts.get(deviceId).add(new ConnectPoint(deviceId, portNumber));
+ });
+
+ EdgePortNib edgePortNib = EdgePortNib.getInstance();
+ edgePortNib.setEdgePorts(edgePorts);
+ print("the number of edge ports: %d", edgePortNib.getEdgePorts().size());
+
+ stream.close();
+ }
+
+ /**
+ * Fetches mastership-related information and creates the mastership NIB.
+ *
+ * @param fileName absolute path of JSON file to read
+ */
+ private void createMastershipNib(String fileName) throws IOException {
+ InputStream stream = new FileInputStream(new File(fileName));
+ JsonNode jsonTree = mapper().readTree(stream);
+ Map<DeviceId, NodeId> deviceMasterMap = new HashMap<>();
+
+ // note: the parsing structure depends on MastersListCommand
+ jsonTree.forEach(jsonNode -> {
+ ArrayNode devicesNode = ((ArrayNode) jsonNode.get("devices"));
+ devicesNode.forEach(deviceNode -> {
+ // a device is connected to only one master node at a time
+ deviceMasterMap.put(
+ DeviceId.deviceId(deviceNode.asText()),
+ NodeId.nodeId(jsonNode.get("id").asText()));
+ });
+ });
+
+ MastershipNib mastershipNib = MastershipNib.getInstance();
+ mastershipNib.setDeviceMasterMap(deviceMasterMap);
+ print("the number of device-node mappings: %d", mastershipNib.getDeviceMasterMap().size());
+
+ stream.close();
+ }
+
+ /**
+ * Fetches driver-related information and creates the driver NIB.
+ *
+ * @param fileName absolute path of JSON file to read
+ */
+ private void createDriverNib(String fileName) throws IOException {
+ InputStream stream = new FileInputStream(new File(fileName));
+ JsonNode jsonTree = mapper().readTree(stream);
+ Map<DeviceId, String> deviceDriverMap = new HashMap<>();
+
+ // note: the parsing structure depends on DeviceDriversCommand
+ jsonTree.fields().forEachRemaining(e -> {
+ deviceDriverMap.put(DeviceId.deviceId(e.getKey()), e.getValue().asText());
+ });
+
+ DriverNib driverNib = DriverNib.getInstance();
+ driverNib.setDeviceDriverMap(deviceDriverMap);
+ print("the number of device-driver mappings: %d", deviceDriverMap.size());
+
+ stream.close();
+ }
+
+ /**
+ * Fetches device-related information and creates the device NIB.
+ *
+ * @param fileName absolute path of JSON file to read
+ */
+ private void createDeviceNib(String fileName) throws IOException {
+ InputStream stream = new FileInputStream(new File(fileName));
+ JsonNode jsonTree = mapper().readTree(stream);
+ Map<Device, Set<Port>> devicePortMap = new HashMap<>();
+
+ // note: the parsing structure depends on DevicePortsListCommand
+ jsonTree.forEach(jsonNode -> {
+ Device device = codec(Device.class).decode(
+ (ObjectNode) jsonNode.get("device"), this);
+ Set<Port> ports = new HashSet<>(codec(Port.class).decode(
+ (ArrayNode) jsonNode.get("ports"), this));
+ devicePortMap.put(device, ports);
+ });
+
+ DeviceNib deviceNib = DeviceNib.getInstance();
+ deviceNib.setDevicePortMap(devicePortMap);
+ print("the number of devices: %d", deviceNib.getDevicePortMap().size());
+
+ stream.close();
+ }
+
+ /**
+ * Fetches host-related information and creates the host NIB.
+ *
+ * @param fileName absolute path of JSON file to read
+ */
+ private void createHostNib(String fileName) throws IOException {
+ InputStream stream = new FileInputStream(new File(fileName));
+ JsonNode jsonTree = mapper().readTree(stream);
+ Set<Host> hosts = new HashSet<>();
+
+ // note: the parsing structure depends on HostsListCommand
+ hosts.addAll(codec(Host.class).decode((ArrayNode) jsonTree, this));
+
+ HostNib hostNib = HostNib.getInstance();
+ hostNib.setHosts(hosts);
+ print("the number of hosts: %d", hostNib.getHosts().size());
+
+ stream.close();
+ }
+
+ /**
+ * Fetches link-related information and creates the link NIB.
+ *
+ * @param fileName absolute path of JSON file to read
+ */
+ private void createLinkNib(String fileName) throws IOException {
+ InputStream stream = new FileInputStream(new File(fileName));
+ JsonNode jsonTree = mapper().readTree(stream);
+ Set<Link> links = new HashSet<>();
+
+ // note: the parsing structure depends on LinksListCommand
+ links.addAll(codec(Link.class).decode((ArrayNode) jsonTree, this));
+
+ LinkNib linkNib = LinkNib.getInstance();
+ linkNib.setLinks(links);
+ print("the number of links: %d", linkNib.getLinks().size());
+
+ stream.close();
+ }
+
+ /**
+ * Fetches group-related information and creates the group NIB.
+ *
+ * @param fileName absolute path of JSON file to read
+ */
+ private void createGroupNib(String fileName) throws IOException {
+ InputStream stream = new FileInputStream(new File(fileName));
+ JsonNode jsonTree = mapper().readTree(stream);
+ Set<Group> groups = new HashSet<>();
+
+ // note: the parsing structure depends on GroupsListCommand
+ groups.addAll(codec(Group.class).decode((ArrayNode) jsonTree, this));
+
+ GroupNib groupNib = GroupNib.getInstance();
+ groupNib.setGroups(groups);
+ print("the number of groups: %d", groupNib.getGroups().size());
+
+ stream.close();
+ }
+
+ /**
+ * Fetches flow-related information and creates the flow NIB.
+ *
+ * @param fileName absolute path of JSON file to read
+ */
+ private void createFlowNib(String fileName) throws IOException {
+ InputStream stream = new FileInputStream(new File(fileName));
+ JsonNode jsonTree = mapper().readTree(stream);
+ Set<FlowEntry> flows = new HashSet<>();
+
+ List<ObjectNode> flowNodeList = new ArrayList<>();
+ jsonTree.forEach(jsonNode -> {
+ ArrayNode flowArrayNode = (ArrayNode) jsonNode.get("flows");
+ Lists.newArrayList(flowArrayNode.iterator())
+ .forEach(flowNode -> flowNodeList.add((ObjectNode) flowNode));
+ });
+
+ // TODO: future plan for the new APIs of the flow rule service that returns raw flows or normalized flows
+ flowNodeList.forEach(flowNode -> {
+ FlowEntry flow;
+ try {
+ flow = codec(FlowEntry.class).decode(flowNode, this);
+ } catch (IllegalArgumentException e) {
+ log.warn("T3 in offline mode ignores reading extension fields of this flow to avoid decoding error");
+ ObjectNode extensionRemoved = removeExtension(flowNode);
+ flow = codec(FlowEntry.class).decode(extensionRemoved, this);
+ }
+ flows.add(flow);
+ });
+
+ FlowNib flowNib = FlowNib.getInstance();
+ flowNib.setFlows(flows);
+ print("the number of flows: %d", flowNib.getFlows().size());
+
+ stream.close();
+ }
+
+ /**
+ * Remove JSON nodes for extension instructions of a flow.
+ * This effectively allows T3 in offline mode to ignore extension fields of flows to avoid "device not found" error.
+ * See decodeExtension() in {@link org.onosproject.codec.impl.DecodeInstructionCodecHelper}.
+ *
+ * @param flowNode the json node representing a flow
+ * @return json node with removed extensions
+ */
+ private ObjectNode removeExtension(ObjectNode flowNode) {
+
+ // TODO: decoding extension instructions of offline (dumped) flows is not supported by T3 for now
+ ArrayNode extensionRemoved = mapper().createArrayNode();
+ ArrayNode instructionArrayNode = (ArrayNode) flowNode.get("treatment").get("instructions");
+ instructionArrayNode.forEach(instrNode -> {
+ String instrType = instrNode.get("type").asText();
+ if (!instrType.equals(Instruction.Type.EXTENSION.name())) {
+ extensionRemoved.add(instrNode);
+ }
+ });
+ ((ObjectNode) flowNode.get("treatment")).replace("instructions", extensionRemoved);
+
+ return flowNode;
+ }
+
+}
\ No newline at end of file
diff --git a/apps/t3/app/src/main/java/org/onosproject/t3/cli/TroubleshootMcastCommand.java b/apps/t3/app/src/main/java/org/onosproject/t3/cli/TroubleshootMcastCommand.java
index 325691e..3df110f 100644
--- a/apps/t3/app/src/main/java/org/onosproject/t3/cli/TroubleshootMcastCommand.java
+++ b/apps/t3/app/src/main/java/org/onosproject/t3/cli/TroubleshootMcastCommand.java
@@ -18,12 +18,14 @@
import org.apache.commons.lang.StringUtils;
import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
import org.apache.karaf.shell.api.action.Option;
import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.onlab.packet.EthType;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.VlanId;
import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.cli.PlaceholderCompleter;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.criteria.Criterion;
@@ -45,23 +47,31 @@
description = "Traces all the mcast routes present in the system")
public class TroubleshootMcastCommand extends AbstractShellCommand {
-
@Option(name = "-v", aliases = "--verbose", description = "Outputs trace for each mcast route")
+ @Completion(PlaceholderCompleter.class)
private boolean verbosity1 = false;
@Option(name = "-vv", aliases = "--veryverbose", description = "Outputs middle level details of every trace")
+ @Completion(PlaceholderCompleter.class)
private boolean verbosity2 = false;
@Option(name = "-vvv", aliases = "--veryveryverbose", description = "Outputs complete details of every trace")
+ @Completion(PlaceholderCompleter.class)
private boolean verbosity3 = false;
@Option(name = "-vid", aliases = "--vlanId", description = "Vlan of incoming packet", valueToShowInHelp = "None")
+ @Completion(PlaceholderCompleter.class)
String vlan = "None";
@Override
protected void doExecute() {
TroubleshootService service = get(TroubleshootService.class);
+ if (service.checkNibsUnavailable()) {
+ print(TroubleshootLoadFileCommand.ERROR_NULL);
+ return;
+ }
+
print("Tracing all Multicast routes in the System");
//Create the generator for the list of traces.
diff --git a/apps/t3/app/src/main/java/org/onosproject/t3/cli/TroubleshootPingAllCommand.java b/apps/t3/app/src/main/java/org/onosproject/t3/cli/TroubleshootPingAllCommand.java
index 93e843a..3e7003f 100644
--- a/apps/t3/app/src/main/java/org/onosproject/t3/cli/TroubleshootPingAllCommand.java
+++ b/apps/t3/app/src/main/java/org/onosproject/t3/cli/TroubleshootPingAllCommand.java
@@ -23,6 +23,7 @@
import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.onlab.packet.IpAddress;
import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.cli.PlaceholderCompleter;
import org.onosproject.cli.net.EthTypeCompleter;
import org.onosproject.net.Host;
import org.onosproject.net.flow.criteria.Criterion;
@@ -54,17 +55,24 @@
String ethType = "ipv4";
@Option(name = "-v", aliases = "--verbose", description = "Outputs trace for each host to host combination")
+ @Completion(PlaceholderCompleter.class)
private boolean verbosity1 = false;
@Option(name = "-vv", aliases = "--veryverbose", description = "Outputs details of every trace")
+ @Completion(PlaceholderCompleter.class)
private boolean verbosity2 = false;
@Option(name = "-d", aliases = "--delay", description = "delay between host to host trace display")
+ @Completion(PlaceholderCompleter.class)
private long delay = 0;
@Override
protected void doExecute() {
TroubleshootService service = get(TroubleshootService.class);
+ if (service.checkNibsUnavailable()) {
+ print(TroubleshootLoadFileCommand.ERROR_NULL);
+ return;
+ }
EtherType type = EtherType.valueOf(ethType.toUpperCase());
diff --git a/apps/t3/app/src/main/java/org/onosproject/t3/cli/TroubleshootSimpleTraceCommand.java b/apps/t3/app/src/main/java/org/onosproject/t3/cli/TroubleshootSimpleTraceCommand.java
index 7b18913..7a5ecc7 100644
--- a/apps/t3/app/src/main/java/org/onosproject/t3/cli/TroubleshootSimpleTraceCommand.java
+++ b/apps/t3/app/src/main/java/org/onosproject/t3/cli/TroubleshootSimpleTraceCommand.java
@@ -22,6 +22,7 @@
import org.apache.karaf.shell.api.action.Option;
import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.cli.PlaceholderCompleter;
import org.onosproject.cli.net.EthTypeCompleter;
import org.onosproject.cli.net.HostIdCompleter;
import org.onosproject.net.HostId;
@@ -53,9 +54,11 @@
String dstHost = null;
@Option(name = "-v", aliases = "--verbose", description = "Outputs complete path")
+ @Completion(PlaceholderCompleter.class)
private boolean verbosity1 = false;
@Option(name = "-vv", aliases = "--veryverbose", description = "Outputs flows and groups for every device")
+ @Completion(PlaceholderCompleter.class)
private boolean verbosity2 = false;
@Option(name = "-et", aliases = "--ethType", description = "ETH Type", valueToShowInHelp = "ipv4")
@@ -65,6 +68,14 @@
@Override
protected void doExecute() {
TroubleshootService service = get(TroubleshootService.class);
+ if (service.checkNibsUnavailable()) {
+ print(TroubleshootLoadFileCommand.ERROR_NULL);
+ return;
+ }
+ if (srcHost.equals(dstHost)) {
+ print("Source and destination are same. Use different hosts");
+ return;
+ }
EtherType type = EtherType.valueOf(ethType.toUpperCase());
diff --git a/apps/t3/app/src/main/java/org/onosproject/t3/cli/TroubleshootTraceCommand.java b/apps/t3/app/src/main/java/org/onosproject/t3/cli/TroubleshootTraceCommand.java
index ed11cbe..5da3f8c 100644
--- a/apps/t3/app/src/main/java/org/onosproject/t3/cli/TroubleshootTraceCommand.java
+++ b/apps/t3/app/src/main/java/org/onosproject/t3/cli/TroubleshootTraceCommand.java
@@ -18,6 +18,7 @@
import com.google.common.base.Preconditions;
import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
import org.apache.karaf.shell.api.action.Option;
import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.onlab.packet.IpAddress;
@@ -26,6 +27,10 @@
import org.onlab.packet.TpPort;
import org.onlab.packet.VlanId;
import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.cli.PlaceholderCompleter;
+import org.onosproject.cli.net.ConnectPointCompleter;
+import org.onosproject.cli.net.EthTypeCompleter;
+import org.onosproject.cli.net.IpProtocolCompleter;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
@@ -56,56 +61,77 @@
private static final String CONTROLLER = "CONTROLLER";
@Option(name = "-v", aliases = "--verbose", description = "Outputs complete path")
+ @Completion(PlaceholderCompleter.class)
private boolean verbosity1 = false;
@Option(name = "-vv", aliases = "--veryverbose", description = "Outputs flows and groups for every device")
+ @Completion(PlaceholderCompleter.class)
private boolean verbosity2 = false;
@Option(name = "-s", aliases = "--srcIp", description = "Source IP")
+ @Completion(PlaceholderCompleter.class)
String srcIp = null;
@Option(name = "-sp", aliases = "--srcPort", description = "Source Port", required = true)
+ @Completion(ConnectPointCompleter.class)
String srcPort = null;
@Option(name = "-sm", aliases = "--srcMac", description = "Source MAC")
+ @Completion(PlaceholderCompleter.class)
String srcMac = null;
@Option(name = "-et", aliases = "--ethType", description = "ETH Type", valueToShowInHelp = "ipv4")
+ @Completion(EthTypeCompleter.class)
String ethType = "ipv4";
@Option(name = "-stp", aliases = "--srcTcpPort", description = "Source TCP Port")
+ @Completion(PlaceholderCompleter.class)
String srcTcpPort = null;
@Option(name = "-d", aliases = "--dstIp", description = "Destination IP")
+ @Completion(PlaceholderCompleter.class)
String dstIp = null;
@Option(name = "-dm", aliases = "--dstMac", description = "Destination MAC")
+ @Completion(PlaceholderCompleter.class)
String dstMac = null;
@Option(name = "-dtp", aliases = "--dstTcpPort", description = "destination TCP Port")
+ @Completion(PlaceholderCompleter.class)
String dstTcpPort = null;
@Option(name = "-vid", aliases = "--vlanId", description = "Vlan of incoming packet", valueToShowInHelp = "None")
+ @Completion(PlaceholderCompleter.class)
String vlan = "None";
@Option(name = "-ml", aliases = "--mplsLabel", description = "Mpls label of incoming packet")
+ @Completion(PlaceholderCompleter.class)
String mplsLabel = null;
@Option(name = "-mb", aliases = "--mplsBos", description = "MPLS BOS")
+ @Completion(PlaceholderCompleter.class)
String mplsBos = null;
@Option(name = "-ipp", aliases = "--ipProto", description = "IP Proto")
+ @Completion(IpProtocolCompleter.class)
String ipProto = null;
@Option(name = "-udps", aliases = "--udpSrc", description = "UDP Source")
+ @Completion(PlaceholderCompleter.class)
String udpSrc = null;
@Option(name = "-udpd", aliases = "--udpDst", description = "UDP Destination")
+ @Completion(PlaceholderCompleter.class)
String udpDst = null;
@Override
protected void doExecute() {
TroubleshootService service = get(TroubleshootService.class);
+ if (service.checkNibsUnavailable()) {
+ print(TroubleshootLoadFileCommand.ERROR_NULL);
+ return;
+ }
+
String[] cpInfo = srcPort.split("/");
Preconditions.checkArgument(cpInfo.length == 2, "wrong format of source port");
ConnectPoint cp;
diff --git a/apps/t3/app/src/main/java/org/onosproject/t3/impl/McastGenerator.java b/apps/t3/app/src/main/java/org/onosproject/t3/impl/McastGenerator.java
index e93af15..7520843 100644
--- a/apps/t3/app/src/main/java/org/onosproject/t3/impl/McastGenerator.java
+++ b/apps/t3/app/src/main/java/org/onosproject/t3/impl/McastGenerator.java
@@ -22,9 +22,9 @@
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.mcast.api.McastRouteData;
-import org.onosproject.mcast.api.MulticastRouteService;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.t3.api.MulticastRouteNib;
import org.onosproject.t3.api.StaticPacketTrace;
import org.slf4j.Logger;
@@ -44,27 +44,27 @@
private static final String GENERATOR_ERROR =
"Generator for mcast route trace has benn interrupted. The trace result may be incomplete.";
- private final MulticastRouteService mcastService;
+ private final MulticastRouteNib mcastRouteNib;
private final TroubleshootManager manager;
private final VlanId vlanId;
/**
* Creates a generator for obtaining traces of all configured multicast routes.
*
- * @param service the host service
+ * @param mcastRouteNib the multicast route NIB
* @param manager the troubleshoot manager issuing the request.
* @param vlanId the multicast configured VlanId.
*/
- McastGenerator(MulticastRouteService service, TroubleshootManager manager, VlanId vlanId) {
- this.mcastService = service;
+ McastGenerator(MulticastRouteNib mcastRouteNib, TroubleshootManager manager, VlanId vlanId) {
+ this.mcastRouteNib = mcastRouteNib;
this.manager = manager;
this.vlanId = vlanId;
}
@Override
protected void run() {
- mcastService.getRoutes().forEach(route -> {
- McastRouteData routeData = mcastService.routeData(route);
+ mcastRouteNib.getRoutes().forEach(route -> {
+ McastRouteData routeData = mcastRouteNib.routeData(route);
IpAddress group = route.group();
routeData.sources().forEach((host, sources) -> {
sources.forEach(source -> {
diff --git a/apps/t3/app/src/main/java/org/onosproject/t3/impl/PingAllGenerator.java b/apps/t3/app/src/main/java/org/onosproject/t3/impl/PingAllGenerator.java
index bf4d4b4..e935fad 100644
--- a/apps/t3/app/src/main/java/org/onosproject/t3/impl/PingAllGenerator.java
+++ b/apps/t3/app/src/main/java/org/onosproject/t3/impl/PingAllGenerator.java
@@ -19,7 +19,7 @@
import com.google.common.collect.Sets;
import org.onlab.packet.EthType;
import org.onlab.packet.IpAddress;
-import org.onosproject.net.host.HostService;
+import org.onosproject.t3.api.HostNib;
import org.onosproject.t3.api.StaticPacketTrace;
import org.slf4j.Logger;
@@ -36,30 +36,30 @@
private static final Logger log = getLogger(PingAllGenerator.class);
private final EthType.EtherType etherType;
- private final HostService hostService;
+ private final HostNib hostNib;
private final TroubleshootManager manager;
/**
* Creates a generator for obtaining traces of pings between all the hosts in the network.
*
* @param etherType the type of traffic we are tracing.
- * @param service the host service
+ * @param hostNib the host NIB
* @param manager the troubleshoot manager issuing the request.
*/
- PingAllGenerator(EthType.EtherType etherType, HostService service, TroubleshootManager manager) {
+ PingAllGenerator(EthType.EtherType etherType, HostNib hostNib, TroubleshootManager manager) {
this.etherType = etherType;
- this.hostService = service;
+ this.hostNib = hostNib;
this.manager = manager;
}
@Override
protected void run() throws InterruptedException {
- hostService.getHosts().forEach(host -> {
+ hostNib.getHosts().forEach(host -> {
List<IpAddress> ipAddresses = manager.getIpAddresses(host, etherType, false);
if (ipAddresses.size() > 0) {
//check if the host has only local IPs of that ETH type
boolean onlyLocalSrc = ipAddresses.size() == 1 && ipAddresses.get(0).isLinkLocal();
- hostService.getHosts().forEach(hostToPing -> {
+ hostNib.getHosts().forEach(hostToPing -> {
List<IpAddress> ipAddressesToPing = manager.getIpAddresses(hostToPing, etherType, false);
//check if the other host has only local IPs of that ETH type
boolean onlyLocalDst = ipAddressesToPing.size() == 1 && ipAddressesToPing.get(0).isLinkLocal();
diff --git a/apps/t3/app/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java b/apps/t3/app/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java
index 51332da..b1359bc 100644
--- a/apps/t3/app/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java
+++ b/apps/t3/app/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java
@@ -25,8 +25,6 @@
import org.onlab.packet.IpAddress;
import org.onlab.packet.VlanId;
import org.onosproject.cluster.NodeId;
-import org.onosproject.mastership.MastershipService;
-import org.onosproject.mcast.api.MulticastRouteService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
@@ -35,15 +33,10 @@
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.config.ConfigException;
-import org.onosproject.net.config.NetworkConfigService;
import org.onosproject.net.config.basics.InterfaceConfig;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.driver.DriverService;
-import org.onosproject.net.edge.EdgePortService;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowRule;
-import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.flow.IndexTableId;
import org.onosproject.net.flow.TableId;
import org.onosproject.net.flow.TrafficSelector;
@@ -59,20 +52,25 @@
import org.onosproject.net.flow.instructions.L2ModificationInstruction;
import org.onosproject.net.group.Group;
import org.onosproject.net.group.GroupBucket;
-import org.onosproject.net.group.GroupService;
-import org.onosproject.net.host.HostService;
import org.onosproject.net.host.InterfaceIpAddress;
import org.onosproject.net.intf.Interface;
-import org.onosproject.net.link.LinkService;
import org.onosproject.routeservice.ResolvedRoute;
-import org.onosproject.routeservice.RouteService;
import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
+import org.onosproject.t3.api.DeviceNib;
+import org.onosproject.t3.api.DriverNib;
+import org.onosproject.t3.api.EdgePortNib;
+import org.onosproject.t3.api.FlowNib;
+import org.onosproject.t3.api.GroupNib;
import org.onosproject.t3.api.GroupsInDevice;
+import org.onosproject.t3.api.HostNib;
+import org.onosproject.t3.api.LinkNib;
+import org.onosproject.t3.api.MastershipNib;
+import org.onosproject.t3.api.MulticastRouteNib;
+import org.onosproject.t3.api.NetworkConfigNib;
+import org.onosproject.t3.api.RouteNib;
import org.onosproject.t3.api.StaticPacketTrace;
import org.onosproject.t3.api.TroubleshootService;
import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.Reference;
-import org.osgi.service.component.annotations.ReferenceCardinality;
import org.slf4j.Logger;
import java.net.UnknownHostException;
@@ -85,6 +83,7 @@
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import static org.onlab.packet.EthType.EtherType;
@@ -109,48 +108,50 @@
static final String PACKET_TO_CONTROLLER = "Packet goes to the controller";
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- protected FlowRuleService flowRuleService;
+ // uses a snapshot (cache) of NIBs instead of interacting with ONOS core in runtime
+ protected FlowNib flowNib;
+ protected GroupNib groupNib;
+ protected LinkNib linkNib;
+ protected HostNib hostNib;
+ protected DeviceNib deviceNib;
+ protected DriverNib driverNib;
+ protected MastershipNib mastershipNib;
+ protected EdgePortNib edgePortNib;
+ protected RouteNib routeNib;
+ protected NetworkConfigNib networkConfigNib;
+ protected MulticastRouteNib mcastRouteNib;
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- protected GroupService groupService;
+ @Override
+ public boolean checkNibsUnavailable() {
+ return Stream.of(flowNib, groupNib, linkNib, hostNib, deviceNib, driverNib,
+ mastershipNib, edgePortNib, routeNib, networkConfigNib, mcastRouteNib)
+ .anyMatch(x -> x == null);
+ }
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- protected LinkService linkService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- protected HostService hostService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- protected DriverService driverService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- protected DeviceService deviceService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- protected MastershipService mastershipService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- protected NetworkConfigService networkConfigService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- protected EdgePortService edgePortService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- protected RouteService routeService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY)
- protected MulticastRouteService mcastService;
+ @Override
+ public void applyNibs() {
+ flowNib = FlowNib.getInstance();
+ groupNib = GroupNib.getInstance();
+ linkNib = LinkNib.getInstance();
+ hostNib = HostNib.getInstance();
+ deviceNib = DeviceNib.getInstance();
+ driverNib = DriverNib.getInstance();
+ mastershipNib = MastershipNib.getInstance();
+ edgePortNib = EdgePortNib.getInstance();
+ routeNib = RouteNib.getInstance();
+ networkConfigNib = NetworkConfigNib.getInstance();
+ mcastRouteNib = MulticastRouteNib.getInstance();
+ }
@Override
public List<StaticPacketTrace> pingAll(EtherType type) {
ImmutableList.Builder<StaticPacketTrace> tracesBuilder = ImmutableList.builder();
- hostService.getHosts().forEach(host -> {
+ hostNib.getHosts().forEach(host -> {
List<IpAddress> ipAddresses = getIpAddresses(host, type, false);
if (ipAddresses.size() > 0) {
//check if the host has only local IPs of that ETH type
boolean onlyLocalSrc = ipAddresses.size() == 1 && ipAddresses.get(0).isLinkLocal();
- hostService.getHosts().forEach(hostToPing -> {
+ hostNib.getHosts().forEach(hostToPing -> {
List<IpAddress> ipAddressesToPing = getIpAddresses(hostToPing, type, false);
//check if the other host has only local IPs of that ETH type
boolean onlyLocalDst = ipAddressesToPing.size() == 1 && ipAddressesToPing.get(0).isLinkLocal();
@@ -170,18 +171,18 @@
@Override
public Generator<Set<StaticPacketTrace>> pingAllGenerator(EtherType type) {
- return new PingAllGenerator(type, hostService, this);
+ return new PingAllGenerator(type, hostNib, this);
}
@Override
public Generator<Set<StaticPacketTrace>> traceMcast(VlanId vlanId) {
- return new McastGenerator(mcastService, this, vlanId);
+ return new McastGenerator(mcastRouteNib, this, vlanId);
}
@Override
public Set<StaticPacketTrace> trace(HostId sourceHost, HostId destinationHost, EtherType etherType) {
- Host source = hostService.getHost(sourceHost);
- Host destination = hostService.getHost(destinationHost);
+ Host source = hostNib.getHost(sourceHost);
+ Host destination = hostNib.getHost(destinationHost);
//Temporary trace to fail in case we don't have enough information or what is provided is incoherent
StaticPacketTrace failTrace = new StaticPacketTrace(null, null, Pair.of(source, destination));
@@ -243,7 +244,7 @@
}
//l3 unicast, we get the dst mac of the leaf the source is connected to from netcfg
- SegmentRoutingDeviceConfig segmentRoutingConfig = networkConfigService.getConfig(source.location()
+ SegmentRoutingDeviceConfig segmentRoutingConfig = networkConfigNib.getConfig(source.location()
.deviceId(), SegmentRoutingDeviceConfig.class);
if (segmentRoutingConfig != null) {
selectorBuilder.matchEthDst(segmentRoutingConfig.routerMac());
@@ -337,8 +338,8 @@
return false;
}
- InterfaceConfig interfaceCfgH1 = networkConfigService.getConfig(source.location(), InterfaceConfig.class);
- InterfaceConfig interfaceCfgH2 = networkConfigService.getConfig(destination.location(), InterfaceConfig.class);
+ InterfaceConfig interfaceCfgH1 = networkConfigNib.getConfig(source.location(), InterfaceConfig.class);
+ InterfaceConfig interfaceCfgH2 = networkConfigNib.getConfig(destination.location(), InterfaceConfig.class);
if (interfaceCfgH1 != null && interfaceCfgH2 != null) {
//following can be optimized but for clarity is left as is
@@ -376,7 +377,7 @@
public StaticPacketTrace trace(TrafficSelector packet, ConnectPoint in) {
log.info("Tracing packet {} coming in through {}", packet, in);
//device must exist in ONOS
- Preconditions.checkNotNull(deviceService.getDevice(in.deviceId()),
+ Preconditions.checkNotNull(deviceNib.getDevice(in.deviceId()),
"Device " + in.deviceId() + " must exist in ONOS");
StaticPacketTrace trace = new StaticPacketTrace(packet, in);
@@ -391,7 +392,7 @@
@Override
public List<Set<StaticPacketTrace>> getMulitcastTrace(VlanId vlanId) {
- Generator<Set<StaticPacketTrace>> gen = new McastGenerator(mcastService, this, vlanId);
+ Generator<Set<StaticPacketTrace>> gen = new McastGenerator(mcastRouteNib, this, vlanId);
List<Set<StaticPacketTrace>> multicastTraceList =
StreamSupport.stream(gen.spliterator(), false).collect(Collectors.toList());
return multicastTraceList;
@@ -440,7 +441,7 @@
log.debug("{}", outputPath.getFinalPacket());
//Hosts for the the given output
- Set<Host> hostsList = hostService.getConnectedHosts(cp);
+ Set<Host> hostsList = hostNib.getConnectedHosts(cp);
//Hosts queried from the original ip or mac
Set<Host> hosts = getHosts(trace);
@@ -465,12 +466,13 @@
} else if (cp.port().equals(PortNumber.CONTROLLER)) {
//Getting the master when the packet gets sent as packet in
- NodeId master = mastershipService.getMasterFor(cp.deviceId());
+ NodeId master = mastershipNib.getMasterFor(cp.deviceId());
+ // TODO if we don't need to print master node id, exclude mastership NIB which is used only here
trace.addResultMessage(PACKET_TO_CONTROLLER + " " + master.id());
computePath(completePath, trace, outputPath.getOutput());
handleVlanToController(outputPath, trace);
- } else if (linkService.getEgressLinks(cp).size() > 0) {
+ } else if (linkNib.getEgressLinks(cp).size() > 0) {
//TODO this can be optimized if we use a Tree structure for paths.
//if we already have outputs let's check if the one we are considering starts from one of the devices
@@ -502,7 +504,7 @@
//let's add the ouput for the input
completePath.add(cp);
//let's compute the links for the given output
- Set<Link> links = linkService.getEgressLinks(cp);
+ Set<Link> links = linkNib.getEgressLinks(cp);
log.debug("Egress Links {}", links);
//For each link we trace the corresponding device
for (Link link : links) {
@@ -517,7 +519,7 @@
//continue the trace along the path
getTrace(completePath, dst, trace, isDualHomed);
}
- } else if (edgePortService.isEdgePoint(outputPath.getOutput()) &&
+ } else if (edgePortNib.isEdgePoint(outputPath.getOutput()) &&
trace.getInitialPacket().getCriterion(Criterion.Type.ETH_DST) != null &&
((EthCriterion) trace.getInitialPacket().getCriterion(Criterion.Type.ETH_DST))
.mac().isMulticast()) {
@@ -528,7 +530,7 @@
if (!hasOtherOutput(in.deviceId(), trace, outputPath.getOutput())) {
return trace;
}
- } else if (deviceService.getPort(cp) != null && deviceService.getPort(cp).isEnabled()) {
+ } else if (deviceNib.getPort(cp) != null && deviceNib.getPort(cp).isEnabled()) {
EthTypeCriterion ethTypeCriterion = (EthTypeCriterion) trace.getInitialPacket()
.getCriterion(Criterion.Type.ETH_TYPE);
//We treat as correct output only if it's not LLDP or BDDP
@@ -551,7 +553,7 @@
if (ipAddress != null) {
IpAddress finalIpAddress = ipAddress;
if (hostsList.stream().anyMatch(host -> host.ipAddresses().contains(finalIpAddress)) ||
- hostService.getHostsByIp(finalIpAddress).isEmpty()) {
+ hostNib.getHostsByIp(finalIpAddress).isEmpty()) {
trace.addResultMessage("Packet is " +
((EthTypeCriterion) outputPath.getFinalPacket()
.getCriterion(Criterion.Type.ETH_TYPE)).ethType() +
@@ -574,7 +576,7 @@
} else {
computePath(completePath, trace, cp);
trace.setSuccess(false);
- if (deviceService.getPort(cp) == null) {
+ if (deviceNib.getPort(cp) == null) {
//Port is not existent on device.
log.warn("Port {} is not available on device.", cp);
trace.addResultMessage("Port " + cp + "is not available on device. Packet is dropped");
@@ -660,15 +662,15 @@
.getCriterion(Criterion.Type.IPV6_DST));
Set<Host> hosts = new HashSet<>();
if (ipv4Criterion != null) {
- hosts.addAll(hostService.getHostsByIp(ipv4Criterion.ip().address()));
+ hosts.addAll(hostNib.getHostsByIp(ipv4Criterion.ip().address()));
}
if (ipv6Criterion != null) {
- hosts.addAll(hostService.getHostsByIp(ipv6Criterion.ip().address()));
+ hosts.addAll(hostNib.getHostsByIp(ipv6Criterion.ip().address()));
}
EthCriterion ethCriterion = ((EthCriterion) trace.getInitialPacket()
.getCriterion(Criterion.Type.ETH_DST));
if (ethCriterion != null) {
- hosts.addAll(hostService.getHostsByMac(ethCriterion.mac()));
+ hosts.addAll(hostNib.getHostsByMac(ethCriterion.mac()));
}
return hosts;
}
@@ -727,7 +729,7 @@
log.debug("Packet {} coming in from {}", packet, in);
//if device is not available exit here.
- if (!deviceService.isAvailable(in.deviceId())) {
+ if (!deviceNib.isAvailable(in.deviceId())) {
trace.addResultMessage("Device is offline " + in.deviceId());
computePath(completePath, trace, null);
return trace;
@@ -765,7 +767,7 @@
log.debug("Found Flow Entry {}", flowEntry);
boolean isOfdpaHardware = TroubleshootUtils.hardwareOfdpaMap
- .getOrDefault(driverService.getDriver(in.deviceId()).name(), false);
+ .getOrDefault(driverNib.getDriverName(in.deviceId()), false);
//if the flow entry on a table is null and we are on hardware we treat as table miss, with few exceptions
if (flowEntry == null && isOfdpaHardware) {
@@ -945,11 +947,10 @@
ip = ((IPCriterion) trace.getInitialPacket().getCriterion(Criterion.Type.IPV6_DST)).ip().address();
}
if (ip != null) {
- Optional<ResolvedRoute> optionalRoute = routeService.longestPrefixLookup(ip);
+ Optional<ResolvedRoute> optionalRoute = routeNib.longestPrefixLookup(ip);
if (optionalRoute.isPresent()) {
ResolvedRoute route = optionalRoute.get();
- route.prefix();
- multipleRoutes = routeService.getAllResolvedRoutes(route.prefix()).size() > 1;
+ multipleRoutes = routeNib.getAllResolvedRoutes(route.prefix()).size() > 1;
}
}
return multipleRoutes;
@@ -972,7 +973,7 @@
if (ethTypeCriterion != null && (ethTypeCriterion.ethType().equals(EtherType.LLDP.ethType())
|| ethTypeCriterion.ethType().equals(EtherType.BDDP.ethType()))) {
//get the active ports
- List<Port> enabledPorts = deviceService.getPorts(in.deviceId()).stream()
+ List<Port> enabledPorts = deviceNib.getPorts(in.deviceId()).stream()
.filter(Port::isEnabled)
.collect(Collectors.toList());
//build an output from each one
@@ -1012,9 +1013,9 @@
if (packetVlanIdCriterion.vlanId().equals(entryModVlanIdInstruction.vlanId())) {
//find a rule on the same table that matches the vlan and
// also all the other elements of the flow such as input port
- secondVlanFlow = Lists.newArrayList(flowRuleService.getFlowEntriesByState(in.deviceId(),
- FlowEntry.FlowEntryState.ADDED).iterator())
- .stream()
+ secondVlanFlow = Lists.newArrayList(flowNib.getFlowEntriesByState(in.deviceId(),
+ FlowEntry.FlowEntryState.ADDED)
+ .iterator()).stream()
.filter(entry -> {
return entry.table().equals(IndexTableId.of(10));
})
@@ -1065,8 +1066,7 @@
private FlowEntry findNextTableIdEntry(DeviceId deviceId, int currentId) {
final Comparator<FlowEntry> comparator = Comparator.comparing((FlowEntry f) -> ((IndexTableId) f.table()).id());
-
- return Lists.newArrayList(flowRuleService.getFlowEntriesByState(deviceId, FlowEntry.FlowEntryState.ADDED)
+ return Lists.newArrayList(flowNib.getFlowEntriesByState(deviceId, FlowEntry.FlowEntryState.ADDED)
.iterator()).stream()
.filter(f -> ((IndexTableId) f.table()).id() > currentId).min(comparator).orElse(null);
}
@@ -1149,7 +1149,7 @@
//handle all the internal instructions pointing to a group.
for (Instruction instr : groupInstructionlist) {
GroupInstruction groupInstruction = (GroupInstruction) instr;
- Group group = Lists.newArrayList(groupService.getGroups(deviceId)).stream().filter(groupInternal -> {
+ Group group = Lists.newArrayList(groupNib.getGroups(deviceId)).stream().filter(groupInternal -> {
return groupInternal.id().equals(groupInstruction.groupId());
}).findAny().orElse(null);
if (group == null) {
@@ -1312,7 +1312,7 @@
private FlowEntry matchHighestPriority(TrafficSelector packet, ConnectPoint in, TableId tableId) {
//Computing the possible match rules.
final Comparator<FlowEntry> comparator = Comparator.comparing(FlowRule::priority);
- return Lists.newArrayList(flowRuleService.getFlowEntriesByState(in.deviceId(), FlowEntry.FlowEntryState.ADDED)
+ return Lists.newArrayList(flowNib.getFlowEntriesByState(in.deviceId(), FlowEntry.FlowEntryState.ADDED)
.iterator()).stream()
.filter(flowEntry -> {
return flowEntry.table().equals(tableId);
diff --git a/apps/t3/app/src/test/java/org/onosproject/t3/impl/TroubleshootManagerTest.java b/apps/t3/app/src/test/java/org/onosproject/t3/impl/TroubleshootManagerTest.java
index c00d373..d1eba21 100644
--- a/apps/t3/app/src/test/java/org/onosproject/t3/impl/TroubleshootManagerTest.java
+++ b/apps/t3/app/src/test/java/org/onosproject/t3/impl/TroubleshootManagerTest.java
@@ -25,7 +25,6 @@
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.cluster.NodeId;
-import org.onosproject.mastership.MastershipServiceAdapter;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.DefaultDevice;
@@ -37,29 +36,27 @@
import org.onosproject.net.Link;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
-import org.onosproject.net.device.DeviceServiceAdapter;
-import org.onosproject.net.driver.DefaultDriver;
-import org.onosproject.net.driver.Driver;
-import org.onosproject.net.driver.DriverServiceAdapter;
-import org.onosproject.net.edge.EdgePortServiceAdapter;
import org.onosproject.net.flow.FlowEntry;
-import org.onosproject.net.flow.FlowRuleServiceAdapter;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.criteria.EthTypeCriterion;
import org.onosproject.net.flow.criteria.MplsCriterion;
import org.onosproject.net.flow.criteria.VlanIdCriterion;
import org.onosproject.net.group.Group;
-import org.onosproject.net.group.GroupServiceAdapter;
-import org.onosproject.net.host.HostServiceAdapter;
-import org.onosproject.net.link.LinkServiceAdapter;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.routeservice.ResolvedRoute;
-import org.onosproject.routeservice.RouteServiceAdapter;
+import org.onosproject.t3.api.DeviceNib;
+import org.onosproject.t3.api.DriverNib;
+import org.onosproject.t3.api.EdgePortNib;
+import org.onosproject.t3.api.FlowNib;
+import org.onosproject.t3.api.GroupNib;
+import org.onosproject.t3.api.HostNib;
+import org.onosproject.t3.api.LinkNib;
+import org.onosproject.t3.api.MastershipNib;
+import org.onosproject.t3.api.RouteNib;
import org.onosproject.t3.api.StaticPacketTrace;
import org.slf4j.Logger;
-import java.util.HashMap;
import java.util.Optional;
import java.util.Set;
@@ -84,24 +81,28 @@
@Before
public void setUp() throws Exception {
mngr = new TroubleshootManager();
- mngr.flowRuleService = new TestFlowRuleService();
- mngr.hostService = new TestHostService();
- mngr.linkService = new TestLinkService();
- mngr.driverService = new TestDriverService();
- mngr.groupService = new TestGroupService();
- mngr.deviceService = new TestDeviceService();
- mngr.mastershipService = new TestMastershipService();
- mngr.edgePortService = new TestEdgePortService();
- mngr.routeService = new TestRouteService();
+
+ mngr.flowNib = new TestFlowRuleService();
+ mngr.groupNib = new TestGroupService();
+ mngr.hostNib = new TestHostService();
+ mngr.linkNib = new TestLinkService();
+ mngr.deviceNib = new TestDeviceService();
+ mngr.driverNib = new TestDriverService();
+ mngr.mastershipNib = new TestMastershipService();
+ mngr.edgePortNib = new TestEdgePortService();
+ mngr.routeNib = new TestRouteService();
assertNotNull("Manager should not be null", mngr);
- assertNotNull("Flow rule Service should not be null", mngr.flowRuleService);
- assertNotNull("Host Service should not be null", mngr.hostService);
- assertNotNull("Group Service should not be null", mngr.groupService);
- assertNotNull("Driver Service should not be null", mngr.driverService);
- assertNotNull("Link Service should not be null", mngr.linkService);
- assertNotNull("Device Service should not be null", mngr.deviceService);
+ assertNotNull("Flow rule Service should not be null", mngr.flowNib);
+ assertNotNull("Group Service should not be null", mngr.groupNib);
+ assertNotNull("Host Service should not be null", mngr.hostNib);
+ assertNotNull("Link Service should not be null", mngr.linkNib);
+ assertNotNull("Device Service should not be null", mngr.deviceNib);
+ assertNotNull("Driver Service should not be null", mngr.driverNib);
+ assertNotNull("Mastership Service should not be null", mngr.driverNib);
+ assertNotNull("EdgePort Service should not be null", mngr.driverNib);
+ assertNotNull("Route Service should not be null", mngr.routeNib);
}
/**
@@ -436,7 +437,7 @@
assertNull("Trace should have 0 output", traceFail.getGroupOuputs(deviceId));
}
- private class TestFlowRuleService extends FlowRuleServiceAdapter {
+ private class TestFlowRuleService extends FlowNib {
@Override
public Iterable<FlowEntry> getFlowEntriesByState(DeviceId deviceId, FlowEntry.FlowEntryState state) {
if (deviceId.equals(SINGLE_FLOW_DEVICE)) {
@@ -486,19 +487,7 @@
}
}
- private class TestDriverService extends DriverServiceAdapter {
- @Override
- public Driver getDriver(DeviceId deviceId) {
- if (deviceId.equals(HARDWARE_DEVICE) || deviceId.equals(HARDWARE_DEVICE_10)) {
- return new DefaultDriver("ofdpa", ImmutableList.of(),
- "test", "test", "test", new HashMap<>(), new HashMap<>());
- }
- return new DefaultDriver("NotHWDriver", ImmutableList.of(),
- "test", "test", "test", new HashMap<>(), new HashMap<>());
- }
- }
-
- private class TestGroupService extends GroupServiceAdapter {
+ private class TestGroupService extends GroupNib {
@Override
public Iterable<Group> getGroups(DeviceId deviceId) {
if (deviceId.equals(GROUP_FLOW_DEVICE)) {
@@ -520,7 +509,7 @@
}
}
- private class TestHostService extends HostServiceAdapter {
+ private class TestHostService extends HostNib {
@Override
public Set<Host> getConnectedHosts(ConnectPoint connectPoint) {
if (connectPoint.equals(TOPO_FLOW_3_OUT_CP)) {
@@ -570,7 +559,7 @@
}
}
- private class TestLinkService extends LinkServiceAdapter {
+ private class TestLinkService extends LinkNib {
@Override
public Set<Link> getEgressLinks(ConnectPoint connectPoint) {
if (connectPoint.equals(TOPO_FLOW_1_OUT_CP)
@@ -649,7 +638,7 @@
}
}
- private class TestDeviceService extends DeviceServiceAdapter {
+ private class TestDeviceService extends DeviceNib {
@Override
public Device getDevice(DeviceId deviceId) {
if (deviceId.equals(DeviceId.deviceId("nonexistent"))) {
@@ -671,8 +660,24 @@
}
}
- private class TestEdgePortService extends EdgePortServiceAdapter {
+ private class TestDriverService extends DriverNib {
+ @Override
+ public String getDriverName(DeviceId deviceId) {
+ if (deviceId.equals(HARDWARE_DEVICE) || deviceId.equals(HARDWARE_DEVICE_10)) {
+ return "ofdpa";
+ }
+ return "NotHWDriver";
+ }
+ }
+ private class TestMastershipService extends MastershipNib {
+ @Override
+ public NodeId getMasterFor(DeviceId deviceId) {
+ return NodeId.nodeId(MASTER_1);
+ }
+ }
+
+ private class TestEdgePortService extends EdgePortNib {
@Override
public boolean isEdgePoint(ConnectPoint point) {
return point.equals(MULTICAST_OUT_CP) ||
@@ -680,17 +685,11 @@
}
}
- private class TestRouteService extends RouteServiceAdapter {
+ private class TestRouteService extends RouteNib {
@Override
public Optional<ResolvedRoute> longestPrefixLookup(IpAddress ip) {
return Optional.empty();
}
}
- private class TestMastershipService extends MastershipServiceAdapter {
- @Override
- public NodeId getMasterFor(DeviceId deviceId) {
- return NodeId.nodeId(MASTER_1);
- }
- }
}
\ No newline at end of file
diff --git a/cli/src/main/java/org/onosproject/cli/net/DevicePortsListCommand.java b/cli/src/main/java/org/onosproject/cli/net/DevicePortsListCommand.java
index 86887f7..f3d63bd 100644
--- a/cli/src/main/java/org/onosproject/cli/net/DevicePortsListCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/DevicePortsListCommand.java
@@ -114,6 +114,7 @@
for (Port port : service.getPorts(device.id())) {
if (isIncluded(port)) {
ports.add(mapper.createObjectNode()
+ .put("element", device.id().toString())
.put("port", port.number().toString())
.put("isEnabled", port.isEnabled())
.put("type", port.type().toString().toLowerCase())
diff --git a/cli/src/main/java/org/onosproject/cli/net/EdgePortsListCommand.java b/cli/src/main/java/org/onosproject/cli/net/EdgePortsListCommand.java
index 6f7ae26..2f24ceb 100644
--- a/cli/src/main/java/org/onosproject/cli/net/EdgePortsListCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/EdgePortsListCommand.java
@@ -15,6 +15,7 @@
*/
package org.onosproject.cli.net;
+import com.fasterxml.jackson.databind.node.ArrayNode;
import org.apache.karaf.shell.api.action.Argument;
import org.apache.karaf.shell.api.action.Command;
import org.apache.karaf.shell.api.action.Completion;
@@ -56,7 +57,17 @@
}
private void printEdgePoints(Iterable<ConnectPoint> edgePoints) {
- sort(edgePoints).forEach(e -> print(FMT, e.deviceId(), e.port()));
+ List<ConnectPoint> sorted = sort(edgePoints);
+ if (outputJson()) {
+ ArrayNode result = mapper().createObjectNode().putArray(null);
+ sorted.forEach(e -> {
+ result.add(mapper().createObjectNode()
+ .put(e.deviceId().toString(), e.port().toString()));
+ });
+ print("%s", result.toString());
+ } else {
+ sorted.forEach(e -> print(FMT, e.deviceId(), e.port()));
+ }
}
private static List<ConnectPoint> sort(Iterable<ConnectPoint> connectPoints) {
diff --git a/core/common/BUILD b/core/common/BUILD
index 9abdc58..be6cac4 100644
--- a/core/common/BUILD
+++ b/core/common/BUILD
@@ -1,4 +1,6 @@
-COMPILE_DEPS = CORE_DEPS + JACKSON + METRICS
+COMPILE_DEPS = CORE_DEPS + JACKSON + METRICS + KRYO + [
+ "//core/store/serializers:onos-core-serializers",
+]
TEST_DEPS = TEST + ["//core/api:onos-api-tests"]
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/CriterionCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/CriterionCodec.java
index 24b749c..93cfe5d 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/CriterionCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/CriterionCodec.java
@@ -82,6 +82,7 @@
static final String PI_MATCH_MASK = "mask";
static final String PI_MATCH_HIGH_VALUE = "highValue";
static final String PI_MATCH_LOW_VALUE = "lowValue";
+ static final String EXTENSION = "extension";
@Override
public ObjectNode encode(Criterion criterion, CodecContext context) {
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java
index f690d5d..9516ed3 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java
@@ -15,6 +15,7 @@
*/
package org.onosproject.codec.impl;
+import com.esotericsoftware.kryo.io.Input;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onlab.packet.Ip6Address;
@@ -33,20 +34,28 @@
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.criteria.Criteria;
import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.ExtensionCriterion;
import org.onosproject.net.flow.criteria.PiCriterion;
import org.onosproject.net.pi.model.PiMatchFieldId;
import org.onosproject.net.pi.model.PiMatchType;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.slf4j.Logger;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import static org.onlab.util.Tools.nullIsIllegal;
+import static org.slf4j.LoggerFactory.getLogger;
/**
* Decode portion of the criterion codec.
*/
public final class DecodeCriterionCodecHelper {
+ private static final Logger log = getLogger(DecodeCriterionCodecHelper.class);
+
private final ObjectNode json;
protected static final String MISSING_MEMBER_MESSAGE =
@@ -114,6 +123,7 @@
decoderMap.put(Criterion.Type.ODU_SIGID.name(), new OduSigIdDecoder());
decoderMap.put(Criterion.Type.ODU_SIGTYPE.name(), new OduSigTypeDecoder());
decoderMap.put(Criterion.Type.PROTOCOL_INDEPENDENT.name(), new PiDecoder());
+ decoderMap.put(Criterion.Type.EXTENSION.name(), new ExtensionDecoder());
}
private class EthTypeDecoder implements CriterionDecoder {
@@ -130,6 +140,7 @@
return Criteria.matchEthType(ethType);
}
}
+
private class EthDstDecoder implements CriterionDecoder {
@Override
public Criterion decodeCriterion(ObjectNode json) {
@@ -139,6 +150,7 @@
return Criteria.matchEthDst(mac);
}
}
+
private class EthDstMaskedDecoder implements CriterionDecoder {
@Override
public Criterion decodeCriterion(ObjectNode json) {
@@ -149,6 +161,7 @@
return Criteria.matchEthDstMasked(mac, macMask);
}
}
+
private class EthSrcDecoder implements CriterionDecoder {
@Override
public Criterion decodeCriterion(ObjectNode json) {
@@ -669,6 +682,24 @@
}
}
+ private class ExtensionDecoder implements CriterionDecoder {
+ @Override
+ public Criterion decodeCriterion(ObjectNode json) {
+ try {
+ byte[] buffer = nullIsIllegal(json.get(CriterionCodec.EXTENSION),
+ CriterionCodec.EXTENSION + MISSING_MEMBER_MESSAGE).binaryValue();
+ Input input = new Input(new ByteArrayInputStream(buffer));
+ ExtensionCriterion extensionCriterion =
+ KryoNamespaces.API.borrow().readObject(input, ExtensionCriterion.class);
+ input.close();
+ return extensionCriterion;
+ } catch (IOException e) {
+ log.warn("Cannot convert the {} field into byte array", CriterionCodec.EXTENSION);
+ return null;
+ }
+ }
+ }
+
/**
* Decodes the JSON into a criterion object.
*
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
index 2933ca9..cfe5447 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
@@ -137,7 +137,10 @@
long tunnelId = nullIsIllegal(json.get(InstructionCodec.TUNNEL_ID),
InstructionCodec.TUNNEL_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asLong();
return Instructions.modTunnelId(tunnelId);
+ } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_BOS.name())) {
+ return Instructions.modMplsBos(json.get("bos").asBoolean());
}
+
throw new IllegalArgumentException("L2 Instruction subtype "
+ subType + " is not supported");
}
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/DeviceCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/DeviceCodec.java
index d34092a..c42dcfd 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/DeviceCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/DeviceCodec.java
@@ -20,6 +20,7 @@
import org.onlab.packet.ChassisId;
import org.onosproject.codec.CodecContext;
import org.onosproject.net.Annotations;
+import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.DefaultDevice;
import org.onosproject.net.Device;
import org.onosproject.net.Device.Type;
@@ -99,4 +100,26 @@
return new DefaultDevice(pid, id, type, mfr, hw, sw, serial,
chassisId, annotations);
}
+
+ /**
+ * Extracts annotations of given Object.
+ *
+ * @param deviceNode annotated JSON object node representing a device
+ * @param context decode context
+ * @return extracted Annotations
+ */
+ @Override
+ protected Annotations extractAnnotations(ObjectNode deviceNode, CodecContext context) {
+ ObjectNode annotationsNode = get(deviceNode, "annotations");
+ if (annotationsNode != null) {
+ // add needed fields to the annotations of the Device object
+ if (deviceNode.get(AVAILABLE) != null) {
+ annotationsNode.put(AVAILABLE, deviceNode.get(AVAILABLE).asText());
+ }
+ return context.codec(Annotations.class).decode(annotationsNode, context);
+ } else {
+ return DefaultAnnotations.EMPTY;
+ }
+ }
+
}
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java
index 067a99a..c99e353 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java
@@ -15,6 +15,7 @@
*/
package org.onosproject.codec.impl;
+import com.esotericsoftware.kryo.io.Output;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onlab.util.HexString;
@@ -57,7 +58,9 @@
import org.onosproject.net.pi.runtime.PiLpmFieldMatch;
import org.onosproject.net.pi.runtime.PiRangeFieldMatch;
import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
+import org.onosproject.store.serializers.KryoNamespaces;
+import java.io.ByteArrayOutputStream;
import java.util.EnumMap;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -133,6 +136,7 @@
formatMap.put(Criterion.Type.ODU_SIGID, new FormatOduSignalId());
formatMap.put(Criterion.Type.ODU_SIGTYPE, new FormatOduSignalType());
formatMap.put(Criterion.Type.PROTOCOL_INDEPENDENT, new FormatProtocolIndependent());
+ formatMap.put(Criterion.Type.EXTENSION, new FormatExtension());
// Currently unimplemented
formatMap.put(Criterion.Type.ARP_OP, new FormatUnknown());
formatMap.put(Criterion.Type.ARP_SPA, new FormatUnknown());
@@ -146,7 +150,6 @@
formatMap.put(Criterion.Type.TCP_FLAGS, new FormatUnknown());
formatMap.put(Criterion.Type.ACTSET_OUTPUT, new FormatUnknown());
formatMap.put(Criterion.Type.PACKET_TYPE, new FormatUnknown());
- formatMap.put(Criterion.Type.EXTENSION, new FormatUnknown());
formatMap.put(Criterion.Type.ETH_SRC_MASKED, new FormatUnknown());
formatMap.put(Criterion.Type.TCP_SRC_MASKED, new FormatUnknown());
formatMap.put(Criterion.Type.TCP_DST_MASKED, new FormatUnknown());
@@ -579,6 +582,19 @@
}
}
+ private class FormatExtension implements CriterionTypeFormatter {
+ @Override
+ public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) {
+ Output output = new Output(new ByteArrayOutputStream());
+ KryoNamespaces.API.borrow().writeObject(output, criterion);
+ root.put(CriterionCodec.EXTENSION, output.toBytes());
+ output.flush();
+ output.close();
+
+ return root;
+ }
+ }
+
private class FormatDummyType implements CriterionTypeFormatter {
@Override
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java
index a30068e..589a386 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java
@@ -309,6 +309,8 @@
}
if (device.is(ExtensionTreatmentCodec.class)) {
+ // for extension instructions, encoding device id is needed for the corresponding decoder
+ result.put("deviceId", deviceId.toString());
ExtensionTreatmentCodec treatmentCodec = device.as(ExtensionTreatmentCodec.class);
ObjectNode node = treatmentCodec.encode(extensionInstruction.extensionInstruction(), context);
result.set(InstructionCodec.EXTENSION, node);
diff --git a/tools/package/runtime/bin/onos-diagnostics b/tools/package/runtime/bin/onos-diagnostics
index 2ac2310..0daa320 100755
--- a/tools/package/runtime/bin/onos-diagnostics
+++ b/tools/package/runtime/bin/onos-diagnostics
@@ -20,7 +20,7 @@
# Tool to collect cluster-wide diagnostics into a single tar stream.
# -----------------------------------------------------------------------------
function usage() {
- echo "usage: $(basename $0) [-x] [-n name] [-P port] [-u user] [-p password] [ip1 ip2...]"
+ echo "usage: $(basename $0) [-x] [-j] [-n name] [-P port] [-u user] [-p password] [ip1 ip2...]"
echo ""
echo "Environment Variables:"
echo " ONOS_INSTANCES IPs or hostnames of ONOS cluster machines"
@@ -41,6 +41,11 @@
echo " # The cluster node IPs will be drawn from ONOS_INSTANCES variable."
echo " > $(basename $0) -x -n prague -u onos -p rules"
echo ""
+ echo " # Collect diagnostics for the cluster and store them in JSON files."
+ echo " # JSON_CLI_COMMANDS below lists JSON-supported diagnostics commands."
+ echo " # Collection archive will be named /tmp/onos-diags.tar.gz"
+ echo " > $(basename $0) -j"
+ echo ""
echo " # Collect compressed diagnostics for a cluster."
echo " # REST API user name is 'onos' and password is 'rules'."
echo " # Collection archive will be named /tmp/onos-diags.tar.gz"
@@ -75,14 +80,15 @@
"hosts"
"interfaces"
- "ports -e"
+ "ports"
"portstats -nz"
+ "edge-ports"
"packet-processors"
"packet-requests"
"intents"
- "flows -s"
+ "flows"
"groups"
"roles"
@@ -118,18 +124,34 @@
"mcast-host-show"
)
+JSON_CLI_COMMANDS=(
+ "netcfg -j"
+ "devices -j"
+ "device-drivers -j"
+ "links -j"
+ "hosts -j"
+ "ports -j"
+ "edge-ports -j"
+ "flows -j"
+ "groups -j"
+ "masters -j"
+ "routes -j"
+ "mcast-host-show -j"
+)
+
port=${ONOS_WEB_PORT}
user=${ONOS_WEB_USER}
password=${ONOS_WEB_PASS}
# Scan arguments for user/password or other options...
-while getopts n:P:u:p:x?h o; do
+while getopts n:P:u:p:x?j?h o; do
case "$o" in
n) name=$OPTARG;;
P) port=$OPTARG;;
u) user=$OPTARG;;
p) password=$OPTARG;;
x) extract=true;;
+ j) json=true;;
*) usage;;
esac
done
@@ -158,8 +180,10 @@
tar zxf ../$node.tar.gz && rm ../$node.tar.gz
# Acquire remotely obtained diagnostics via ssh CLI
+ [ ! -z $json ] && CLI_COMMANDS=("${JSON_CLI_COMMANDS[@]}")
for cmd in "${CLI_COMMANDS[@]}"; do
cmdLog="$(echo $cmd | cut -d\ -f1 | sed 's/:/-/g').txt"
+ [ ! -z $json ] && cmdLog="${cmdLog%.txt}.json"
printf "$cmdLog "
onos $node $cmd 2>/dev/null >$cmdLog
done