Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
Conflicts: core/store/hz/net/src/main/java/org/onlab/onos/store/device/impl/DistributedDeviceStore.java core/store/hz/net/src/test/java/org/onlab/onos/store/device/impl/DistributedDeviceStoreTest.java features/features.xml tools/test/cells/office Change-Id: I08e6d7c6a0bdaae072dd50ff7ac36d94f16d77e1
Showing
151 changed files
with
3389 additions
and
168 deletions
apps/calendar/pom.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
5 | + <modelVersion>4.0.0</modelVersion> | ||
6 | + | ||
7 | + <parent> | ||
8 | + <groupId>org.onlab.onos</groupId> | ||
9 | + <artifactId>onos-apps</artifactId> | ||
10 | + <version>1.0.0-SNAPSHOT</version> | ||
11 | + <relativePath>../pom.xml</relativePath> | ||
12 | + </parent> | ||
13 | + | ||
14 | + <artifactId>onos-app-calendar</artifactId> | ||
15 | + <packaging>bundle</packaging> | ||
16 | + | ||
17 | + <description>ONOS simple calendaring REST interface for intents</description> | ||
18 | + | ||
19 | + <properties> | ||
20 | + <web.context>/onos/calendar</web.context> | ||
21 | + </properties> | ||
22 | + | ||
23 | + <dependencies> | ||
24 | + <dependency> | ||
25 | + <groupId>org.onlab.onos</groupId> | ||
26 | + <artifactId>onlab-rest</artifactId> | ||
27 | + <version>${project.version}</version> | ||
28 | + </dependency> | ||
29 | + | ||
30 | + <dependency> | ||
31 | + <groupId>com.sun.jersey</groupId> | ||
32 | + <artifactId>jersey-servlet</artifactId> | ||
33 | + </dependency> | ||
34 | + <dependency> | ||
35 | + <groupId>com.sun.jersey.jersey-test-framework</groupId> | ||
36 | + <artifactId>jersey-test-framework-core</artifactId> | ||
37 | + <version>1.18.1</version> | ||
38 | + <scope>test</scope> | ||
39 | + </dependency> | ||
40 | + <dependency> | ||
41 | + <groupId>com.sun.jersey.jersey-test-framework</groupId> | ||
42 | + <artifactId>jersey-test-framework-grizzly2</artifactId> | ||
43 | + <version>1.18.1</version> | ||
44 | + <scope>test</scope> | ||
45 | + </dependency> | ||
46 | + <dependency> | ||
47 | + <groupId>org.osgi</groupId> | ||
48 | + <artifactId>org.osgi.core</artifactId> | ||
49 | + </dependency> | ||
50 | + </dependencies> | ||
51 | + | ||
52 | + <build> | ||
53 | + <plugins> | ||
54 | + <plugin> | ||
55 | + <groupId>org.apache.felix</groupId> | ||
56 | + <artifactId>maven-bundle-plugin</artifactId> | ||
57 | + <extensions>true</extensions> | ||
58 | + <configuration> | ||
59 | + <instructions> | ||
60 | + <_wab>src/main/webapp/</_wab> | ||
61 | + <Bundle-SymbolicName> | ||
62 | + ${project.groupId}.${project.artifactId} | ||
63 | + </Bundle-SymbolicName> | ||
64 | + <Import-Package> | ||
65 | + org.osgi.framework, | ||
66 | + javax.ws.rs,javax.ws.rs.core, | ||
67 | + com.sun.jersey.api.core, | ||
68 | + com.sun.jersey.spi.container.servlet, | ||
69 | + com.sun.jersey.server.impl.container.servlet, | ||
70 | + org.onlab.packet.*, | ||
71 | + org.onlab.rest.*, | ||
72 | + org.onlab.onos.* | ||
73 | + </Import-Package> | ||
74 | + <Web-ContextPath>${web.context}</Web-ContextPath> | ||
75 | + </instructions> | ||
76 | + </configuration> | ||
77 | + </plugin> | ||
78 | + </plugins> | ||
79 | + </build> | ||
80 | + | ||
81 | +</project> |
1 | +package org.onlab.onos.calendar; | ||
2 | + | ||
3 | +import org.onlab.onos.net.ConnectPoint; | ||
4 | +import org.onlab.onos.net.DeviceId; | ||
5 | +import org.onlab.onos.net.intent.IntentService; | ||
6 | +import org.onlab.rest.BaseResource; | ||
7 | + | ||
8 | +import javax.ws.rs.POST; | ||
9 | +import javax.ws.rs.Path; | ||
10 | +import javax.ws.rs.PathParam; | ||
11 | +import javax.ws.rs.core.Response; | ||
12 | +import java.net.URI; | ||
13 | + | ||
14 | +import static org.onlab.onos.net.PortNumber.portNumber; | ||
15 | + | ||
16 | +/** | ||
17 | + * Web resource for triggering calendared intents. | ||
18 | + */ | ||
19 | +@Path("intent") | ||
20 | +public class BandwidthCalendarResource extends BaseResource { | ||
21 | + | ||
22 | + @POST | ||
23 | + @Path("{src}/{dst}/{srcPort}/{dstPort}/{bandwidth}") | ||
24 | + public Response createIntent(@PathParam("src") String src, | ||
25 | + @PathParam("dst") String dst, | ||
26 | + @PathParam("srcPort") String srcPort, | ||
27 | + @PathParam("dstPort") String dstPort, | ||
28 | + @PathParam("bandwidth") String bandwidth) { | ||
29 | + // TODO: implement calls to intent framework | ||
30 | + IntentService service = get(IntentService.class); | ||
31 | + | ||
32 | + ConnectPoint srcPoint = new ConnectPoint(deviceId(src), portNumber(srcPort)); | ||
33 | + ConnectPoint dstPoint = new ConnectPoint(deviceId(dst), portNumber(dstPort)); | ||
34 | + | ||
35 | + return Response.ok("Yo! We got src=" + srcPoint + "; dst=" + dstPoint + | ||
36 | + "; bw=" + bandwidth + "; intent service " + service).build(); | ||
37 | + } | ||
38 | + | ||
39 | + private DeviceId deviceId(String dpid) { | ||
40 | + return DeviceId.deviceId(URI.create("of:" + dpid)); | ||
41 | + } | ||
42 | + | ||
43 | +} |
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" | ||
3 | + xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" | ||
4 | + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" | ||
5 | + id="ONOS" version="2.5"> | ||
6 | + <display-name>ONOS GUI</display-name> | ||
7 | + | ||
8 | + <servlet> | ||
9 | + <servlet-name>JAX-RS Service</servlet-name> | ||
10 | + <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> | ||
11 | + <init-param> | ||
12 | + <param-name>com.sun.jersey.config.property.packages</param-name> | ||
13 | + <param-value>org.onlab.onos.calendar</param-value> | ||
14 | + </init-param> | ||
15 | + <load-on-startup>10</load-on-startup> | ||
16 | + </servlet> | ||
17 | + | ||
18 | + <servlet-mapping> | ||
19 | + <servlet-name>JAX-RS Service</servlet-name> | ||
20 | + <url-pattern>/rs/*</url-pattern> | ||
21 | + </servlet-mapping> | ||
22 | + | ||
23 | +</web-app> | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -16,4 +16,11 @@ | ... | @@ -16,4 +16,11 @@ |
16 | 16 | ||
17 | <description>ONOS simple reactive forwarding app</description> | 17 | <description>ONOS simple reactive forwarding app</description> |
18 | 18 | ||
19 | + <dependencies> | ||
20 | + <dependency> | ||
21 | + <groupId>org.osgi</groupId> | ||
22 | + <artifactId>org.osgi.compendium</artifactId> | ||
23 | + </dependency> | ||
24 | + </dependencies> | ||
25 | + | ||
19 | </project> | 26 | </project> | ... | ... |
1 | package org.onlab.onos.fwd; | 1 | package org.onlab.onos.fwd; |
2 | 2 | ||
3 | -import static org.slf4j.LoggerFactory.getLogger; | ||
4 | - | ||
5 | -import java.util.Set; | ||
6 | - | ||
7 | import org.apache.felix.scr.annotations.Activate; | 3 | import org.apache.felix.scr.annotations.Activate; |
8 | import org.apache.felix.scr.annotations.Component; | 4 | import org.apache.felix.scr.annotations.Component; |
9 | import org.apache.felix.scr.annotations.Deactivate; | 5 | import org.apache.felix.scr.annotations.Deactivate; |
6 | +import org.apache.felix.scr.annotations.Modified; | ||
7 | +import org.apache.felix.scr.annotations.Property; | ||
10 | import org.apache.felix.scr.annotations.Reference; | 8 | import org.apache.felix.scr.annotations.Reference; |
11 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 9 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
12 | import org.onlab.onos.ApplicationId; | 10 | import org.onlab.onos.ApplicationId; |
... | @@ -29,8 +27,14 @@ import org.onlab.onos.net.packet.PacketProcessor; | ... | @@ -29,8 +27,14 @@ import org.onlab.onos.net.packet.PacketProcessor; |
29 | import org.onlab.onos.net.packet.PacketService; | 27 | import org.onlab.onos.net.packet.PacketService; |
30 | import org.onlab.onos.net.topology.TopologyService; | 28 | import org.onlab.onos.net.topology.TopologyService; |
31 | import org.onlab.packet.Ethernet; | 29 | import org.onlab.packet.Ethernet; |
30 | +import org.osgi.service.component.ComponentContext; | ||
32 | import org.slf4j.Logger; | 31 | import org.slf4j.Logger; |
33 | 32 | ||
33 | +import java.util.Dictionary; | ||
34 | +import java.util.Set; | ||
35 | + | ||
36 | +import static org.slf4j.LoggerFactory.getLogger; | ||
37 | + | ||
34 | /** | 38 | /** |
35 | * Sample reactive forwarding application. | 39 | * Sample reactive forwarding application. |
36 | */ | 40 | */ |
... | @@ -61,6 +65,10 @@ public class ReactiveForwarding { | ... | @@ -61,6 +65,10 @@ public class ReactiveForwarding { |
61 | 65 | ||
62 | private ApplicationId appId; | 66 | private ApplicationId appId; |
63 | 67 | ||
68 | + @Property(name = "enabled", boolValue = true, | ||
69 | + label = "Enable forwarding; default is true") | ||
70 | + private boolean isEnabled = true; | ||
71 | + | ||
64 | @Activate | 72 | @Activate |
65 | public void activate() { | 73 | public void activate() { |
66 | appId = coreService.registerApplication("org.onlab.onos.fwd"); | 74 | appId = coreService.registerApplication("org.onlab.onos.fwd"); |
... | @@ -76,6 +84,22 @@ public class ReactiveForwarding { | ... | @@ -76,6 +84,22 @@ public class ReactiveForwarding { |
76 | log.info("Stopped"); | 84 | log.info("Stopped"); |
77 | } | 85 | } |
78 | 86 | ||
87 | + @Modified | ||
88 | + public void modified(ComponentContext context) { | ||
89 | + Dictionary properties = context.getProperties(); | ||
90 | + String flag = (String) properties.get("enabled"); | ||
91 | + if (flag != null) { | ||
92 | + boolean enabled = flag.equals("true"); | ||
93 | + if (isEnabled != enabled) { | ||
94 | + isEnabled = enabled; | ||
95 | + if (!isEnabled) { | ||
96 | + flowRuleService.removeFlowRulesById(appId); | ||
97 | + } | ||
98 | + log.info("Reconfigured. Forwarding is {}", | ||
99 | + isEnabled ? "enabled" : "disabled"); | ||
100 | + } | ||
101 | + } | ||
102 | + } | ||
79 | 103 | ||
80 | /** | 104 | /** |
81 | * Packet processor responsible for forwarding packets along their paths. | 105 | * Packet processor responsible for forwarding packets along their paths. |
... | @@ -86,7 +110,7 @@ public class ReactiveForwarding { | ... | @@ -86,7 +110,7 @@ public class ReactiveForwarding { |
86 | public void process(PacketContext context) { | 110 | public void process(PacketContext context) { |
87 | // Stop processing if the packet has been handled, since we | 111 | // Stop processing if the packet has been handled, since we |
88 | // can't do any more to it. | 112 | // can't do any more to it. |
89 | - if (context.isHandled()) { | 113 | + if (!isEnabled || context.isHandled()) { |
90 | return; | 114 | return; |
91 | } | 115 | } |
92 | 116 | ||
... | @@ -185,7 +209,6 @@ public class ReactiveForwarding { | ... | @@ -185,7 +209,6 @@ public class ReactiveForwarding { |
185 | builder.build(), treat.build(), PRIORITY, appId, TIMEOUT); | 209 | builder.build(), treat.build(), PRIORITY, appId, TIMEOUT); |
186 | 210 | ||
187 | flowRuleService.applyFlowRules(f); | 211 | flowRuleService.applyFlowRules(f); |
188 | - | ||
189 | } | 212 | } |
190 | 213 | ||
191 | } | 214 | } | ... | ... |
... | @@ -25,6 +25,7 @@ | ... | @@ -25,6 +25,7 @@ |
25 | <module>proxyarp</module> | 25 | <module>proxyarp</module> |
26 | <module>config</module> | 26 | <module>config</module> |
27 | <module>sdnip</module> | 27 | <module>sdnip</module> |
28 | + <module>calendar</module> | ||
28 | </modules> | 29 | </modules> |
29 | 30 | ||
30 | <properties> | 31 | <properties> | ... | ... |
... | @@ -36,6 +36,36 @@ | ... | @@ -36,6 +36,36 @@ |
36 | <groupId>com.google.guava</groupId> | 36 | <groupId>com.google.guava</groupId> |
37 | <artifactId>guava</artifactId> | 37 | <artifactId>guava</artifactId> |
38 | </dependency> | 38 | </dependency> |
39 | + | ||
40 | + <dependency> | ||
41 | + <groupId>org.onlab.onos</groupId> | ||
42 | + <artifactId>onlab-thirdparty</artifactId> | ||
43 | + </dependency> | ||
44 | + | ||
45 | + <dependency> | ||
46 | + <groupId>org.onlab.onos</groupId> | ||
47 | + <artifactId>onlab-misc</artifactId> | ||
48 | + </dependency> | ||
49 | + | ||
50 | + <dependency> | ||
51 | + <groupId>org.onlab.onos</groupId> | ||
52 | + <artifactId>onos-cli</artifactId> | ||
53 | + <version>${project.version}</version> | ||
54 | + </dependency> | ||
55 | + <dependency> | ||
56 | + <groupId>org.apache.karaf.shell</groupId> | ||
57 | + <artifactId>org.apache.karaf.shell.console</artifactId> | ||
58 | + </dependency> | ||
59 | + <dependency> | ||
60 | + <groupId>org.osgi</groupId> | ||
61 | + <artifactId>org.osgi.core</artifactId> | ||
62 | + </dependency> | ||
63 | + | ||
64 | + <dependency> | ||
65 | + <groupId>org.easymock</groupId> | ||
66 | + <artifactId>easymock</artifactId> | ||
67 | + <scope>test</scope> | ||
68 | + </dependency> | ||
39 | </dependencies> | 69 | </dependencies> |
40 | 70 | ||
41 | </project> | 71 | </project> | ... | ... |
... | @@ -126,8 +126,8 @@ public class PeerConnectivity { | ... | @@ -126,8 +126,8 @@ public class PeerConnectivity { |
126 | TrafficSelector selector = DefaultTrafficSelector.builder() | 126 | TrafficSelector selector = DefaultTrafficSelector.builder() |
127 | .matchEthType(Ethernet.TYPE_IPV4) | 127 | .matchEthType(Ethernet.TYPE_IPV4) |
128 | .matchIPProtocol(IPv4.PROTOCOL_TCP) | 128 | .matchIPProtocol(IPv4.PROTOCOL_TCP) |
129 | - .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH)) | 129 | + .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH)) |
130 | - .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH)) | 130 | + .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH)) |
131 | .matchTcpDst(BGP_PORT) | 131 | .matchTcpDst(BGP_PORT) |
132 | .build(); | 132 | .build(); |
133 | 133 | ||
... | @@ -147,8 +147,8 @@ public class PeerConnectivity { | ... | @@ -147,8 +147,8 @@ public class PeerConnectivity { |
147 | selector = DefaultTrafficSelector.builder() | 147 | selector = DefaultTrafficSelector.builder() |
148 | .matchEthType(Ethernet.TYPE_IPV4) | 148 | .matchEthType(Ethernet.TYPE_IPV4) |
149 | .matchIPProtocol(IPv4.PROTOCOL_TCP) | 149 | .matchIPProtocol(IPv4.PROTOCOL_TCP) |
150 | - .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH)) | 150 | + .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH)) |
151 | - .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH)) | 151 | + .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH)) |
152 | .matchTcpSrc(BGP_PORT) | 152 | .matchTcpSrc(BGP_PORT) |
153 | .build(); | 153 | .build(); |
154 | 154 | ||
... | @@ -165,8 +165,8 @@ public class PeerConnectivity { | ... | @@ -165,8 +165,8 @@ public class PeerConnectivity { |
165 | selector = DefaultTrafficSelector.builder() | 165 | selector = DefaultTrafficSelector.builder() |
166 | .matchEthType(Ethernet.TYPE_IPV4) | 166 | .matchEthType(Ethernet.TYPE_IPV4) |
167 | .matchIPProtocol(IPv4.PROTOCOL_TCP) | 167 | .matchIPProtocol(IPv4.PROTOCOL_TCP) |
168 | - .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH)) | 168 | + .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH)) |
169 | - .matchIPDst(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH)) | 169 | + .matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH)) |
170 | .matchTcpDst(BGP_PORT) | 170 | .matchTcpDst(BGP_PORT) |
171 | .build(); | 171 | .build(); |
172 | 172 | ||
... | @@ -183,8 +183,8 @@ public class PeerConnectivity { | ... | @@ -183,8 +183,8 @@ public class PeerConnectivity { |
183 | selector = DefaultTrafficSelector.builder() | 183 | selector = DefaultTrafficSelector.builder() |
184 | .matchEthType(Ethernet.TYPE_IPV4) | 184 | .matchEthType(Ethernet.TYPE_IPV4) |
185 | .matchIPProtocol(IPv4.PROTOCOL_TCP) | 185 | .matchIPProtocol(IPv4.PROTOCOL_TCP) |
186 | - .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH)) | 186 | + .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH)) |
187 | - .matchIPDst(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH)) | 187 | + .matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH)) |
188 | .matchTcpSrc(BGP_PORT) | 188 | .matchTcpSrc(BGP_PORT) |
189 | .build(); | 189 | .build(); |
190 | 190 | ||
... | @@ -251,8 +251,8 @@ public class PeerConnectivity { | ... | @@ -251,8 +251,8 @@ public class PeerConnectivity { |
251 | TrafficSelector selector = DefaultTrafficSelector.builder() | 251 | TrafficSelector selector = DefaultTrafficSelector.builder() |
252 | .matchEthType(Ethernet.TYPE_IPV4) | 252 | .matchEthType(Ethernet.TYPE_IPV4) |
253 | .matchIPProtocol(IPv4.PROTOCOL_ICMP) | 253 | .matchIPProtocol(IPv4.PROTOCOL_ICMP) |
254 | - .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH)) | 254 | + .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH)) |
255 | - .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH)) | 255 | + .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH)) |
256 | .build(); | 256 | .build(); |
257 | 257 | ||
258 | TrafficTreatment treatment = DefaultTrafficTreatment.builder() | 258 | TrafficTreatment treatment = DefaultTrafficTreatment.builder() |
... | @@ -269,8 +269,8 @@ public class PeerConnectivity { | ... | @@ -269,8 +269,8 @@ public class PeerConnectivity { |
269 | selector = DefaultTrafficSelector.builder() | 269 | selector = DefaultTrafficSelector.builder() |
270 | .matchEthType(Ethernet.TYPE_IPV4) | 270 | .matchEthType(Ethernet.TYPE_IPV4) |
271 | .matchIPProtocol(IPv4.PROTOCOL_ICMP) | 271 | .matchIPProtocol(IPv4.PROTOCOL_ICMP) |
272 | - .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toRealInt(), IPV4_BIT_LENGTH)) | 272 | + .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH)) |
273 | - .matchIPDst(IpPrefix.valueOf(bgpdAddress.toRealInt(), IPV4_BIT_LENGTH)) | 273 | + .matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH)) |
274 | .build(); | 274 | .build(); |
275 | 275 | ||
276 | PointToPointIntent reversedIntent = new PointToPointIntent( | 276 | PointToPointIntent reversedIntent = new PointToPointIntent( | ... | ... |
1 | +package org.onlab.onos.sdnip; | ||
2 | + | ||
3 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
4 | + | ||
5 | +import java.util.Objects; | ||
6 | + | ||
7 | +import org.onlab.packet.IpAddress; | ||
8 | +import org.onlab.packet.IpPrefix; | ||
9 | + | ||
10 | +import com.google.common.base.MoreObjects; | ||
11 | + | ||
12 | +/** | ||
13 | + * Represents a route entry for an IP prefix. | ||
14 | + */ | ||
15 | +public class RouteEntry { | ||
16 | + private final IpPrefix prefix; // The IP prefix | ||
17 | + private final IpAddress nextHop; // Next-hop IP address | ||
18 | + | ||
19 | + /** | ||
20 | + * Class constructor. | ||
21 | + * | ||
22 | + * @param prefix the IP prefix of the route | ||
23 | + * @param nextHop the next hop IP address for the route | ||
24 | + */ | ||
25 | + public RouteEntry(IpPrefix prefix, IpAddress nextHop) { | ||
26 | + this.prefix = checkNotNull(prefix); | ||
27 | + this.nextHop = checkNotNull(nextHop); | ||
28 | + } | ||
29 | + | ||
30 | + /** | ||
31 | + * Returns the IP prefix of the route. | ||
32 | + * | ||
33 | + * @return the IP prefix of the route | ||
34 | + */ | ||
35 | + public IpPrefix prefix() { | ||
36 | + return prefix; | ||
37 | + } | ||
38 | + | ||
39 | + /** | ||
40 | + * Returns the next hop IP address for the route. | ||
41 | + * | ||
42 | + * @return the next hop IP address for the route | ||
43 | + */ | ||
44 | + public IpAddress nextHop() { | ||
45 | + return nextHop; | ||
46 | + } | ||
47 | + | ||
48 | + /** | ||
49 | + * Creates the binary string representation of an IPv4 prefix. | ||
50 | + * The string length is equal to the prefix length. | ||
51 | + * | ||
52 | + * @param ip4Prefix the IPv4 prefix to use | ||
53 | + * @return the binary string representation | ||
54 | + */ | ||
55 | + static String createBinaryString(IpPrefix ip4Prefix) { | ||
56 | + if (ip4Prefix.prefixLength() == 0) { | ||
57 | + return ""; | ||
58 | + } | ||
59 | + | ||
60 | + StringBuilder result = new StringBuilder(ip4Prefix.prefixLength()); | ||
61 | + long value = ip4Prefix.toInt(); | ||
62 | + for (int i = 0; i < ip4Prefix.prefixLength(); i++) { | ||
63 | + long mask = 1 << (IpAddress.MAX_INET_MASK - 1 - i); | ||
64 | + result.append(((value & mask) == 0) ? "0" : "1"); | ||
65 | + } | ||
66 | + return result.toString(); | ||
67 | + } | ||
68 | + | ||
69 | + @Override | ||
70 | + public boolean equals(Object other) { | ||
71 | + if (this == other) { | ||
72 | + return true; | ||
73 | + } | ||
74 | + | ||
75 | + // | ||
76 | + // NOTE: Subclasses are considered as change of identity, hence | ||
77 | + // equals() will return false if the class type doesn't match. | ||
78 | + // | ||
79 | + if (other == null || getClass() != other.getClass()) { | ||
80 | + return false; | ||
81 | + } | ||
82 | + | ||
83 | + RouteEntry otherRoute = (RouteEntry) other; | ||
84 | + return Objects.equals(this.prefix, otherRoute.prefix) && | ||
85 | + Objects.equals(this.nextHop, otherRoute.nextHop); | ||
86 | + } | ||
87 | + | ||
88 | + @Override | ||
89 | + public int hashCode() { | ||
90 | + return Objects.hash(prefix, nextHop); | ||
91 | + } | ||
92 | + | ||
93 | + @Override | ||
94 | + public String toString() { | ||
95 | + return MoreObjects.toStringHelper(getClass()) | ||
96 | + .add("prefix", prefix) | ||
97 | + .add("nextHop", nextHop) | ||
98 | + .toString(); | ||
99 | + } | ||
100 | +} |
1 | +package org.onlab.onos.sdnip; | ||
2 | + | ||
3 | +/** | ||
4 | + * An interface to receive route updates from route providers. | ||
5 | + */ | ||
6 | +public interface RouteListener { | ||
7 | + /** | ||
8 | + * Receives a route update from a route provider. | ||
9 | + * | ||
10 | + * @param routeUpdate the updated route information | ||
11 | + */ | ||
12 | + public void update(RouteUpdate routeUpdate); | ||
13 | +} |
1 | +package org.onlab.onos.sdnip; | ||
2 | + | ||
3 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
4 | + | ||
5 | +import java.util.Objects; | ||
6 | + | ||
7 | +import com.google.common.base.MoreObjects; | ||
8 | + | ||
9 | +/** | ||
10 | + * Represents a change in routing information. | ||
11 | + */ | ||
12 | +public class RouteUpdate { | ||
13 | + private final Type type; // The route update type | ||
14 | + private final RouteEntry routeEntry; // The updated route entry | ||
15 | + | ||
16 | + /** | ||
17 | + * Specifies the type of a route update. | ||
18 | + * <p/> | ||
19 | + * Route updates can either provide updated information for a route, or | ||
20 | + * withdraw a previously updated route. | ||
21 | + */ | ||
22 | + public enum Type { | ||
23 | + /** | ||
24 | + * The update contains updated route information for a route. | ||
25 | + */ | ||
26 | + UPDATE, | ||
27 | + /** | ||
28 | + * The update withdraws the route, meaning any previous information is | ||
29 | + * no longer valid. | ||
30 | + */ | ||
31 | + DELETE | ||
32 | + } | ||
33 | + | ||
34 | + /** | ||
35 | + * Class constructor. | ||
36 | + * | ||
37 | + * @param type the type of the route update | ||
38 | + * @param routeEntry the route entry with the update | ||
39 | + */ | ||
40 | + public RouteUpdate(Type type, RouteEntry routeEntry) { | ||
41 | + this.type = type; | ||
42 | + this.routeEntry = checkNotNull(routeEntry); | ||
43 | + } | ||
44 | + | ||
45 | + /** | ||
46 | + * Returns the type of the route update. | ||
47 | + * | ||
48 | + * @return the type of the update | ||
49 | + */ | ||
50 | + public Type type() { | ||
51 | + return type; | ||
52 | + } | ||
53 | + | ||
54 | + /** | ||
55 | + * Returns the route entry the route update is for. | ||
56 | + * | ||
57 | + * @return the route entry the route update is for | ||
58 | + */ | ||
59 | + public RouteEntry routeEntry() { | ||
60 | + return routeEntry; | ||
61 | + } | ||
62 | + | ||
63 | + @Override | ||
64 | + public boolean equals(Object other) { | ||
65 | + if (other == this) { | ||
66 | + return true; | ||
67 | + } | ||
68 | + | ||
69 | + if (!(other instanceof RouteUpdate)) { | ||
70 | + return false; | ||
71 | + } | ||
72 | + | ||
73 | + RouteUpdate otherUpdate = (RouteUpdate) other; | ||
74 | + | ||
75 | + return Objects.equals(this.type, otherUpdate.type) && | ||
76 | + Objects.equals(this.routeEntry, otherUpdate.routeEntry); | ||
77 | + } | ||
78 | + | ||
79 | + @Override | ||
80 | + public int hashCode() { | ||
81 | + return Objects.hash(type, routeEntry); | ||
82 | + } | ||
83 | + | ||
84 | + @Override | ||
85 | + public String toString() { | ||
86 | + return MoreObjects.toStringHelper(getClass()) | ||
87 | + .add("type", type) | ||
88 | + .add("routeEntry", routeEntry) | ||
89 | + .toString(); | ||
90 | + } | ||
91 | +} |
This diff is collapsed. Click to expand it.
... | @@ -2,21 +2,30 @@ package org.onlab.onos.sdnip; | ... | @@ -2,21 +2,30 @@ package org.onlab.onos.sdnip; |
2 | 2 | ||
3 | import static org.slf4j.LoggerFactory.getLogger; | 3 | import static org.slf4j.LoggerFactory.getLogger; |
4 | 4 | ||
5 | +import java.util.Collection; | ||
6 | + | ||
5 | import org.apache.felix.scr.annotations.Activate; | 7 | import org.apache.felix.scr.annotations.Activate; |
6 | import org.apache.felix.scr.annotations.Component; | 8 | import org.apache.felix.scr.annotations.Component; |
7 | import org.apache.felix.scr.annotations.Deactivate; | 9 | import org.apache.felix.scr.annotations.Deactivate; |
8 | import org.apache.felix.scr.annotations.Reference; | 10 | import org.apache.felix.scr.annotations.Reference; |
9 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 11 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
12 | +import org.apache.felix.scr.annotations.Service; | ||
10 | import org.onlab.onos.net.host.HostService; | 13 | import org.onlab.onos.net.host.HostService; |
11 | import org.onlab.onos.net.intent.IntentService; | 14 | import org.onlab.onos.net.intent.IntentService; |
15 | +import org.onlab.onos.sdnip.RouteUpdate.Type; | ||
16 | +import org.onlab.onos.sdnip.bgp.BgpRouteEntry; | ||
17 | +import org.onlab.onos.sdnip.bgp.BgpSessionManager; | ||
12 | import org.onlab.onos.sdnip.config.SdnIpConfigReader; | 18 | import org.onlab.onos.sdnip.config.SdnIpConfigReader; |
19 | +import org.onlab.packet.IpAddress; | ||
20 | +import org.onlab.packet.IpPrefix; | ||
13 | import org.slf4j.Logger; | 21 | import org.slf4j.Logger; |
14 | 22 | ||
15 | /** | 23 | /** |
16 | - * Placeholder SDN-IP component. | 24 | + * Component for the SDN-IP peering application. |
17 | */ | 25 | */ |
18 | @Component(immediate = true) | 26 | @Component(immediate = true) |
19 | -public class SdnIp { | 27 | +@Service |
28 | +public class SdnIp implements SdnIpService { | ||
20 | 29 | ||
21 | private final Logger log = getLogger(getClass()); | 30 | private final Logger log = getLogger(getClass()); |
22 | 31 | ||
... | @@ -28,6 +37,8 @@ public class SdnIp { | ... | @@ -28,6 +37,8 @@ public class SdnIp { |
28 | 37 | ||
29 | private SdnIpConfigReader config; | 38 | private SdnIpConfigReader config; |
30 | private PeerConnectivity peerConnectivity; | 39 | private PeerConnectivity peerConnectivity; |
40 | + private Router router; | ||
41 | + private BgpSessionManager bgpSessionManager; | ||
31 | 42 | ||
32 | @Activate | 43 | @Activate |
33 | protected void activate() { | 44 | protected void activate() { |
... | @@ -41,10 +52,31 @@ public class SdnIp { | ... | @@ -41,10 +52,31 @@ public class SdnIp { |
41 | peerConnectivity = new PeerConnectivity(config, interfaceService, intentService); | 52 | peerConnectivity = new PeerConnectivity(config, interfaceService, intentService); |
42 | peerConnectivity.start(); | 53 | peerConnectivity.start(); |
43 | 54 | ||
55 | + router = new Router(intentService, hostService, config, interfaceService); | ||
56 | + router.start(); | ||
57 | + | ||
58 | + bgpSessionManager = new BgpSessionManager(router); | ||
59 | + bgpSessionManager.startUp(2000); // TODO | ||
60 | + | ||
61 | + // TODO need to disable link discovery on external ports | ||
62 | + | ||
63 | + router.update(new RouteUpdate(Type.UPDATE, new RouteEntry( | ||
64 | + IpPrefix.valueOf("172.16.20.0/24"), | ||
65 | + IpAddress.valueOf("192.168.10.1")))); | ||
44 | } | 66 | } |
45 | 67 | ||
46 | @Deactivate | 68 | @Deactivate |
47 | protected void deactivate() { | 69 | protected void deactivate() { |
48 | log.info("Stopped"); | 70 | log.info("Stopped"); |
49 | } | 71 | } |
72 | + | ||
73 | + @Override | ||
74 | + public Collection<BgpRouteEntry> getBgpRoutes() { | ||
75 | + return bgpSessionManager.getBgpRoutes(); | ||
76 | + } | ||
77 | + | ||
78 | + @Override | ||
79 | + public Collection<RouteEntry> getRoutes() { | ||
80 | + return router.getRoutes(); | ||
81 | + } | ||
50 | } | 82 | } | ... | ... |
1 | +package org.onlab.onos.sdnip; | ||
2 | + | ||
3 | +import java.util.Collection; | ||
4 | + | ||
5 | +import org.onlab.onos.sdnip.bgp.BgpRouteEntry; | ||
6 | + | ||
7 | +/** | ||
8 | + * Service interface exported by SDN-IP. | ||
9 | + */ | ||
10 | +public interface SdnIpService { | ||
11 | + /** | ||
12 | + * Gets the BGP routes. | ||
13 | + * | ||
14 | + * @return the BGP routes | ||
15 | + */ | ||
16 | + public Collection<BgpRouteEntry> getBgpRoutes(); | ||
17 | + | ||
18 | + /** | ||
19 | + * Gets all the routes known to SDN-IP. | ||
20 | + * | ||
21 | + * @return the SDN-IP routes | ||
22 | + */ | ||
23 | + public Collection<RouteEntry> getRoutes(); | ||
24 | +} |
This diff is collapsed. Click to expand it.
1 | +package org.onlab.onos.sdnip.bgp; | ||
2 | + | ||
3 | +import org.jboss.netty.buffer.ChannelBuffer; | ||
4 | +import org.jboss.netty.buffer.ChannelBuffers; | ||
5 | +import org.jboss.netty.channel.Channel; | ||
6 | +import org.jboss.netty.channel.ChannelHandlerContext; | ||
7 | +import org.jboss.netty.handler.codec.frame.FrameDecoder; | ||
8 | +import org.onlab.onos.sdnip.bgp.BgpConstants.Notifications.MessageHeaderError; | ||
9 | +import org.slf4j.Logger; | ||
10 | +import org.slf4j.LoggerFactory; | ||
11 | + | ||
12 | +/** | ||
13 | + * Class for handling the decoding of the BGP messages. | ||
14 | + */ | ||
15 | +class BgpFrameDecoder extends FrameDecoder { | ||
16 | + private static final Logger log = | ||
17 | + LoggerFactory.getLogger(BgpFrameDecoder.class); | ||
18 | + | ||
19 | + private final BgpSession bgpSession; | ||
20 | + | ||
21 | + /** | ||
22 | + * Constructor for a given BGP Session. | ||
23 | + * | ||
24 | + * @param bgpSession the BGP session state to use. | ||
25 | + */ | ||
26 | + BgpFrameDecoder(BgpSession bgpSession) { | ||
27 | + this.bgpSession = bgpSession; | ||
28 | + } | ||
29 | + | ||
30 | + @Override | ||
31 | + protected Object decode(ChannelHandlerContext ctx, | ||
32 | + Channel channel, | ||
33 | + ChannelBuffer buf) throws Exception { | ||
34 | + // | ||
35 | + // NOTE: If we close the channel during the decoding, we might still | ||
36 | + // see some incoming messages while the channel closing is completed. | ||
37 | + // | ||
38 | + if (bgpSession.isClosed()) { | ||
39 | + return null; | ||
40 | + } | ||
41 | + | ||
42 | + log.trace("BGP Peer: decode(): remoteAddr = {} localAddr = {} " + | ||
43 | + "messageSize = {}", | ||
44 | + ctx.getChannel().getRemoteAddress(), | ||
45 | + ctx.getChannel().getLocalAddress(), | ||
46 | + buf.readableBytes()); | ||
47 | + | ||
48 | + // Test for minimum length of the BGP message | ||
49 | + if (buf.readableBytes() < BgpConstants.BGP_HEADER_LENGTH) { | ||
50 | + // No enough data received | ||
51 | + return null; | ||
52 | + } | ||
53 | + | ||
54 | + // | ||
55 | + // Mark the current buffer position in case we haven't received | ||
56 | + // the whole message. | ||
57 | + // | ||
58 | + buf.markReaderIndex(); | ||
59 | + | ||
60 | + // | ||
61 | + // Read and check the BGP message Marker field: it must be all ones | ||
62 | + // (See RFC 4271, Section 4.1) | ||
63 | + // | ||
64 | + byte[] marker = new byte[BgpConstants.BGP_HEADER_MARKER_LENGTH]; | ||
65 | + buf.readBytes(marker); | ||
66 | + for (int i = 0; i < marker.length; i++) { | ||
67 | + if (marker[i] != (byte) 0xff) { | ||
68 | + log.debug("BGP RX Error: invalid marker {} at position {}", | ||
69 | + marker[i], i); | ||
70 | + // | ||
71 | + // ERROR: Connection Not Synchronized | ||
72 | + // | ||
73 | + // Send NOTIFICATION and close the connection | ||
74 | + int errorCode = MessageHeaderError.ERROR_CODE; | ||
75 | + int errorSubcode = | ||
76 | + MessageHeaderError.CONNECTION_NOT_SYNCHRONIZED; | ||
77 | + ChannelBuffer txMessage = | ||
78 | + bgpSession.prepareBgpNotification(errorCode, errorSubcode, | ||
79 | + null); | ||
80 | + ctx.getChannel().write(txMessage); | ||
81 | + bgpSession.closeChannel(ctx); | ||
82 | + return null; | ||
83 | + } | ||
84 | + } | ||
85 | + | ||
86 | + // | ||
87 | + // Read and check the BGP message Length field | ||
88 | + // | ||
89 | + int length = buf.readUnsignedShort(); | ||
90 | + if ((length < BgpConstants.BGP_HEADER_LENGTH) || | ||
91 | + (length > BgpConstants.BGP_MESSAGE_MAX_LENGTH)) { | ||
92 | + log.debug("BGP RX Error: invalid Length field {}. " + | ||
93 | + "Must be between {} and {}", | ||
94 | + length, | ||
95 | + BgpConstants.BGP_HEADER_LENGTH, | ||
96 | + BgpConstants.BGP_MESSAGE_MAX_LENGTH); | ||
97 | + // | ||
98 | + // ERROR: Bad Message Length | ||
99 | + // | ||
100 | + // Send NOTIFICATION and close the connection | ||
101 | + ChannelBuffer txMessage = | ||
102 | + bgpSession.prepareBgpNotificationBadMessageLength(length); | ||
103 | + ctx.getChannel().write(txMessage); | ||
104 | + bgpSession.closeChannel(ctx); | ||
105 | + return null; | ||
106 | + } | ||
107 | + | ||
108 | + // | ||
109 | + // Test whether the rest of the message is received: | ||
110 | + // So far we have read the Marker (16 octets) and the | ||
111 | + // Length (2 octets) fields. | ||
112 | + // | ||
113 | + int remainingMessageLen = | ||
114 | + length - BgpConstants.BGP_HEADER_MARKER_LENGTH - 2; | ||
115 | + if (buf.readableBytes() < remainingMessageLen) { | ||
116 | + // No enough data received | ||
117 | + buf.resetReaderIndex(); | ||
118 | + return null; | ||
119 | + } | ||
120 | + | ||
121 | + // | ||
122 | + // Read the BGP message Type field, and process based on that type | ||
123 | + // | ||
124 | + int type = buf.readUnsignedByte(); | ||
125 | + remainingMessageLen--; // Adjust after reading the type | ||
126 | + ChannelBuffer message = buf.readBytes(remainingMessageLen); | ||
127 | + | ||
128 | + // | ||
129 | + // Process the remaining of the message based on the message type | ||
130 | + // | ||
131 | + switch (type) { | ||
132 | + case BgpConstants.BGP_TYPE_OPEN: | ||
133 | + bgpSession.processBgpOpen(ctx, message); | ||
134 | + break; | ||
135 | + case BgpConstants.BGP_TYPE_UPDATE: | ||
136 | + bgpSession.processBgpUpdate(ctx, message); | ||
137 | + break; | ||
138 | + case BgpConstants.BGP_TYPE_NOTIFICATION: | ||
139 | + bgpSession.processBgpNotification(ctx, message); | ||
140 | + break; | ||
141 | + case BgpConstants.BGP_TYPE_KEEPALIVE: | ||
142 | + bgpSession.processBgpKeepalive(ctx, message); | ||
143 | + break; | ||
144 | + default: | ||
145 | + // | ||
146 | + // ERROR: Bad Message Type | ||
147 | + // | ||
148 | + // Send NOTIFICATION and close the connection | ||
149 | + int errorCode = MessageHeaderError.ERROR_CODE; | ||
150 | + int errorSubcode = MessageHeaderError.BAD_MESSAGE_TYPE; | ||
151 | + ChannelBuffer data = ChannelBuffers.buffer(1); | ||
152 | + data.writeByte(type); | ||
153 | + ChannelBuffer txMessage = | ||
154 | + bgpSession.prepareBgpNotification(errorCode, errorSubcode, | ||
155 | + data); | ||
156 | + ctx.getChannel().write(txMessage); | ||
157 | + bgpSession.closeChannel(ctx); | ||
158 | + return null; | ||
159 | + } | ||
160 | + return null; | ||
161 | + } | ||
162 | +} |
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
1 | +package org.onlab.onos.sdnip.cli; | ||
2 | + | ||
3 | +import org.apache.karaf.shell.commands.Command; | ||
4 | +import org.onlab.onos.cli.AbstractShellCommand; | ||
5 | +import org.onlab.onos.sdnip.SdnIpService; | ||
6 | +import org.onlab.onos.sdnip.bgp.BgpConstants; | ||
7 | +import org.onlab.onos.sdnip.bgp.BgpRouteEntry; | ||
8 | + | ||
9 | +/** | ||
10 | + * Command to show the routes learned through BGP. | ||
11 | + */ | ||
12 | +@Command(scope = "onos", name = "bgp-routes", | ||
13 | + description = "Lists all routes received from BGP") | ||
14 | +public class BgpRoutesListCommand extends AbstractShellCommand { | ||
15 | + | ||
16 | + private static final String FORMAT = | ||
17 | + "prefix=%s, nexthop=%s, origin=%s, localpref=%s, med=%s, aspath=%s, bgpid=%s"; | ||
18 | + | ||
19 | + @Override | ||
20 | + protected void execute() { | ||
21 | + SdnIpService service = get(SdnIpService.class); | ||
22 | + | ||
23 | + for (BgpRouteEntry route : service.getBgpRoutes()) { | ||
24 | + printRoute(route); | ||
25 | + } | ||
26 | + } | ||
27 | + | ||
28 | + private void printRoute(BgpRouteEntry route) { | ||
29 | + if (route != null) { | ||
30 | + print(FORMAT, route.prefix(), route.nextHop(), | ||
31 | + originToString(route.getOrigin()), route.getLocalPref(), | ||
32 | + route.getMultiExitDisc(), route.getAsPath(), | ||
33 | + route.getBgpSession().getRemoteBgpId()); | ||
34 | + } | ||
35 | + } | ||
36 | + | ||
37 | + private static String originToString(int origin) { | ||
38 | + String originString = "UNKNOWN"; | ||
39 | + | ||
40 | + switch (origin) { | ||
41 | + case BgpConstants.Update.Origin.IGP: | ||
42 | + originString = "IGP"; | ||
43 | + break; | ||
44 | + case BgpConstants.Update.Origin.EGP: | ||
45 | + originString = "EGP"; | ||
46 | + break; | ||
47 | + case BgpConstants.Update.Origin.INCOMPLETE: | ||
48 | + originString = "INCOMPLETE"; | ||
49 | + break; | ||
50 | + default: | ||
51 | + break; | ||
52 | + } | ||
53 | + | ||
54 | + return originString; | ||
55 | + } | ||
56 | + | ||
57 | +} |
1 | +package org.onlab.onos.sdnip.cli; | ||
2 | + | ||
3 | +import org.apache.karaf.shell.commands.Command; | ||
4 | +import org.onlab.onos.cli.AbstractShellCommand; | ||
5 | +import org.onlab.onos.sdnip.RouteEntry; | ||
6 | +import org.onlab.onos.sdnip.SdnIpService; | ||
7 | + | ||
8 | +/** | ||
9 | + * Command to show the list of routes in SDN-IP's routing table. | ||
10 | + */ | ||
11 | +@Command(scope = "onos", name = "routes", | ||
12 | + description = "Lists all routes known to SDN-IP") | ||
13 | +public class RoutesListCommand extends AbstractShellCommand { | ||
14 | + | ||
15 | + private static final String FORMAT = | ||
16 | + "prefix=%s, nexthop=%s"; | ||
17 | + | ||
18 | + @Override | ||
19 | + protected void execute() { | ||
20 | + SdnIpService service = get(SdnIpService.class); | ||
21 | + | ||
22 | + for (RouteEntry route : service.getRoutes()) { | ||
23 | + printRoute(route); | ||
24 | + } | ||
25 | + } | ||
26 | + | ||
27 | + private void printRoute(RouteEntry route) { | ||
28 | + if (route != null) { | ||
29 | + print(FORMAT, route.prefix(), route.nextHop()); | ||
30 | + } | ||
31 | + } | ||
32 | +} |
1 | +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"> | ||
2 | + | ||
3 | + <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0"> | ||
4 | + <command> | ||
5 | + <action class="org.onlab.onos.sdnip.cli.BgpRoutesListCommand"/> | ||
6 | + </command> | ||
7 | + <command> | ||
8 | + <action class="org.onlab.onos.sdnip.cli.RoutesListCommand"/> | ||
9 | + </command> | ||
10 | + </command-bundle> | ||
11 | +</blueprint> |
1 | +package org.onlab.onos.sdnip; | ||
2 | + | ||
3 | +import static org.hamcrest.Matchers.is; | ||
4 | +import static org.hamcrest.Matchers.not; | ||
5 | +import static org.junit.Assert.assertThat; | ||
6 | + | ||
7 | +import org.junit.Test; | ||
8 | +import org.onlab.packet.IpAddress; | ||
9 | +import org.onlab.packet.IpPrefix; | ||
10 | + | ||
11 | +/** | ||
12 | + * Unit tests for the RouteEntry class. | ||
13 | + */ | ||
14 | +public class RouteEntryTest { | ||
15 | + /** | ||
16 | + * Tests valid class constructor. | ||
17 | + */ | ||
18 | + @Test | ||
19 | + public void testConstructor() { | ||
20 | + IpPrefix prefix = IpPrefix.valueOf("1.2.3.0/24"); | ||
21 | + IpAddress nextHop = IpAddress.valueOf("5.6.7.8"); | ||
22 | + | ||
23 | + RouteEntry routeEntry = new RouteEntry(prefix, nextHop); | ||
24 | + assertThat(routeEntry.toString(), | ||
25 | + is("RouteEntry{prefix=1.2.3.0/24, nextHop=5.6.7.8}")); | ||
26 | + } | ||
27 | + | ||
28 | + /** | ||
29 | + * Tests invalid class constructor for null IPv4 prefix. | ||
30 | + */ | ||
31 | + @Test(expected = NullPointerException.class) | ||
32 | + public void testInvalidConstructorNullPrefix() { | ||
33 | + IpPrefix prefix = null; | ||
34 | + IpAddress nextHop = IpAddress.valueOf("5.6.7.8"); | ||
35 | + | ||
36 | + new RouteEntry(prefix, nextHop); | ||
37 | + } | ||
38 | + | ||
39 | + /** | ||
40 | + * Tests invalid class constructor for null IPv4 next-hop. | ||
41 | + */ | ||
42 | + @Test(expected = NullPointerException.class) | ||
43 | + public void testInvalidConstructorNullNextHop() { | ||
44 | + IpPrefix prefix = IpPrefix.valueOf("1.2.3.0/24"); | ||
45 | + IpAddress nextHop = null; | ||
46 | + | ||
47 | + new RouteEntry(prefix, nextHop); | ||
48 | + } | ||
49 | + | ||
50 | + /** | ||
51 | + * Tests getting the fields of a route entry. | ||
52 | + */ | ||
53 | + @Test | ||
54 | + public void testGetFields() { | ||
55 | + IpPrefix prefix = IpPrefix.valueOf("1.2.3.0/24"); | ||
56 | + IpAddress nextHop = IpAddress.valueOf("5.6.7.8"); | ||
57 | + | ||
58 | + RouteEntry routeEntry = new RouteEntry(prefix, nextHop); | ||
59 | + assertThat(routeEntry.prefix(), is(prefix)); | ||
60 | + assertThat(routeEntry.nextHop(), is(nextHop)); | ||
61 | + } | ||
62 | + | ||
63 | + /** | ||
64 | + * Tests creating a binary string from IPv4 prefix. | ||
65 | + */ | ||
66 | + @Test | ||
67 | + public void testCreateBinaryString() { | ||
68 | + IpPrefix prefix; | ||
69 | + | ||
70 | + prefix = IpPrefix.valueOf("0.0.0.0/0"); | ||
71 | + assertThat(RouteEntry.createBinaryString(prefix), is("")); | ||
72 | + | ||
73 | + prefix = IpPrefix.valueOf("192.168.166.0/22"); | ||
74 | + assertThat(RouteEntry.createBinaryString(prefix), | ||
75 | + is("1100000010101000101001")); | ||
76 | + | ||
77 | + prefix = IpPrefix.valueOf("192.168.166.0/23"); | ||
78 | + assertThat(RouteEntry.createBinaryString(prefix), | ||
79 | + is("11000000101010001010011")); | ||
80 | + | ||
81 | + prefix = IpPrefix.valueOf("192.168.166.0/24"); | ||
82 | + assertThat(RouteEntry.createBinaryString(prefix), | ||
83 | + is("110000001010100010100110")); | ||
84 | + | ||
85 | + prefix = IpPrefix.valueOf("130.162.10.1/25"); | ||
86 | + assertThat(RouteEntry.createBinaryString(prefix), | ||
87 | + is("1000001010100010000010100")); | ||
88 | + | ||
89 | + prefix = IpPrefix.valueOf("255.255.255.255/32"); | ||
90 | + assertThat(RouteEntry.createBinaryString(prefix), | ||
91 | + is("11111111111111111111111111111111")); | ||
92 | + } | ||
93 | + | ||
94 | + /** | ||
95 | + * Tests equality of {@link RouteEntry}. | ||
96 | + */ | ||
97 | + @Test | ||
98 | + public void testEquality() { | ||
99 | + IpPrefix prefix1 = IpPrefix.valueOf("1.2.3.0/24"); | ||
100 | + IpAddress nextHop1 = IpAddress.valueOf("5.6.7.8"); | ||
101 | + RouteEntry routeEntry1 = new RouteEntry(prefix1, nextHop1); | ||
102 | + | ||
103 | + IpPrefix prefix2 = IpPrefix.valueOf("1.2.3.0/24"); | ||
104 | + IpAddress nextHop2 = IpAddress.valueOf("5.6.7.8"); | ||
105 | + RouteEntry routeEntry2 = new RouteEntry(prefix2, nextHop2); | ||
106 | + | ||
107 | + assertThat(routeEntry1, is(routeEntry2)); | ||
108 | + } | ||
109 | + | ||
110 | + /** | ||
111 | + * Tests non-equality of {@link RouteEntry}. | ||
112 | + */ | ||
113 | + @Test | ||
114 | + public void testNonEquality() { | ||
115 | + IpPrefix prefix1 = IpPrefix.valueOf("1.2.3.0/24"); | ||
116 | + IpAddress nextHop1 = IpAddress.valueOf("5.6.7.8"); | ||
117 | + RouteEntry routeEntry1 = new RouteEntry(prefix1, nextHop1); | ||
118 | + | ||
119 | + IpPrefix prefix2 = IpPrefix.valueOf("1.2.3.0/25"); // Different | ||
120 | + IpAddress nextHop2 = IpAddress.valueOf("5.6.7.8"); | ||
121 | + RouteEntry routeEntry2 = new RouteEntry(prefix2, nextHop2); | ||
122 | + | ||
123 | + IpPrefix prefix3 = IpPrefix.valueOf("1.2.3.0/24"); | ||
124 | + IpAddress nextHop3 = IpAddress.valueOf("5.6.7.9"); // Different | ||
125 | + RouteEntry routeEntry3 = new RouteEntry(prefix3, nextHop3); | ||
126 | + | ||
127 | + assertThat(routeEntry1, is(not(routeEntry2))); | ||
128 | + assertThat(routeEntry1, is(not(routeEntry3))); | ||
129 | + } | ||
130 | + | ||
131 | + /** | ||
132 | + * Tests object string representation. | ||
133 | + */ | ||
134 | + @Test | ||
135 | + public void testToString() { | ||
136 | + IpPrefix prefix = IpPrefix.valueOf("1.2.3.0/24"); | ||
137 | + IpAddress nextHop = IpAddress.valueOf("5.6.7.8"); | ||
138 | + RouteEntry routeEntry = new RouteEntry(prefix, nextHop); | ||
139 | + | ||
140 | + assertThat(routeEntry.toString(), | ||
141 | + is("RouteEntry{prefix=1.2.3.0/24, nextHop=5.6.7.8}")); | ||
142 | + } | ||
143 | +} |
1 | +package org.onlab.onos.sdnip.bgp; | ||
2 | + | ||
3 | +import static org.hamcrest.Matchers.is; | ||
4 | +import static org.hamcrest.Matchers.not; | ||
5 | +import static org.junit.Assert.assertThat; | ||
6 | + | ||
7 | +import java.util.ArrayList; | ||
8 | + | ||
9 | +import org.junit.Test; | ||
10 | + | ||
11 | +/** | ||
12 | + * Unit tests for the BgpRouteEntry.AsPath class. | ||
13 | + */ | ||
14 | +public class AsPathTest { | ||
15 | + /** | ||
16 | + * Generates an AS Path. | ||
17 | + * | ||
18 | + * @return a generated AS Path | ||
19 | + */ | ||
20 | + private BgpRouteEntry.AsPath generateAsPath() { | ||
21 | + ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>(); | ||
22 | + byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE; | ||
23 | + ArrayList<Long> segmentAsNumbers1 = new ArrayList<>(); | ||
24 | + segmentAsNumbers1.add((long) 1); | ||
25 | + segmentAsNumbers1.add((long) 2); | ||
26 | + segmentAsNumbers1.add((long) 3); | ||
27 | + BgpRouteEntry.PathSegment pathSegment1 = | ||
28 | + new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1); | ||
29 | + pathSegments.add(pathSegment1); | ||
30 | + // | ||
31 | + byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET; | ||
32 | + ArrayList<Long> segmentAsNumbers2 = new ArrayList<>(); | ||
33 | + segmentAsNumbers2.add((long) 4); | ||
34 | + segmentAsNumbers2.add((long) 5); | ||
35 | + segmentAsNumbers2.add((long) 6); | ||
36 | + BgpRouteEntry.PathSegment pathSegment2 = | ||
37 | + new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2); | ||
38 | + pathSegments.add(pathSegment2); | ||
39 | + // | ||
40 | + BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments); | ||
41 | + | ||
42 | + return asPath; | ||
43 | + } | ||
44 | + | ||
45 | + /** | ||
46 | + * Tests valid class constructor. | ||
47 | + */ | ||
48 | + @Test | ||
49 | + public void testConstructor() { | ||
50 | + BgpRouteEntry.AsPath asPath = generateAsPath(); | ||
51 | + | ||
52 | + String expectedString = | ||
53 | + "AsPath{pathSegments=" + | ||
54 | + "[PathSegment{type=2, segmentAsNumbers=[1, 2, 3]}, " + | ||
55 | + "PathSegment{type=1, segmentAsNumbers=[4, 5, 6]}]}"; | ||
56 | + assertThat(asPath.toString(), is(expectedString)); | ||
57 | + } | ||
58 | + | ||
59 | + /** | ||
60 | + * Tests invalid class constructor for null Path Segments. | ||
61 | + */ | ||
62 | + @Test(expected = NullPointerException.class) | ||
63 | + public void testInvalidConstructorNullPathSegments() { | ||
64 | + ArrayList<BgpRouteEntry.PathSegment> pathSegments = null; | ||
65 | + new BgpRouteEntry.AsPath(pathSegments); | ||
66 | + } | ||
67 | + | ||
68 | + /** | ||
69 | + * Tests getting the fields of an AS Path. | ||
70 | + */ | ||
71 | + @Test | ||
72 | + public void testGetFields() { | ||
73 | + // Create the fields to compare against | ||
74 | + ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>(); | ||
75 | + byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE; | ||
76 | + ArrayList<Long> segmentAsNumbers1 = new ArrayList<>(); | ||
77 | + segmentAsNumbers1.add((long) 1); | ||
78 | + segmentAsNumbers1.add((long) 2); | ||
79 | + segmentAsNumbers1.add((long) 3); | ||
80 | + BgpRouteEntry.PathSegment pathSegment1 = | ||
81 | + new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1); | ||
82 | + pathSegments.add(pathSegment1); | ||
83 | + // | ||
84 | + byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET; | ||
85 | + ArrayList<Long> segmentAsNumbers2 = new ArrayList<>(); | ||
86 | + segmentAsNumbers2.add((long) 4); | ||
87 | + segmentAsNumbers2.add((long) 5); | ||
88 | + segmentAsNumbers2.add((long) 6); | ||
89 | + BgpRouteEntry.PathSegment pathSegment2 = | ||
90 | + new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2); | ||
91 | + pathSegments.add(pathSegment2); | ||
92 | + | ||
93 | + // Generate the entry to test | ||
94 | + BgpRouteEntry.AsPath asPath = generateAsPath(); | ||
95 | + | ||
96 | + assertThat(asPath.getPathSegments(), is(pathSegments)); | ||
97 | + } | ||
98 | + | ||
99 | + /** | ||
100 | + * Tests getting the AS Path Length. | ||
101 | + */ | ||
102 | + @Test | ||
103 | + public void testGetAsPathLength() { | ||
104 | + BgpRouteEntry.AsPath asPath = generateAsPath(); | ||
105 | + assertThat(asPath.getAsPathLength(), is(4)); | ||
106 | + | ||
107 | + // Create an empty AS Path | ||
108 | + ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>(); | ||
109 | + asPath = new BgpRouteEntry.AsPath(pathSegments); | ||
110 | + assertThat(asPath.getAsPathLength(), is(0)); | ||
111 | + } | ||
112 | + | ||
113 | + /** | ||
114 | + * Tests equality of {@link BgpRouteEntry.AsPath}. | ||
115 | + */ | ||
116 | + @Test | ||
117 | + public void testEquality() { | ||
118 | + BgpRouteEntry.AsPath asPath1 = generateAsPath(); | ||
119 | + BgpRouteEntry.AsPath asPath2 = generateAsPath(); | ||
120 | + | ||
121 | + assertThat(asPath1, is(asPath2)); | ||
122 | + } | ||
123 | + | ||
124 | + /** | ||
125 | + * Tests non-equality of {@link BgpRouteEntry.AsPath}. | ||
126 | + */ | ||
127 | + @Test | ||
128 | + public void testNonEquality() { | ||
129 | + BgpRouteEntry.AsPath asPath1 = generateAsPath(); | ||
130 | + | ||
131 | + // Setup AS Path 2 | ||
132 | + ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>(); | ||
133 | + byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE; | ||
134 | + ArrayList<Long> segmentAsNumbers1 = new ArrayList<>(); | ||
135 | + segmentAsNumbers1.add((long) 1); | ||
136 | + segmentAsNumbers1.add((long) 2); | ||
137 | + segmentAsNumbers1.add((long) 3); | ||
138 | + BgpRouteEntry.PathSegment pathSegment1 = | ||
139 | + new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1); | ||
140 | + pathSegments.add(pathSegment1); | ||
141 | + // | ||
142 | + byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET; | ||
143 | + ArrayList<Long> segmentAsNumbers2 = new ArrayList<>(); | ||
144 | + segmentAsNumbers2.add((long) 4); | ||
145 | + segmentAsNumbers2.add((long) 55); // Different | ||
146 | + segmentAsNumbers2.add((long) 6); | ||
147 | + BgpRouteEntry.PathSegment pathSegment2 = | ||
148 | + new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2); | ||
149 | + pathSegments.add(pathSegment2); | ||
150 | + // | ||
151 | + BgpRouteEntry.AsPath asPath2 = new BgpRouteEntry.AsPath(pathSegments); | ||
152 | + | ||
153 | + assertThat(asPath1, is(not(asPath2))); | ||
154 | + } | ||
155 | + | ||
156 | + /** | ||
157 | + * Tests object string representation. | ||
158 | + */ | ||
159 | + @Test | ||
160 | + public void testToString() { | ||
161 | + BgpRouteEntry.AsPath asPath = generateAsPath(); | ||
162 | + | ||
163 | + String expectedString = | ||
164 | + "AsPath{pathSegments=" + | ||
165 | + "[PathSegment{type=2, segmentAsNumbers=[1, 2, 3]}, " + | ||
166 | + "PathSegment{type=1, segmentAsNumbers=[4, 5, 6]}]}"; | ||
167 | + assertThat(asPath.toString(), is(expectedString)); | ||
168 | + } | ||
169 | +} |
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
1 | +package org.onlab.onos.sdnip.bgp; | ||
2 | + | ||
3 | +import static org.hamcrest.Matchers.is; | ||
4 | +import static org.hamcrest.Matchers.not; | ||
5 | +import static org.junit.Assert.assertThat; | ||
6 | + | ||
7 | +import java.util.ArrayList; | ||
8 | + | ||
9 | +import org.junit.Test; | ||
10 | + | ||
11 | +/** | ||
12 | + * Unit tests for the BgpRouteEntry.PathSegment class. | ||
13 | + */ | ||
14 | +public class PathSegmentTest { | ||
15 | + /** | ||
16 | + * Generates a Path Segment. | ||
17 | + * | ||
18 | + * @return a generated PathSegment | ||
19 | + */ | ||
20 | + private BgpRouteEntry.PathSegment generatePathSegment() { | ||
21 | + byte pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE; | ||
22 | + ArrayList<Long> segmentAsNumbers = new ArrayList<>(); | ||
23 | + segmentAsNumbers.add((long) 1); | ||
24 | + segmentAsNumbers.add((long) 2); | ||
25 | + segmentAsNumbers.add((long) 3); | ||
26 | + BgpRouteEntry.PathSegment pathSegment = | ||
27 | + new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers); | ||
28 | + | ||
29 | + return pathSegment; | ||
30 | + } | ||
31 | + | ||
32 | + /** | ||
33 | + * Tests valid class constructor. | ||
34 | + */ | ||
35 | + @Test | ||
36 | + public void testConstructor() { | ||
37 | + BgpRouteEntry.PathSegment pathSegment = generatePathSegment(); | ||
38 | + | ||
39 | + String expectedString = | ||
40 | + "PathSegment{type=2, segmentAsNumbers=[1, 2, 3]}"; | ||
41 | + assertThat(pathSegment.toString(), is(expectedString)); | ||
42 | + } | ||
43 | + | ||
44 | + /** | ||
45 | + * Tests invalid class constructor for null Segment AS Numbers. | ||
46 | + */ | ||
47 | + @Test(expected = NullPointerException.class) | ||
48 | + public void testInvalidConstructorNullSegmentAsNumbers() { | ||
49 | + byte pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE; | ||
50 | + ArrayList<Long> segmentAsNumbers = null; | ||
51 | + new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers); | ||
52 | + } | ||
53 | + | ||
54 | + /** | ||
55 | + * Tests getting the fields of a Path Segment. | ||
56 | + */ | ||
57 | + @Test | ||
58 | + public void testGetFields() { | ||
59 | + // Create the fields to compare against | ||
60 | + byte pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE; | ||
61 | + ArrayList<Long> segmentAsNumbers = new ArrayList<>(); | ||
62 | + segmentAsNumbers.add((long) 1); | ||
63 | + segmentAsNumbers.add((long) 2); | ||
64 | + segmentAsNumbers.add((long) 3); | ||
65 | + | ||
66 | + // Generate the entry to test | ||
67 | + BgpRouteEntry.PathSegment pathSegment = generatePathSegment(); | ||
68 | + | ||
69 | + assertThat(pathSegment.getType(), is(pathSegmentType)); | ||
70 | + assertThat(pathSegment.getSegmentAsNumbers(), is(segmentAsNumbers)); | ||
71 | + } | ||
72 | + | ||
73 | + /** | ||
74 | + * Tests equality of {@link BgpRouteEntry.PathSegment}. | ||
75 | + */ | ||
76 | + @Test | ||
77 | + public void testEquality() { | ||
78 | + BgpRouteEntry.PathSegment pathSegment1 = generatePathSegment(); | ||
79 | + BgpRouteEntry.PathSegment pathSegment2 = generatePathSegment(); | ||
80 | + | ||
81 | + assertThat(pathSegment1, is(pathSegment2)); | ||
82 | + } | ||
83 | + | ||
84 | + /** | ||
85 | + * Tests non-equality of {@link BgpRouteEntry.PathSegment}. | ||
86 | + */ | ||
87 | + @Test | ||
88 | + public void testNonEquality() { | ||
89 | + BgpRouteEntry.PathSegment pathSegment1 = generatePathSegment(); | ||
90 | + | ||
91 | + // Setup Path Segment 2 | ||
92 | + byte pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE; | ||
93 | + ArrayList<Long> segmentAsNumbers = new ArrayList<>(); | ||
94 | + segmentAsNumbers.add((long) 1); | ||
95 | + segmentAsNumbers.add((long) 22); // Different | ||
96 | + segmentAsNumbers.add((long) 3); | ||
97 | + // | ||
98 | + BgpRouteEntry.PathSegment pathSegment2 = | ||
99 | + new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers); | ||
100 | + | ||
101 | + assertThat(pathSegment1, is(not(pathSegment2))); | ||
102 | + } | ||
103 | + | ||
104 | + /** | ||
105 | + * Tests object string representation. | ||
106 | + */ | ||
107 | + @Test | ||
108 | + public void testToString() { | ||
109 | + BgpRouteEntry.PathSegment pathSegment = generatePathSegment(); | ||
110 | + | ||
111 | + String expectedString = | ||
112 | + "PathSegment{type=2, segmentAsNumbers=[1, 2, 3]}"; | ||
113 | + assertThat(pathSegment.toString(), is(expectedString)); | ||
114 | + } | ||
115 | +} |
1 | +package org.onlab.onos.sdnip.bgp; | ||
2 | + | ||
3 | +import java.util.Collection; | ||
4 | + | ||
5 | +import org.jboss.netty.buffer.ChannelBuffer; | ||
6 | +import org.jboss.netty.buffer.ChannelBuffers; | ||
7 | +import org.jboss.netty.channel.ChannelHandlerContext; | ||
8 | +import org.jboss.netty.channel.ChannelStateEvent; | ||
9 | +import org.jboss.netty.channel.SimpleChannelHandler; | ||
10 | +import org.onlab.packet.IpAddress; | ||
11 | +import org.onlab.packet.IpPrefix; | ||
12 | + | ||
13 | +/** | ||
14 | + * Class for handling the remote BGP Peer session. | ||
15 | + */ | ||
16 | +class TestBgpPeerChannelHandler extends SimpleChannelHandler { | ||
17 | + static final long PEER_AS = 65001; | ||
18 | + static final int PEER_HOLDTIME = 120; // 120 seconds | ||
19 | + final IpAddress bgpId; // The BGP ID | ||
20 | + final long localPref; // Local preference for routes | ||
21 | + final long multiExitDisc = 20; // MED value | ||
22 | + | ||
23 | + ChannelHandlerContext savedCtx; | ||
24 | + | ||
25 | + /** | ||
26 | + * Constructor for given BGP ID. | ||
27 | + * | ||
28 | + * @param bgpId the BGP ID to use | ||
29 | + * @param localPref the local preference for the routes to use | ||
30 | + */ | ||
31 | + TestBgpPeerChannelHandler(IpAddress bgpId, | ||
32 | + long localPref) { | ||
33 | + this.bgpId = bgpId; | ||
34 | + this.localPref = localPref; | ||
35 | + } | ||
36 | + | ||
37 | + /** | ||
38 | + * Closes the channel. | ||
39 | + */ | ||
40 | + void closeChannel() { | ||
41 | + savedCtx.getChannel().close(); | ||
42 | + } | ||
43 | + | ||
44 | + @Override | ||
45 | + public void channelConnected(ChannelHandlerContext ctx, | ||
46 | + ChannelStateEvent channelEvent) { | ||
47 | + this.savedCtx = ctx; | ||
48 | + // Prepare and transmit BGP OPEN message | ||
49 | + ChannelBuffer message = prepareBgpOpen(); | ||
50 | + ctx.getChannel().write(message); | ||
51 | + | ||
52 | + // Prepare and transmit BGP KEEPALIVE message | ||
53 | + message = prepareBgpKeepalive(); | ||
54 | + ctx.getChannel().write(message); | ||
55 | + } | ||
56 | + | ||
57 | + @Override | ||
58 | + public void channelDisconnected(ChannelHandlerContext ctx, | ||
59 | + ChannelStateEvent channelEvent) { | ||
60 | + // Nothing to do | ||
61 | + } | ||
62 | + | ||
63 | + /** | ||
64 | + * Prepares BGP OPEN message. | ||
65 | + * | ||
66 | + * @return the message to transmit (BGP header included) | ||
67 | + */ | ||
68 | + ChannelBuffer prepareBgpOpen() { | ||
69 | + ChannelBuffer message = | ||
70 | + ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH); | ||
71 | + message.writeByte(BgpConstants.BGP_VERSION); | ||
72 | + message.writeShort((int) PEER_AS); | ||
73 | + message.writeShort(PEER_HOLDTIME); | ||
74 | + message.writeInt(bgpId.toInt()); | ||
75 | + message.writeByte(0); // No Optional Parameters | ||
76 | + return prepareBgpMessage(BgpConstants.BGP_TYPE_OPEN, message); | ||
77 | + } | ||
78 | + | ||
79 | + /** | ||
80 | + * Prepares BGP UPDATE message. | ||
81 | + * | ||
82 | + * @param nextHopRouter the next-hop router address for the routes to add | ||
83 | + * @param addedRoutes the routes to add | ||
84 | + * @param withdrawnRoutes the routes to withdraw | ||
85 | + * @return the message to transmit (BGP header included) | ||
86 | + */ | ||
87 | + ChannelBuffer prepareBgpUpdate(IpAddress nextHopRouter, | ||
88 | + Collection<IpPrefix> addedRoutes, | ||
89 | + Collection<IpPrefix> withdrawnRoutes) { | ||
90 | + int attrFlags; | ||
91 | + ChannelBuffer message = | ||
92 | + ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH); | ||
93 | + ChannelBuffer pathAttributes = | ||
94 | + ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH); | ||
95 | + | ||
96 | + // Encode the Withdrawn Routes | ||
97 | + ChannelBuffer encodedPrefixes = encodePackedPrefixes(withdrawnRoutes); | ||
98 | + message.writeShort(encodedPrefixes.readableBytes()); | ||
99 | + message.writeBytes(encodedPrefixes); | ||
100 | + | ||
101 | + // Encode the Path Attributes | ||
102 | + // ORIGIN: IGP | ||
103 | + attrFlags = 0x40; // Transitive flag | ||
104 | + pathAttributes.writeByte(attrFlags); | ||
105 | + pathAttributes.writeByte(BgpConstants.Update.Origin.TYPE); | ||
106 | + pathAttributes.writeByte(1); // Data length | ||
107 | + pathAttributes.writeByte(BgpConstants.Update.Origin.IGP); | ||
108 | + // AS_PATH: Two Path Segments of 3 ASes each | ||
109 | + attrFlags = 0x40; // Transitive flag | ||
110 | + pathAttributes.writeByte(attrFlags); | ||
111 | + pathAttributes.writeByte(BgpConstants.Update.AsPath.TYPE); | ||
112 | + pathAttributes.writeByte(16); // Data length | ||
113 | + byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE; | ||
114 | + pathAttributes.writeByte(pathSegmentType1); | ||
115 | + pathAttributes.writeByte(3); // Three ASes | ||
116 | + pathAttributes.writeShort(65010); // AS=65010 | ||
117 | + pathAttributes.writeShort(65020); // AS=65020 | ||
118 | + pathAttributes.writeShort(65030); // AS=65030 | ||
119 | + byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET; | ||
120 | + pathAttributes.writeByte(pathSegmentType2); | ||
121 | + pathAttributes.writeByte(3); // Three ASes | ||
122 | + pathAttributes.writeShort(65041); // AS=65041 | ||
123 | + pathAttributes.writeShort(65042); // AS=65042 | ||
124 | + pathAttributes.writeShort(65043); // AS=65043 | ||
125 | + // NEXT_HOP: nextHopRouter | ||
126 | + attrFlags = 0x40; // Transitive flag | ||
127 | + pathAttributes.writeByte(attrFlags); | ||
128 | + pathAttributes.writeByte(BgpConstants.Update.NextHop.TYPE); | ||
129 | + pathAttributes.writeByte(4); // Data length | ||
130 | + pathAttributes.writeInt(nextHopRouter.toInt()); // Next-hop router | ||
131 | + // LOCAL_PREF: localPref | ||
132 | + attrFlags = 0x40; // Transitive flag | ||
133 | + pathAttributes.writeByte(attrFlags); | ||
134 | + pathAttributes.writeByte(BgpConstants.Update.LocalPref.TYPE); | ||
135 | + pathAttributes.writeByte(4); // Data length | ||
136 | + pathAttributes.writeInt((int) localPref); // Preference value | ||
137 | + // MULTI_EXIT_DISC: multiExitDisc | ||
138 | + attrFlags = 0x80; // Optional | ||
139 | + // Non-Transitive flag | ||
140 | + pathAttributes.writeByte(attrFlags); | ||
141 | + pathAttributes.writeByte(BgpConstants.Update.MultiExitDisc.TYPE); | ||
142 | + pathAttributes.writeByte(4); // Data length | ||
143 | + pathAttributes.writeInt((int) multiExitDisc); // Preference value | ||
144 | + // The NLRI prefixes | ||
145 | + encodedPrefixes = encodePackedPrefixes(addedRoutes); | ||
146 | + | ||
147 | + // Write the Path Attributes, beginning with its length | ||
148 | + message.writeShort(pathAttributes.readableBytes()); | ||
149 | + message.writeBytes(pathAttributes); | ||
150 | + message.writeBytes(encodedPrefixes); | ||
151 | + | ||
152 | + return prepareBgpMessage(BgpConstants.BGP_TYPE_UPDATE, message); | ||
153 | + } | ||
154 | + | ||
155 | + /** | ||
156 | + * Encodes a collection of IPv4 network prefixes in a packed format. | ||
157 | + * <p> | ||
158 | + * The IPv4 prefixes are encoded in the form: | ||
159 | + * <Length, Prefix> where Length is the length in bits of the IPv4 prefix, | ||
160 | + * and Prefix is the IPv4 prefix (padded with trailing bits to the end | ||
161 | + * of an octet). | ||
162 | + * | ||
163 | + * @param prefixes the prefixes to encode | ||
164 | + * @return the buffer with the encoded prefixes | ||
165 | + */ | ||
166 | + private ChannelBuffer encodePackedPrefixes(Collection<IpPrefix> prefixes) { | ||
167 | + ChannelBuffer message = | ||
168 | + ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH); | ||
169 | + | ||
170 | + // Write each of the prefixes | ||
171 | + for (IpPrefix prefix : prefixes) { | ||
172 | + int prefixBitlen = prefix.prefixLength(); | ||
173 | + int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up | ||
174 | + message.writeByte(prefixBitlen); | ||
175 | + | ||
176 | + IpAddress address = prefix.toIpAddress(); | ||
177 | + long value = address.toInt() & 0xffffffffL; | ||
178 | + for (int i = 0; i < IpAddress.INET_LEN; i++) { | ||
179 | + if (prefixBytelen-- == 0) { | ||
180 | + break; | ||
181 | + } | ||
182 | + long nextByte = | ||
183 | + (value >> ((IpAddress.INET_LEN - i - 1) * 8)) & 0xff; | ||
184 | + message.writeByte((int) nextByte); | ||
185 | + } | ||
186 | + } | ||
187 | + | ||
188 | + return message; | ||
189 | + } | ||
190 | + | ||
191 | + /** | ||
192 | + * Prepares BGP KEEPALIVE message. | ||
193 | + * | ||
194 | + * @return the message to transmit (BGP header included) | ||
195 | + */ | ||
196 | + ChannelBuffer prepareBgpKeepalive() { | ||
197 | + ChannelBuffer message = | ||
198 | + ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH); | ||
199 | + return prepareBgpMessage(BgpConstants.BGP_TYPE_KEEPALIVE, message); | ||
200 | + } | ||
201 | + | ||
202 | + /** | ||
203 | + * Prepares BGP NOTIFICATION message. | ||
204 | + * | ||
205 | + * @param errorCode the BGP NOTIFICATION Error Code | ||
206 | + * @param errorSubcode the BGP NOTIFICATION Error Subcode if applicable, | ||
207 | + * otherwise BgpConstants.Notifications.ERROR_SUBCODE_UNSPECIFIC | ||
208 | + * @param payload the BGP NOTIFICATION Data if applicable, otherwise null | ||
209 | + * @return the message to transmit (BGP header included) | ||
210 | + */ | ||
211 | + ChannelBuffer prepareBgpNotification(int errorCode, int errorSubcode, | ||
212 | + ChannelBuffer data) { | ||
213 | + ChannelBuffer message = | ||
214 | + ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH); | ||
215 | + // Prepare the NOTIFICATION message payload | ||
216 | + message.writeByte(errorCode); | ||
217 | + message.writeByte(errorSubcode); | ||
218 | + if (data != null) { | ||
219 | + message.writeBytes(data); | ||
220 | + } | ||
221 | + return prepareBgpMessage(BgpConstants.BGP_TYPE_NOTIFICATION, message); | ||
222 | + } | ||
223 | + | ||
224 | + /** | ||
225 | + * Prepares BGP message. | ||
226 | + * | ||
227 | + * @param type the BGP message type | ||
228 | + * @param payload the message payload to transmit (BGP header excluded) | ||
229 | + * @return the message to transmit (BGP header included) | ||
230 | + */ | ||
231 | + private ChannelBuffer prepareBgpMessage(int type, ChannelBuffer payload) { | ||
232 | + ChannelBuffer message = | ||
233 | + ChannelBuffers.buffer(BgpConstants.BGP_HEADER_LENGTH + | ||
234 | + payload.readableBytes()); | ||
235 | + | ||
236 | + // Write the marker | ||
237 | + for (int i = 0; i < BgpConstants.BGP_HEADER_MARKER_LENGTH; i++) { | ||
238 | + message.writeByte(0xff); | ||
239 | + } | ||
240 | + | ||
241 | + // Write the rest of the BGP header | ||
242 | + message.writeShort(BgpConstants.BGP_HEADER_LENGTH + | ||
243 | + payload.readableBytes()); | ||
244 | + message.writeByte(type); | ||
245 | + | ||
246 | + // Write the payload | ||
247 | + message.writeBytes(payload); | ||
248 | + return message; | ||
249 | + } | ||
250 | +} |
1 | +package org.onlab.onos.sdnip.bgp; | ||
2 | + | ||
3 | +import java.util.concurrent.CountDownLatch; | ||
4 | + | ||
5 | +import org.jboss.netty.buffer.ChannelBuffer; | ||
6 | +import org.jboss.netty.channel.Channel; | ||
7 | +import org.jboss.netty.channel.ChannelHandlerContext; | ||
8 | +import org.jboss.netty.handler.codec.frame.FrameDecoder; | ||
9 | +import org.onlab.packet.IpAddress; | ||
10 | + | ||
11 | +/** | ||
12 | + * Class for handling the decoding of the BGP messages at the remote | ||
13 | + * BGP peer session. | ||
14 | + */ | ||
15 | +class TestBgpPeerFrameDecoder extends FrameDecoder { | ||
16 | + int remoteBgpVersion; // 1 octet | ||
17 | + long remoteAs; // 2 octets | ||
18 | + long remoteHoldtime; // 2 octets | ||
19 | + IpAddress remoteBgpIdentifier; // 4 octets -> IPv4 address | ||
20 | + | ||
21 | + final CountDownLatch receivedOpenMessageLatch = new CountDownLatch(1); | ||
22 | + final CountDownLatch receivedKeepaliveMessageLatch = new CountDownLatch(1); | ||
23 | + | ||
24 | + @Override | ||
25 | + protected Object decode(ChannelHandlerContext ctx, | ||
26 | + Channel channel, | ||
27 | + ChannelBuffer buf) throws Exception { | ||
28 | + // Test for minimum length of the BGP message | ||
29 | + if (buf.readableBytes() < BgpConstants.BGP_HEADER_LENGTH) { | ||
30 | + // No enough data received | ||
31 | + return null; | ||
32 | + } | ||
33 | + | ||
34 | + // | ||
35 | + // Mark the current buffer position in case we haven't received | ||
36 | + // the whole message. | ||
37 | + // | ||
38 | + buf.markReaderIndex(); | ||
39 | + | ||
40 | + // | ||
41 | + // Read and check the BGP message Marker field: it must be all ones | ||
42 | + // | ||
43 | + byte[] marker = new byte[BgpConstants.BGP_HEADER_MARKER_LENGTH]; | ||
44 | + buf.readBytes(marker); | ||
45 | + for (int i = 0; i < marker.length; i++) { | ||
46 | + if (marker[i] != (byte) 0xff) { | ||
47 | + // ERROR: Connection Not Synchronized. Close the channel. | ||
48 | + ctx.getChannel().close(); | ||
49 | + return null; | ||
50 | + } | ||
51 | + } | ||
52 | + | ||
53 | + // | ||
54 | + // Read and check the BGP message Length field | ||
55 | + // | ||
56 | + int length = buf.readUnsignedShort(); | ||
57 | + if ((length < BgpConstants.BGP_HEADER_LENGTH) || | ||
58 | + (length > BgpConstants.BGP_MESSAGE_MAX_LENGTH)) { | ||
59 | + // ERROR: Bad Message Length. Close the channel. | ||
60 | + ctx.getChannel().close(); | ||
61 | + return null; | ||
62 | + } | ||
63 | + | ||
64 | + // | ||
65 | + // Test whether the rest of the message is received: | ||
66 | + // So far we have read the Marker (16 octets) and the | ||
67 | + // Length (2 octets) fields. | ||
68 | + // | ||
69 | + int remainingMessageLen = | ||
70 | + length - BgpConstants.BGP_HEADER_MARKER_LENGTH - 2; | ||
71 | + if (buf.readableBytes() < remainingMessageLen) { | ||
72 | + // No enough data received | ||
73 | + buf.resetReaderIndex(); | ||
74 | + return null; | ||
75 | + } | ||
76 | + | ||
77 | + // | ||
78 | + // Read the BGP message Type field, and process based on that type | ||
79 | + // | ||
80 | + int type = buf.readUnsignedByte(); | ||
81 | + remainingMessageLen--; // Adjust after reading the type | ||
82 | + ChannelBuffer message = buf.readBytes(remainingMessageLen); | ||
83 | + | ||
84 | + // | ||
85 | + // Process the remaining of the message based on the message type | ||
86 | + // | ||
87 | + switch (type) { | ||
88 | + case BgpConstants.BGP_TYPE_OPEN: | ||
89 | + processBgpOpen(ctx, message); | ||
90 | + break; | ||
91 | + case BgpConstants.BGP_TYPE_UPDATE: | ||
92 | + // NOTE: Not used as part of the test, because ONOS does not | ||
93 | + // originate UPDATE messages. | ||
94 | + break; | ||
95 | + case BgpConstants.BGP_TYPE_NOTIFICATION: | ||
96 | + // NOTE: Not used as part of the testing (yet) | ||
97 | + break; | ||
98 | + case BgpConstants.BGP_TYPE_KEEPALIVE: | ||
99 | + processBgpKeepalive(ctx, message); | ||
100 | + break; | ||
101 | + default: | ||
102 | + // ERROR: Bad Message Type. Close the channel. | ||
103 | + ctx.getChannel().close(); | ||
104 | + return null; | ||
105 | + } | ||
106 | + | ||
107 | + return null; | ||
108 | + } | ||
109 | + | ||
110 | + /** | ||
111 | + * Processes BGP OPEN message. | ||
112 | + * | ||
113 | + * @param ctx the Channel Handler Context. | ||
114 | + * @param message the message to process. | ||
115 | + */ | ||
116 | + private void processBgpOpen(ChannelHandlerContext ctx, | ||
117 | + ChannelBuffer message) { | ||
118 | + int minLength = | ||
119 | + BgpConstants.BGP_OPEN_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH; | ||
120 | + if (message.readableBytes() < minLength) { | ||
121 | + // ERROR: Bad Message Length. Close the channel. | ||
122 | + ctx.getChannel().close(); | ||
123 | + return; | ||
124 | + } | ||
125 | + | ||
126 | + // | ||
127 | + // Parse the OPEN message | ||
128 | + // | ||
129 | + remoteBgpVersion = message.readUnsignedByte(); | ||
130 | + remoteAs = message.readUnsignedShort(); | ||
131 | + remoteHoldtime = message.readUnsignedShort(); | ||
132 | + remoteBgpIdentifier = IpAddress.valueOf((int) message.readUnsignedInt()); | ||
133 | + // Optional Parameters | ||
134 | + int optParamLen = message.readUnsignedByte(); | ||
135 | + if (message.readableBytes() < optParamLen) { | ||
136 | + // ERROR: Bad Message Length. Close the channel. | ||
137 | + ctx.getChannel().close(); | ||
138 | + return; | ||
139 | + } | ||
140 | + message.readBytes(optParamLen); // NOTE: data ignored | ||
141 | + | ||
142 | + // BGP OPEN message successfully received | ||
143 | + receivedOpenMessageLatch.countDown(); | ||
144 | + } | ||
145 | + | ||
146 | + /** | ||
147 | + * Processes BGP KEEPALIVE message. | ||
148 | + * | ||
149 | + * @param ctx the Channel Handler Context. | ||
150 | + * @param message the message to process. | ||
151 | + */ | ||
152 | + private void processBgpKeepalive(ChannelHandlerContext ctx, | ||
153 | + ChannelBuffer message) { | ||
154 | + if (message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH != | ||
155 | + BgpConstants.BGP_KEEPALIVE_EXPECTED_LENGTH) { | ||
156 | + // ERROR: Bad Message Length. Close the channel. | ||
157 | + ctx.getChannel().close(); | ||
158 | + return; | ||
159 | + } | ||
160 | + // BGP KEEPALIVE message successfully received | ||
161 | + receivedKeepaliveMessageLatch.countDown(); | ||
162 | + } | ||
163 | +} |
... | @@ -26,6 +26,16 @@ | ... | @@ -26,6 +26,16 @@ |
26 | <groupId>org.onlab.onos</groupId> | 26 | <groupId>org.onlab.onos</groupId> |
27 | <artifactId>onlab-osgi</artifactId> | 27 | <artifactId>onlab-osgi</artifactId> |
28 | </dependency> | 28 | </dependency> |
29 | + | ||
30 | + <dependency> | ||
31 | + <groupId>com.fasterxml.jackson.core</groupId> | ||
32 | + <artifactId>jackson-databind</artifactId> | ||
33 | + </dependency> | ||
34 | + <dependency> | ||
35 | + <groupId>com.fasterxml.jackson.core</groupId> | ||
36 | + <artifactId>jackson-annotations</artifactId> | ||
37 | + </dependency> | ||
38 | + | ||
29 | <dependency> | 39 | <dependency> |
30 | <groupId>org.osgi</groupId> | 40 | <groupId>org.osgi</groupId> |
31 | <artifactId>org.osgi.core</artifactId> | 41 | <artifactId>org.osgi.core</artifactId> | ... | ... |
1 | package org.onlab.onos.cli; | 1 | package org.onlab.onos.cli; |
2 | 2 | ||
3 | +import org.apache.karaf.shell.commands.Option; | ||
3 | import org.apache.karaf.shell.console.OsgiCommandSupport; | 4 | import org.apache.karaf.shell.console.OsgiCommandSupport; |
4 | import org.onlab.osgi.DefaultServiceDirectory; | 5 | import org.onlab.osgi.DefaultServiceDirectory; |
5 | import org.onlab.osgi.ServiceNotFoundException; | 6 | import org.onlab.osgi.ServiceNotFoundException; |
... | @@ -9,6 +10,10 @@ import org.onlab.osgi.ServiceNotFoundException; | ... | @@ -9,6 +10,10 @@ import org.onlab.osgi.ServiceNotFoundException; |
9 | */ | 10 | */ |
10 | public abstract class AbstractShellCommand extends OsgiCommandSupport { | 11 | public abstract class AbstractShellCommand extends OsgiCommandSupport { |
11 | 12 | ||
13 | + @Option(name = "-j", aliases = "--json", description = "Output JSON", | ||
14 | + required = false, multiValued = false) | ||
15 | + private boolean json = false; | ||
16 | + | ||
12 | /** | 17 | /** |
13 | * Returns the reference to the implementation of the specified service. | 18 | * Returns the reference to the implementation of the specified service. |
14 | * | 19 | * |
... | @@ -46,6 +51,15 @@ public abstract class AbstractShellCommand extends OsgiCommandSupport { | ... | @@ -46,6 +51,15 @@ public abstract class AbstractShellCommand extends OsgiCommandSupport { |
46 | */ | 51 | */ |
47 | protected abstract void execute(); | 52 | protected abstract void execute(); |
48 | 53 | ||
54 | + /** | ||
55 | + * Indicates whether JSON format should be output. | ||
56 | + * | ||
57 | + * @return true if JSON is requested | ||
58 | + */ | ||
59 | + protected boolean outputJson() { | ||
60 | + return json; | ||
61 | + } | ||
62 | + | ||
49 | @Override | 63 | @Override |
50 | protected Object doExecute() throws Exception { | 64 | protected Object doExecute() throws Exception { |
51 | try { | 65 | try { | ... | ... |
1 | package org.onlab.onos.cli; | 1 | package org.onlab.onos.cli; |
2 | 2 | ||
3 | +import com.fasterxml.jackson.databind.JsonNode; | ||
4 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
5 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
3 | import com.google.common.collect.Lists; | 6 | import com.google.common.collect.Lists; |
4 | - | ||
5 | import org.apache.karaf.shell.commands.Command; | 7 | import org.apache.karaf.shell.commands.Command; |
6 | import org.onlab.onos.cluster.ClusterService; | 8 | import org.onlab.onos.cluster.ClusterService; |
7 | import org.onlab.onos.cluster.ControllerNode; | 9 | import org.onlab.onos.cluster.ControllerNode; |
... | @@ -26,7 +28,10 @@ public class MastersListCommand extends AbstractShellCommand { | ... | @@ -26,7 +28,10 @@ public class MastersListCommand extends AbstractShellCommand { |
26 | MastershipService mastershipService = get(MastershipService.class); | 28 | MastershipService mastershipService = get(MastershipService.class); |
27 | List<ControllerNode> nodes = newArrayList(service.getNodes()); | 29 | List<ControllerNode> nodes = newArrayList(service.getNodes()); |
28 | Collections.sort(nodes, Comparators.NODE_COMPARATOR); | 30 | Collections.sort(nodes, Comparators.NODE_COMPARATOR); |
29 | - ControllerNode self = service.getLocalNode(); | 31 | + |
32 | + if (outputJson()) { | ||
33 | + print("%s", json(service, mastershipService, nodes)); | ||
34 | + } else { | ||
30 | for (ControllerNode node : nodes) { | 35 | for (ControllerNode node : nodes) { |
31 | List<DeviceId> ids = Lists.newArrayList(mastershipService.getDevicesOf(node.id())); | 36 | List<DeviceId> ids = Lists.newArrayList(mastershipService.getDevicesOf(node.id())); |
32 | Collections.sort(ids, Comparators.ELEMENT_ID_COMPARATOR); | 37 | Collections.sort(ids, Comparators.ELEMENT_ID_COMPARATOR); |
... | @@ -36,5 +41,37 @@ public class MastersListCommand extends AbstractShellCommand { | ... | @@ -36,5 +41,37 @@ public class MastersListCommand extends AbstractShellCommand { |
36 | } | 41 | } |
37 | } | 42 | } |
38 | } | 43 | } |
44 | + } | ||
45 | + | ||
46 | + // Produces JSON structure. | ||
47 | + private JsonNode json(ClusterService service, MastershipService mastershipService, | ||
48 | + List<ControllerNode> nodes) { | ||
49 | + ObjectMapper mapper = new ObjectMapper(); | ||
50 | + ArrayNode result = mapper.createArrayNode(); | ||
51 | + ControllerNode self = service.getLocalNode(); | ||
52 | + for (ControllerNode node : nodes) { | ||
53 | + List<DeviceId> ids = Lists.newArrayList(mastershipService.getDevicesOf(node.id())); | ||
54 | + result.add(mapper.createObjectNode() | ||
55 | + .put("id", node.id().toString()) | ||
56 | + .put("size", ids.size()) | ||
57 | + .set("devices", json(mapper, ids))); | ||
58 | + } | ||
59 | + return result; | ||
60 | + } | ||
61 | + | ||
62 | + /** | ||
63 | + * Produces a JSON array containing the specified device identifiers. | ||
64 | + * | ||
65 | + * @param mapper object mapper | ||
66 | + * @param ids collection of device identifiers | ||
67 | + * @return JSON array | ||
68 | + */ | ||
69 | + public static JsonNode json(ObjectMapper mapper, Iterable<DeviceId> ids) { | ||
70 | + ArrayNode result = mapper.createArrayNode(); | ||
71 | + for (DeviceId deviceId : ids) { | ||
72 | + result.add(deviceId.toString()); | ||
73 | + } | ||
74 | + return result; | ||
75 | + } | ||
39 | 76 | ||
40 | } | 77 | } | ... | ... |
1 | package org.onlab.onos.cli; | 1 | package org.onlab.onos.cli; |
2 | 2 | ||
3 | +import com.fasterxml.jackson.databind.JsonNode; | ||
4 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
5 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
3 | import org.apache.karaf.shell.commands.Command; | 6 | import org.apache.karaf.shell.commands.Command; |
4 | import org.onlab.onos.cluster.ClusterService; | 7 | import org.onlab.onos.cluster.ClusterService; |
5 | import org.onlab.onos.cluster.ControllerNode; | 8 | import org.onlab.onos.cluster.ControllerNode; |
... | @@ -24,6 +27,9 @@ public class NodesListCommand extends AbstractShellCommand { | ... | @@ -24,6 +27,9 @@ public class NodesListCommand extends AbstractShellCommand { |
24 | ClusterService service = get(ClusterService.class); | 27 | ClusterService service = get(ClusterService.class); |
25 | List<ControllerNode> nodes = newArrayList(service.getNodes()); | 28 | List<ControllerNode> nodes = newArrayList(service.getNodes()); |
26 | Collections.sort(nodes, Comparators.NODE_COMPARATOR); | 29 | Collections.sort(nodes, Comparators.NODE_COMPARATOR); |
30 | + if (outputJson()) { | ||
31 | + print("%s", json(service, nodes)); | ||
32 | + } else { | ||
27 | ControllerNode self = service.getLocalNode(); | 33 | ControllerNode self = service.getLocalNode(); |
28 | for (ControllerNode node : nodes) { | 34 | for (ControllerNode node : nodes) { |
29 | print(FMT, node.id(), node.ip(), node.tcpPort(), | 35 | print(FMT, node.id(), node.ip(), node.tcpPort(), |
... | @@ -31,5 +37,22 @@ public class NodesListCommand extends AbstractShellCommand { | ... | @@ -31,5 +37,22 @@ public class NodesListCommand extends AbstractShellCommand { |
31 | node.equals(self) ? "*" : ""); | 37 | node.equals(self) ? "*" : ""); |
32 | } | 38 | } |
33 | } | 39 | } |
40 | + } | ||
41 | + | ||
42 | + // Produces JSON structure. | ||
43 | + private JsonNode json(ClusterService service, List<ControllerNode> nodes) { | ||
44 | + ObjectMapper mapper = new ObjectMapper(); | ||
45 | + ArrayNode result = mapper.createArrayNode(); | ||
46 | + ControllerNode self = service.getLocalNode(); | ||
47 | + for (ControllerNode node : nodes) { | ||
48 | + result.add(mapper.createObjectNode() | ||
49 | + .put("id", node.id().toString()) | ||
50 | + .put("ip", node.ip().toString()) | ||
51 | + .put("tcpPort", node.tcpPort()) | ||
52 | + .put("state", service.getState(node.id()).toString()) | ||
53 | + .put("self", node.equals(self))); | ||
54 | + } | ||
55 | + return result; | ||
56 | + } | ||
34 | 57 | ||
35 | } | 58 | } | ... | ... |
1 | package org.onlab.onos.cli; | 1 | package org.onlab.onos.cli; |
2 | 2 | ||
3 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
3 | import org.apache.karaf.shell.commands.Command; | 4 | import org.apache.karaf.shell.commands.Command; |
4 | import org.onlab.onos.CoreService; | 5 | import org.onlab.onos.CoreService; |
5 | import org.onlab.onos.cluster.ClusterService; | 6 | import org.onlab.onos.cluster.ClusterService; |
... | @@ -22,6 +23,19 @@ public class SummaryCommand extends AbstractShellCommand { | ... | @@ -22,6 +23,19 @@ public class SummaryCommand extends AbstractShellCommand { |
22 | protected void execute() { | 23 | protected void execute() { |
23 | TopologyService topologyService = get(TopologyService.class); | 24 | TopologyService topologyService = get(TopologyService.class); |
24 | Topology topology = topologyService.currentTopology(); | 25 | Topology topology = topologyService.currentTopology(); |
26 | + if (outputJson()) { | ||
27 | + print("%s", new ObjectMapper().createObjectNode() | ||
28 | + .put("node", get(ClusterService.class).getLocalNode().ip().toString()) | ||
29 | + .put("version", get(CoreService.class).version().toString()) | ||
30 | + .put("nodes", get(ClusterService.class).getNodes().size()) | ||
31 | + .put("devices", get(DeviceService.class).getDeviceCount()) | ||
32 | + .put("links", get(LinkService.class).getLinkCount()) | ||
33 | + .put("hosts", get(HostService.class).getHostCount()) | ||
34 | + .put("clusters", topologyService.getClusters(topology).size()) | ||
35 | + .put("paths", topology.pathCount()) | ||
36 | + .put("flows", get(FlowRuleService.class).getFlowRuleCount()) | ||
37 | + .put("intents", get(IntentService.class).getIntentCount())); | ||
38 | + } else { | ||
25 | print("node=%s, version=%s", | 39 | print("node=%s, version=%s", |
26 | get(ClusterService.class).getLocalNode().ip(), | 40 | get(ClusterService.class).getLocalNode().ip(), |
27 | get(CoreService.class).version().toString()); | 41 | get(CoreService.class).version().toString()); |
... | @@ -35,5 +49,6 @@ public class SummaryCommand extends AbstractShellCommand { | ... | @@ -35,5 +49,6 @@ public class SummaryCommand extends AbstractShellCommand { |
35 | get(FlowRuleService.class).getFlowRuleCount(), | 49 | get(FlowRuleService.class).getFlowRuleCount(), |
36 | get(IntentService.class).getIntentCount()); | 50 | get(IntentService.class).getIntentCount()); |
37 | } | 51 | } |
52 | + } | ||
38 | 53 | ||
39 | } | 54 | } | ... | ... |
1 | package org.onlab.onos.cli.net; | 1 | package org.onlab.onos.cli.net; |
2 | 2 | ||
3 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
3 | import com.google.common.collect.Lists; | 4 | import com.google.common.collect.Lists; |
4 | import org.apache.karaf.shell.commands.Argument; | 5 | import org.apache.karaf.shell.commands.Argument; |
5 | import org.apache.karaf.shell.commands.Command; | 6 | import org.apache.karaf.shell.commands.Command; |
... | @@ -10,6 +11,7 @@ import org.onlab.onos.net.topology.TopologyCluster; | ... | @@ -10,6 +11,7 @@ import org.onlab.onos.net.topology.TopologyCluster; |
10 | import java.util.Collections; | 11 | import java.util.Collections; |
11 | import java.util.List; | 12 | import java.util.List; |
12 | 13 | ||
14 | +import static org.onlab.onos.cli.MastersListCommand.json; | ||
13 | import static org.onlab.onos.net.topology.ClusterId.clusterId; | 15 | import static org.onlab.onos.net.topology.ClusterId.clusterId; |
14 | 16 | ||
15 | /** | 17 | /** |
... | @@ -33,11 +35,14 @@ public class ClusterDevicesCommand extends ClustersListCommand { | ... | @@ -33,11 +35,14 @@ public class ClusterDevicesCommand extends ClustersListCommand { |
33 | } else { | 35 | } else { |
34 | List<DeviceId> ids = Lists.newArrayList(service.getClusterDevices(topology, cluster)); | 36 | List<DeviceId> ids = Lists.newArrayList(service.getClusterDevices(topology, cluster)); |
35 | Collections.sort(ids, Comparators.ELEMENT_ID_COMPARATOR); | 37 | Collections.sort(ids, Comparators.ELEMENT_ID_COMPARATOR); |
38 | + if (outputJson()) { | ||
39 | + print("%s", json(new ObjectMapper(), ids)); | ||
40 | + } else { | ||
36 | for (DeviceId deviceId : ids) { | 41 | for (DeviceId deviceId : ids) { |
37 | print("%s", deviceId); | 42 | print("%s", deviceId); |
38 | } | 43 | } |
39 | } | 44 | } |
40 | } | 45 | } |
41 | - | 46 | + } |
42 | 47 | ||
43 | } | 48 | } | ... | ... |
... | @@ -5,6 +5,7 @@ import org.apache.karaf.shell.commands.Command; | ... | @@ -5,6 +5,7 @@ import org.apache.karaf.shell.commands.Command; |
5 | import org.onlab.onos.net.Link; | 5 | import org.onlab.onos.net.Link; |
6 | import org.onlab.onos.net.topology.TopologyCluster; | 6 | import org.onlab.onos.net.topology.TopologyCluster; |
7 | 7 | ||
8 | +import static org.onlab.onos.cli.net.LinksListCommand.json; | ||
8 | import static org.onlab.onos.cli.net.LinksListCommand.linkString; | 9 | import static org.onlab.onos.cli.net.LinksListCommand.linkString; |
9 | import static org.onlab.onos.net.topology.ClusterId.clusterId; | 10 | import static org.onlab.onos.net.topology.ClusterId.clusterId; |
10 | 11 | ||
... | @@ -26,6 +27,8 @@ public class ClusterLinksCommand extends ClustersListCommand { | ... | @@ -26,6 +27,8 @@ public class ClusterLinksCommand extends ClustersListCommand { |
26 | TopologyCluster cluster = service.getCluster(topology, clusterId(cid)); | 27 | TopologyCluster cluster = service.getCluster(topology, clusterId(cid)); |
27 | if (cluster == null) { | 28 | if (cluster == null) { |
28 | error("No such cluster %s", cid); | 29 | error("No such cluster %s", cid); |
30 | + } else if (outputJson()) { | ||
31 | + print("%s", json(service.getClusterLinks(topology, cluster))); | ||
29 | } else { | 32 | } else { |
30 | for (Link link : service.getClusterLinks(topology, cluster)) { | 33 | for (Link link : service.getClusterLinks(topology, cluster)) { |
31 | print(linkString(link)); | 34 | print(linkString(link)); | ... | ... |
1 | package org.onlab.onos.cli.net; | 1 | package org.onlab.onos.cli.net; |
2 | 2 | ||
3 | +import com.fasterxml.jackson.databind.JsonNode; | ||
4 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
5 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
3 | import com.google.common.collect.Lists; | 6 | import com.google.common.collect.Lists; |
4 | import org.apache.karaf.shell.commands.Command; | 7 | import org.apache.karaf.shell.commands.Command; |
5 | import org.onlab.onos.cli.Comparators; | 8 | import org.onlab.onos.cli.Comparators; |
... | @@ -24,9 +27,26 @@ public class ClustersListCommand extends TopologyCommand { | ... | @@ -24,9 +27,26 @@ public class ClustersListCommand extends TopologyCommand { |
24 | List<TopologyCluster> clusters = Lists.newArrayList(service.getClusters(topology)); | 27 | List<TopologyCluster> clusters = Lists.newArrayList(service.getClusters(topology)); |
25 | Collections.sort(clusters, Comparators.CLUSTER_COMPARATOR); | 28 | Collections.sort(clusters, Comparators.CLUSTER_COMPARATOR); |
26 | 29 | ||
30 | + if (outputJson()) { | ||
31 | + print("%s", json(clusters)); | ||
32 | + } else { | ||
27 | for (TopologyCluster cluster : clusters) { | 33 | for (TopologyCluster cluster : clusters) { |
28 | print(FMT, cluster.id().index(), cluster.deviceCount(), cluster.linkCount()); | 34 | print(FMT, cluster.id().index(), cluster.deviceCount(), cluster.linkCount()); |
29 | } | 35 | } |
30 | } | 36 | } |
37 | + } | ||
38 | + | ||
39 | + // Produces a JSON result. | ||
40 | + private JsonNode json(Iterable<TopologyCluster> clusters) { | ||
41 | + ObjectMapper mapper = new ObjectMapper(); | ||
42 | + ArrayNode result = mapper.createArrayNode(); | ||
43 | + for (TopologyCluster cluster : clusters) { | ||
44 | + result.add(mapper.createObjectNode() | ||
45 | + .put("id", cluster.id().index()) | ||
46 | + .put("deviceCount", cluster.deviceCount()) | ||
47 | + .put("linkCount", cluster.linkCount())); | ||
48 | + } | ||
49 | + return result; | ||
50 | + } | ||
31 | 51 | ||
32 | } | 52 | } | ... | ... |
1 | package org.onlab.onos.cli.net; | 1 | package org.onlab.onos.cli.net; |
2 | 2 | ||
3 | +import com.fasterxml.jackson.databind.JsonNode; | ||
4 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
5 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
6 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
3 | import org.apache.karaf.shell.commands.Argument; | 7 | import org.apache.karaf.shell.commands.Argument; |
4 | import org.apache.karaf.shell.commands.Command; | 8 | import org.apache.karaf.shell.commands.Command; |
9 | +import org.apache.karaf.shell.commands.Option; | ||
5 | import org.onlab.onos.cli.Comparators; | 10 | import org.onlab.onos.cli.Comparators; |
6 | import org.onlab.onos.net.Device; | 11 | import org.onlab.onos.net.Device; |
7 | import org.onlab.onos.net.Port; | 12 | import org.onlab.onos.net.Port; |
... | @@ -22,6 +27,14 @@ public class DevicePortsListCommand extends DevicesListCommand { | ... | @@ -22,6 +27,14 @@ public class DevicePortsListCommand extends DevicesListCommand { |
22 | 27 | ||
23 | private static final String FMT = " port=%s, state=%s"; | 28 | private static final String FMT = " port=%s, state=%s"; |
24 | 29 | ||
30 | + @Option(name = "-e", aliases = "--enabled", description = "Show only enabled ports", | ||
31 | + required = false, multiValued = false) | ||
32 | + private boolean enabled = false; | ||
33 | + | ||
34 | + @Option(name = "-d", aliases = "--disabled", description = "Show only disabled ports", | ||
35 | + required = false, multiValued = false) | ||
36 | + private boolean disabled = false; | ||
37 | + | ||
25 | @Argument(index = 0, name = "uri", description = "Device ID", | 38 | @Argument(index = 0, name = "uri", description = "Device ID", |
26 | required = false, multiValued = false) | 39 | required = false, multiValued = false) |
27 | String uri = null; | 40 | String uri = null; |
... | @@ -30,27 +43,79 @@ public class DevicePortsListCommand extends DevicesListCommand { | ... | @@ -30,27 +43,79 @@ public class DevicePortsListCommand extends DevicesListCommand { |
30 | protected void execute() { | 43 | protected void execute() { |
31 | DeviceService service = get(DeviceService.class); | 44 | DeviceService service = get(DeviceService.class); |
32 | if (uri == null) { | 45 | if (uri == null) { |
46 | + if (outputJson()) { | ||
47 | + print("%s", jsonPorts(service, getSortedDevices(service))); | ||
48 | + } else { | ||
33 | for (Device device : getSortedDevices(service)) { | 49 | for (Device device : getSortedDevices(service)) { |
34 | printDevice(service, device); | 50 | printDevice(service, device); |
35 | } | 51 | } |
52 | + } | ||
53 | + | ||
36 | } else { | 54 | } else { |
37 | Device device = service.getDevice(deviceId(uri)); | 55 | Device device = service.getDevice(deviceId(uri)); |
38 | if (device == null) { | 56 | if (device == null) { |
39 | error("No such device %s", uri); | 57 | error("No such device %s", uri); |
58 | + } else if (outputJson()) { | ||
59 | + print("%s", jsonPorts(service, new ObjectMapper(), device)); | ||
40 | } else { | 60 | } else { |
41 | printDevice(service, device); | 61 | printDevice(service, device); |
42 | } | 62 | } |
43 | } | 63 | } |
44 | } | 64 | } |
45 | 65 | ||
66 | + /** | ||
67 | + * Produces JSON array containing ports of the specified devices. | ||
68 | + * | ||
69 | + * @param service device service | ||
70 | + * @param devices collection of devices | ||
71 | + * @return JSON array | ||
72 | + */ | ||
73 | + public JsonNode jsonPorts(DeviceService service, Iterable<Device> devices) { | ||
74 | + ObjectMapper mapper = new ObjectMapper(); | ||
75 | + ArrayNode result = mapper.createArrayNode(); | ||
76 | + for (Device device : devices) { | ||
77 | + result.add(jsonPorts(service, mapper, device)); | ||
78 | + } | ||
79 | + return result; | ||
80 | + } | ||
81 | + | ||
82 | + /** | ||
83 | + * Produces JSON array containing ports of the specified device. | ||
84 | + * | ||
85 | + * @param service device service | ||
86 | + * @param mapper object mapper | ||
87 | + * @param device infrastructure devices | ||
88 | + * @return JSON array | ||
89 | + */ | ||
90 | + public JsonNode jsonPorts(DeviceService service, ObjectMapper mapper, Device device) { | ||
91 | + ObjectNode result = mapper.createObjectNode(); | ||
92 | + ArrayNode ports = mapper.createArrayNode(); | ||
93 | + for (Port port : service.getPorts(device.id())) { | ||
94 | + if (isIncluded(port)) { | ||
95 | + ports.add(mapper.createObjectNode() | ||
96 | + .put("port", port.number().toString()) | ||
97 | + .put("isEnabled", port.isEnabled())); | ||
98 | + } | ||
99 | + } | ||
100 | + return result.put("device", device.id().toString()).set("ports", ports); | ||
101 | + } | ||
102 | + | ||
103 | + // Determines if a port should be included in output. | ||
104 | + private boolean isIncluded(Port port) { | ||
105 | + return enabled && port.isEnabled() || disabled && !port.isEnabled() || | ||
106 | + !enabled && !disabled; | ||
107 | + } | ||
108 | + | ||
46 | @Override | 109 | @Override |
47 | protected void printDevice(DeviceService service, Device device) { | 110 | protected void printDevice(DeviceService service, Device device) { |
48 | super.printDevice(service, device); | 111 | super.printDevice(service, device); |
49 | List<Port> ports = new ArrayList<>(service.getPorts(device.id())); | 112 | List<Port> ports = new ArrayList<>(service.getPorts(device.id())); |
50 | Collections.sort(ports, Comparators.PORT_COMPARATOR); | 113 | Collections.sort(ports, Comparators.PORT_COMPARATOR); |
51 | for (Port port : ports) { | 114 | for (Port port : ports) { |
115 | + if (isIncluded(port)) { | ||
52 | print(FMT, port.number(), port.isEnabled() ? "enabled" : "disabled"); | 116 | print(FMT, port.number(), port.isEnabled() ? "enabled" : "disabled"); |
53 | } | 117 | } |
54 | } | 118 | } |
119 | + } | ||
55 | 120 | ||
56 | } | 121 | } | ... | ... |
1 | package org.onlab.onos.cli.net; | 1 | package org.onlab.onos.cli.net; |
2 | 2 | ||
3 | +import com.fasterxml.jackson.databind.JsonNode; | ||
4 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
5 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
6 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
3 | import org.apache.karaf.shell.commands.Command; | 7 | import org.apache.karaf.shell.commands.Command; |
4 | import org.onlab.onos.cli.AbstractShellCommand; | 8 | import org.onlab.onos.cli.AbstractShellCommand; |
5 | import org.onlab.onos.cli.Comparators; | 9 | import org.onlab.onos.cli.Comparators; |
... | @@ -24,10 +28,53 @@ public class DevicesListCommand extends AbstractShellCommand { | ... | @@ -24,10 +28,53 @@ public class DevicesListCommand extends AbstractShellCommand { |
24 | @Override | 28 | @Override |
25 | protected void execute() { | 29 | protected void execute() { |
26 | DeviceService service = get(DeviceService.class); | 30 | DeviceService service = get(DeviceService.class); |
31 | + if (outputJson()) { | ||
32 | + print("%s", json(service, getSortedDevices(service))); | ||
33 | + } else { | ||
27 | for (Device device : getSortedDevices(service)) { | 34 | for (Device device : getSortedDevices(service)) { |
28 | printDevice(service, device); | 35 | printDevice(service, device); |
29 | } | 36 | } |
30 | } | 37 | } |
38 | + } | ||
39 | + | ||
40 | + /** | ||
41 | + * Returns JSON node representing the specified devices. | ||
42 | + * | ||
43 | + * @param service device service | ||
44 | + * @param devices collection of devices | ||
45 | + * @return JSON node | ||
46 | + */ | ||
47 | + public static JsonNode json(DeviceService service, Iterable<Device> devices) { | ||
48 | + ObjectMapper mapper = new ObjectMapper(); | ||
49 | + ArrayNode result = mapper.createArrayNode(); | ||
50 | + for (Device device : devices) { | ||
51 | + result.add(json(service, mapper, device)); | ||
52 | + } | ||
53 | + return result; | ||
54 | + } | ||
55 | + | ||
56 | + /** | ||
57 | + * Returns JSON node representing the specified device. | ||
58 | + * | ||
59 | + * @param service device service | ||
60 | + * @param mapper object mapper | ||
61 | + * @param device infrastructure device | ||
62 | + * @return JSON node | ||
63 | + */ | ||
64 | + public static ObjectNode json(DeviceService service, ObjectMapper mapper, | ||
65 | + Device device) { | ||
66 | + ObjectNode result = mapper.createObjectNode(); | ||
67 | + if (device != null) { | ||
68 | + result.put("id", device.id().toString()) | ||
69 | + .put("available", service.isAvailable(device.id())) | ||
70 | + .put("role", service.getRole(device.id()).toString()) | ||
71 | + .put("mfr", device.manufacturer()) | ||
72 | + .put("hw", device.hwVersion()) | ||
73 | + .put("sw", device.swVersion()) | ||
74 | + .put("serial", device.serialNumber()); | ||
75 | + } | ||
76 | + return result; | ||
77 | + } | ||
31 | 78 | ||
32 | /** | 79 | /** |
33 | * Returns the list of devices sorted using the device ID URIs. | 80 | * Returns the list of devices sorted using the device ID URIs. | ... | ... |
1 | package org.onlab.onos.cli.net; | 1 | package org.onlab.onos.cli.net; |
2 | 2 | ||
3 | +import com.fasterxml.jackson.databind.JsonNode; | ||
4 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
5 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
6 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
3 | import com.google.common.collect.Maps; | 7 | import com.google.common.collect.Maps; |
4 | import org.apache.karaf.shell.commands.Argument; | 8 | import org.apache.karaf.shell.commands.Argument; |
5 | import org.apache.karaf.shell.commands.Command; | 9 | import org.apache.karaf.shell.commands.Command; |
... | @@ -12,6 +16,8 @@ import org.onlab.onos.net.device.DeviceService; | ... | @@ -12,6 +16,8 @@ import org.onlab.onos.net.device.DeviceService; |
12 | import org.onlab.onos.net.flow.FlowEntry; | 16 | import org.onlab.onos.net.flow.FlowEntry; |
13 | import org.onlab.onos.net.flow.FlowEntry.FlowEntryState; | 17 | import org.onlab.onos.net.flow.FlowEntry.FlowEntryState; |
14 | import org.onlab.onos.net.flow.FlowRuleService; | 18 | import org.onlab.onos.net.flow.FlowRuleService; |
19 | +import org.onlab.onos.net.flow.criteria.Criterion; | ||
20 | +import org.onlab.onos.net.flow.instructions.Instruction; | ||
15 | 21 | ||
16 | import java.util.Collections; | 22 | import java.util.Collections; |
17 | import java.util.List; | 23 | import java.util.List; |
... | @@ -48,10 +54,74 @@ public class FlowsListCommand extends AbstractShellCommand { | ... | @@ -48,10 +54,74 @@ public class FlowsListCommand extends AbstractShellCommand { |
48 | DeviceService deviceService = get(DeviceService.class); | 54 | DeviceService deviceService = get(DeviceService.class); |
49 | FlowRuleService service = get(FlowRuleService.class); | 55 | FlowRuleService service = get(FlowRuleService.class); |
50 | Map<Device, List<FlowEntry>> flows = getSortedFlows(deviceService, service); | 56 | Map<Device, List<FlowEntry>> flows = getSortedFlows(deviceService, service); |
57 | + | ||
58 | + if (outputJson()) { | ||
59 | + print("%s", json(coreService, getSortedDevices(deviceService), flows)); | ||
60 | + } else { | ||
51 | for (Device d : getSortedDevices(deviceService)) { | 61 | for (Device d : getSortedDevices(deviceService)) { |
52 | printFlows(d, flows.get(d), coreService); | 62 | printFlows(d, flows.get(d), coreService); |
53 | } | 63 | } |
54 | } | 64 | } |
65 | + } | ||
66 | + | ||
67 | + /** | ||
68 | + * Produces a JSON array of flows grouped by the each device. | ||
69 | + * | ||
70 | + * @param coreService core service | ||
71 | + * @param devices collection of devices to group flow by | ||
72 | + * @param flows collection of flows per each device | ||
73 | + * @return JSON array | ||
74 | + */ | ||
75 | + private JsonNode json(CoreService coreService, Iterable<Device> devices, | ||
76 | + Map<Device, List<FlowEntry>> flows) { | ||
77 | + ObjectMapper mapper = new ObjectMapper(); | ||
78 | + ArrayNode result = mapper.createArrayNode(); | ||
79 | + for (Device device : devices) { | ||
80 | + result.add(json(coreService, mapper, device, flows.get(device))); | ||
81 | + } | ||
82 | + return result; | ||
83 | + } | ||
84 | + | ||
85 | + // Produces JSON object with the flows of the given device. | ||
86 | + private ObjectNode json(CoreService coreService, ObjectMapper mapper, | ||
87 | + Device device, List<FlowEntry> flows) { | ||
88 | + ObjectNode result = mapper.createObjectNode(); | ||
89 | + ArrayNode array = mapper.createArrayNode(); | ||
90 | + | ||
91 | + for (FlowEntry flow : flows) { | ||
92 | + array.add(json(coreService, mapper, flow)); | ||
93 | + } | ||
94 | + | ||
95 | + result.put("device", device.id().toString()) | ||
96 | + .put("flowCount", flows.size()) | ||
97 | + .set("flows", array); | ||
98 | + return result; | ||
99 | + } | ||
100 | + | ||
101 | + // Produces JSON structure with the specified flow data. | ||
102 | + private ObjectNode json(CoreService coreService, ObjectMapper mapper, | ||
103 | + FlowEntry flow) { | ||
104 | + ObjectNode result = mapper.createObjectNode(); | ||
105 | + ArrayNode crit = mapper.createArrayNode(); | ||
106 | + for (Criterion c : flow.selector().criteria()) { | ||
107 | + crit.add(c.toString()); | ||
108 | + } | ||
109 | + | ||
110 | + ArrayNode instr = mapper.createArrayNode(); | ||
111 | + for (Instruction i : flow.treatment().instructions()) { | ||
112 | + instr.add(i.toString()); | ||
113 | + } | ||
114 | + | ||
115 | + result.put("flowId", Long.toHexString(flow.id().value())) | ||
116 | + .put("state", flow.state().toString()) | ||
117 | + .put("bytes", flow.bytes()) | ||
118 | + .put("packets", flow.packets()) | ||
119 | + .put("life", flow.life()) | ||
120 | + .put("appId", coreService.getAppId(flow.appId()).name()); | ||
121 | + result.set("selector", crit); | ||
122 | + result.set("treatment", instr); | ||
123 | + return result; | ||
124 | + } | ||
55 | 125 | ||
56 | /** | 126 | /** |
57 | * Returns the list of devices sorted using the device ID URIs. | 127 | * Returns the list of devices sorted using the device ID URIs. | ... | ... |
1 | package org.onlab.onos.cli.net; | 1 | package org.onlab.onos.cli.net; |
2 | 2 | ||
3 | +import com.fasterxml.jackson.databind.JsonNode; | ||
4 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
5 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
6 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
3 | import org.apache.karaf.shell.commands.Command; | 7 | import org.apache.karaf.shell.commands.Command; |
4 | import org.onlab.onos.cli.AbstractShellCommand; | 8 | import org.onlab.onos.cli.AbstractShellCommand; |
5 | import org.onlab.onos.cli.Comparators; | 9 | import org.onlab.onos.cli.Comparators; |
6 | import org.onlab.onos.net.Host; | 10 | import org.onlab.onos.net.Host; |
7 | import org.onlab.onos.net.host.HostService; | 11 | import org.onlab.onos.net.host.HostService; |
12 | +import org.onlab.packet.IpPrefix; | ||
8 | 13 | ||
9 | import java.util.Collections; | 14 | import java.util.Collections; |
10 | import java.util.List; | 15 | import java.util.List; |
... | @@ -24,10 +29,41 @@ public class HostsListCommand extends AbstractShellCommand { | ... | @@ -24,10 +29,41 @@ public class HostsListCommand extends AbstractShellCommand { |
24 | @Override | 29 | @Override |
25 | protected void execute() { | 30 | protected void execute() { |
26 | HostService service = get(HostService.class); | 31 | HostService service = get(HostService.class); |
32 | + if (outputJson()) { | ||
33 | + print("%s", json(getSortedHosts(service))); | ||
34 | + } else { | ||
27 | for (Host host : getSortedHosts(service)) { | 35 | for (Host host : getSortedHosts(service)) { |
28 | printHost(host); | 36 | printHost(host); |
29 | } | 37 | } |
30 | } | 38 | } |
39 | + } | ||
40 | + | ||
41 | + // Produces JSON structure. | ||
42 | + private static JsonNode json(Iterable<Host> hosts) { | ||
43 | + ObjectMapper mapper = new ObjectMapper(); | ||
44 | + ArrayNode result = mapper.createArrayNode(); | ||
45 | + for (Host host : hosts) { | ||
46 | + result.add(json(mapper, host)); | ||
47 | + } | ||
48 | + return result; | ||
49 | + } | ||
50 | + | ||
51 | + // Produces JSON structure. | ||
52 | + private static JsonNode json(ObjectMapper mapper, Host host) { | ||
53 | + ObjectNode loc = LinksListCommand.json(mapper, host.location()) | ||
54 | + .put("time", host.location().time()); | ||
55 | + ArrayNode ips = mapper.createArrayNode(); | ||
56 | + for (IpPrefix ip : host.ipAddresses()) { | ||
57 | + ips.add(ip.toString()); | ||
58 | + } | ||
59 | + ObjectNode result = mapper.createObjectNode() | ||
60 | + .put("id", host.id().toString()) | ||
61 | + .put("mac", host.mac().toString()) | ||
62 | + .put("vlan", host.vlan().toString()); | ||
63 | + result.set("location", loc); | ||
64 | + result.set("ips", ips); | ||
65 | + return result; | ||
66 | + } | ||
31 | 67 | ||
32 | /** | 68 | /** |
33 | * Returns the list of devices sorted using the device ID URIs. | 69 | * Returns the list of devices sorted using the device ID URIs. |
... | @@ -44,7 +80,7 @@ public class HostsListCommand extends AbstractShellCommand { | ... | @@ -44,7 +80,7 @@ public class HostsListCommand extends AbstractShellCommand { |
44 | /** | 80 | /** |
45 | * Prints information about a host. | 81 | * Prints information about a host. |
46 | * | 82 | * |
47 | - * @param host | 83 | + * @param host end-station host |
48 | */ | 84 | */ |
49 | protected void printHost(Host host) { | 85 | protected void printHost(Host host) { |
50 | if (host != null) { | 86 | if (host != null) { |
... | @@ -54,4 +90,4 @@ public class HostsListCommand extends AbstractShellCommand { | ... | @@ -54,4 +90,4 @@ public class HostsListCommand extends AbstractShellCommand { |
54 | host.vlan(), host.ipAddresses()); | 90 | host.vlan(), host.ipAddresses()); |
55 | } | 91 | } |
56 | } | 92 | } |
57 | - } | 93 | +} | ... | ... |
1 | package org.onlab.onos.cli.net; | 1 | package org.onlab.onos.cli.net; |
2 | 2 | ||
3 | +import com.fasterxml.jackson.databind.JsonNode; | ||
4 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
5 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
6 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
3 | import org.apache.karaf.shell.commands.Argument; | 7 | import org.apache.karaf.shell.commands.Argument; |
4 | import org.apache.karaf.shell.commands.Command; | 8 | import org.apache.karaf.shell.commands.Command; |
5 | import org.onlab.onos.cli.AbstractShellCommand; | 9 | import org.onlab.onos.cli.AbstractShellCommand; |
10 | +import org.onlab.onos.net.ConnectPoint; | ||
6 | import org.onlab.onos.net.Link; | 11 | import org.onlab.onos.net.Link; |
7 | import org.onlab.onos.net.link.LinkService; | 12 | import org.onlab.onos.net.link.LinkService; |
8 | 13 | ||
... | @@ -27,10 +32,56 @@ public class LinksListCommand extends AbstractShellCommand { | ... | @@ -27,10 +32,56 @@ public class LinksListCommand extends AbstractShellCommand { |
27 | LinkService service = get(LinkService.class); | 32 | LinkService service = get(LinkService.class); |
28 | Iterable<Link> links = uri != null ? | 33 | Iterable<Link> links = uri != null ? |
29 | service.getDeviceLinks(deviceId(uri)) : service.getLinks(); | 34 | service.getDeviceLinks(deviceId(uri)) : service.getLinks(); |
35 | + if (outputJson()) { | ||
36 | + print("%s", json(links)); | ||
37 | + } else { | ||
30 | for (Link link : links) { | 38 | for (Link link : links) { |
31 | print(linkString(link)); | 39 | print(linkString(link)); |
32 | } | 40 | } |
33 | } | 41 | } |
42 | + } | ||
43 | + | ||
44 | + /** | ||
45 | + * Produces a JSON array containing the specified links. | ||
46 | + * | ||
47 | + * @param links collection of links | ||
48 | + * @return JSON array | ||
49 | + */ | ||
50 | + public static JsonNode json(Iterable<Link> links) { | ||
51 | + ObjectMapper mapper = new ObjectMapper(); | ||
52 | + ArrayNode result = mapper.createArrayNode(); | ||
53 | + for (Link link : links) { | ||
54 | + result.add(json(mapper, link)); | ||
55 | + } | ||
56 | + return result; | ||
57 | + } | ||
58 | + | ||
59 | + /** | ||
60 | + * Produces a JSON object for the specified link. | ||
61 | + * | ||
62 | + * @param mapper object mapper | ||
63 | + * @param link link to encode | ||
64 | + * @return JSON object | ||
65 | + */ | ||
66 | + public static ObjectNode json(ObjectMapper mapper, Link link) { | ||
67 | + ObjectNode result = mapper.createObjectNode(); | ||
68 | + result.set("src", json(mapper, link.src())); | ||
69 | + result.set("dst", json(mapper, link.dst())); | ||
70 | + return result; | ||
71 | + } | ||
72 | + | ||
73 | + /** | ||
74 | + * Produces a JSON object for the specified connect point. | ||
75 | + * | ||
76 | + * @param mapper object mapper | ||
77 | + * @param connectPoint connection point to encode | ||
78 | + * @return JSON object | ||
79 | + */ | ||
80 | + public static ObjectNode json(ObjectMapper mapper, ConnectPoint connectPoint) { | ||
81 | + return mapper.createObjectNode() | ||
82 | + .put("device", connectPoint.deviceId().toString()) | ||
83 | + .put("port", connectPoint.port().toString()); | ||
84 | + } | ||
34 | 85 | ||
35 | /** | 86 | /** |
36 | * Returns a formatted string representing the given link. | 87 | * Returns a formatted string representing the given link. | ... | ... |
1 | package org.onlab.onos.cli.net; | 1 | package org.onlab.onos.cli.net; |
2 | 2 | ||
3 | +import com.fasterxml.jackson.databind.JsonNode; | ||
4 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
5 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
3 | import org.apache.karaf.shell.commands.Argument; | 6 | import org.apache.karaf.shell.commands.Argument; |
4 | import org.apache.karaf.shell.commands.Command; | 7 | import org.apache.karaf.shell.commands.Command; |
5 | import org.onlab.onos.net.Link; | 8 | import org.onlab.onos.net.Link; |
... | @@ -32,10 +35,31 @@ public class PathListCommand extends TopologyCommand { | ... | @@ -32,10 +35,31 @@ public class PathListCommand extends TopologyCommand { |
32 | protected void execute() { | 35 | protected void execute() { |
33 | init(); | 36 | init(); |
34 | Set<Path> paths = service.getPaths(topology, deviceId(src), deviceId(dst)); | 37 | Set<Path> paths = service.getPaths(topology, deviceId(src), deviceId(dst)); |
38 | + if (outputJson()) { | ||
39 | + print("%s", json(paths)); | ||
40 | + } else { | ||
35 | for (Path path : paths) { | 41 | for (Path path : paths) { |
36 | print(pathString(path)); | 42 | print(pathString(path)); |
37 | } | 43 | } |
38 | } | 44 | } |
45 | + } | ||
46 | + | ||
47 | + /** | ||
48 | + * Produces a JSON array containing the specified paths. | ||
49 | + * | ||
50 | + * @param paths collection of paths | ||
51 | + * @return JSON array | ||
52 | + */ | ||
53 | + public static JsonNode json(Iterable<Path> paths) { | ||
54 | + ObjectMapper mapper = new ObjectMapper(); | ||
55 | + ArrayNode result = mapper.createArrayNode(); | ||
56 | + for (Path path : paths) { | ||
57 | + result.add(LinksListCommand.json(mapper, path) | ||
58 | + .put("cost", path.cost()) | ||
59 | + .set("links", LinksListCommand.json(path.links()))); | ||
60 | + } | ||
61 | + return result; | ||
62 | + } | ||
39 | 63 | ||
40 | /** | 64 | /** |
41 | * Produces a formatted string representing the specified path. | 65 | * Produces a formatted string representing the specified path. | ... | ... |
1 | package org.onlab.onos.cli.net; | 1 | package org.onlab.onos.cli.net; |
2 | 2 | ||
3 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
3 | import org.apache.karaf.shell.commands.Command; | 4 | import org.apache.karaf.shell.commands.Command; |
4 | import org.onlab.onos.cli.AbstractShellCommand; | 5 | import org.onlab.onos.cli.AbstractShellCommand; |
5 | import org.onlab.onos.net.topology.Topology; | 6 | import org.onlab.onos.net.topology.Topology; |
... | @@ -30,8 +31,17 @@ public class TopologyCommand extends AbstractShellCommand { | ... | @@ -30,8 +31,17 @@ public class TopologyCommand extends AbstractShellCommand { |
30 | @Override | 31 | @Override |
31 | protected void execute() { | 32 | protected void execute() { |
32 | init(); | 33 | init(); |
34 | + if (outputJson()) { | ||
35 | + print("%s", new ObjectMapper().createObjectNode() | ||
36 | + .put("time", topology.time()) | ||
37 | + .put("deviceCount", topology.deviceCount()) | ||
38 | + .put("linkCount", topology.linkCount()) | ||
39 | + .put("clusterCount", topology.clusterCount()) | ||
40 | + .put("pathCount", topology.pathCount())); | ||
41 | + } else { | ||
33 | print(FMT, topology.time(), topology.deviceCount(), topology.linkCount(), | 42 | print(FMT, topology.time(), topology.deviceCount(), topology.linkCount(), |
34 | topology.clusterCount(), topology.pathCount()); | 43 | topology.clusterCount(), topology.pathCount()); |
35 | } | 44 | } |
45 | + } | ||
36 | 46 | ||
37 | } | 47 | } | ... | ... |
... | @@ -12,8 +12,12 @@ public final class ControllerNodeToNodeId | ... | @@ -12,8 +12,12 @@ public final class ControllerNodeToNodeId |
12 | 12 | ||
13 | @Override | 13 | @Override |
14 | public NodeId apply(ControllerNode input) { | 14 | public NodeId apply(ControllerNode input) { |
15 | + if (input == null) { | ||
16 | + return null; | ||
17 | + } else { | ||
15 | return input.id(); | 18 | return input.id(); |
16 | } | 19 | } |
20 | + } | ||
17 | 21 | ||
18 | /** | 22 | /** |
19 | * Returns a Function to convert ControllerNode to NodeId. | 23 | * Returns a Function to convert ControllerNode to NodeId. | ... | ... |
1 | package org.onlab.onos.net.host; | 1 | package org.onlab.onos.net.host; |
2 | 2 | ||
3 | +import java.util.Collections; | ||
4 | +import java.util.Set; | ||
5 | + | ||
3 | import org.onlab.onos.net.AbstractDescription; | 6 | import org.onlab.onos.net.AbstractDescription; |
4 | import org.onlab.onos.net.HostLocation; | 7 | import org.onlab.onos.net.HostLocation; |
5 | import org.onlab.onos.net.SparseAnnotations; | 8 | import org.onlab.onos.net.SparseAnnotations; |
... | @@ -7,6 +10,8 @@ import org.onlab.packet.IpPrefix; | ... | @@ -7,6 +10,8 @@ import org.onlab.packet.IpPrefix; |
7 | import org.onlab.packet.MacAddress; | 10 | import org.onlab.packet.MacAddress; |
8 | import org.onlab.packet.VlanId; | 11 | import org.onlab.packet.VlanId; |
9 | 12 | ||
13 | +import com.google.common.collect.ImmutableSet; | ||
14 | + | ||
10 | import static com.google.common.base.MoreObjects.toStringHelper; | 15 | import static com.google.common.base.MoreObjects.toStringHelper; |
11 | 16 | ||
12 | /** | 17 | /** |
... | @@ -18,7 +23,7 @@ public class DefaultHostDescription extends AbstractDescription | ... | @@ -18,7 +23,7 @@ public class DefaultHostDescription extends AbstractDescription |
18 | private final MacAddress mac; | 23 | private final MacAddress mac; |
19 | private final VlanId vlan; | 24 | private final VlanId vlan; |
20 | private final HostLocation location; | 25 | private final HostLocation location; |
21 | - private final IpPrefix ip; | 26 | + private final Set<IpPrefix> ip; |
22 | 27 | ||
23 | /** | 28 | /** |
24 | * Creates a host description using the supplied information. | 29 | * Creates a host description using the supplied information. |
... | @@ -31,7 +36,7 @@ public class DefaultHostDescription extends AbstractDescription | ... | @@ -31,7 +36,7 @@ public class DefaultHostDescription extends AbstractDescription |
31 | public DefaultHostDescription(MacAddress mac, VlanId vlan, | 36 | public DefaultHostDescription(MacAddress mac, VlanId vlan, |
32 | HostLocation location, | 37 | HostLocation location, |
33 | SparseAnnotations... annotations) { | 38 | SparseAnnotations... annotations) { |
34 | - this(mac, vlan, location, null, annotations); | 39 | + this(mac, vlan, location, Collections.<IpPrefix>emptySet(), annotations); |
35 | } | 40 | } |
36 | 41 | ||
37 | /** | 42 | /** |
... | @@ -46,11 +51,26 @@ public class DefaultHostDescription extends AbstractDescription | ... | @@ -46,11 +51,26 @@ public class DefaultHostDescription extends AbstractDescription |
46 | public DefaultHostDescription(MacAddress mac, VlanId vlan, | 51 | public DefaultHostDescription(MacAddress mac, VlanId vlan, |
47 | HostLocation location, IpPrefix ip, | 52 | HostLocation location, IpPrefix ip, |
48 | SparseAnnotations... annotations) { | 53 | SparseAnnotations... annotations) { |
54 | + this(mac, vlan, location, ImmutableSet.of(ip), annotations); | ||
55 | + } | ||
56 | + | ||
57 | + /** | ||
58 | + * Creates a host description using the supplied information. | ||
59 | + * | ||
60 | + * @param mac host MAC address | ||
61 | + * @param vlan host VLAN identifier | ||
62 | + * @param location host location | ||
63 | + * @param ip host IP addresses | ||
64 | + * @param annotations optional key/value annotations map | ||
65 | + */ | ||
66 | + public DefaultHostDescription(MacAddress mac, VlanId vlan, | ||
67 | + HostLocation location, Set<IpPrefix> ip, | ||
68 | + SparseAnnotations... annotations) { | ||
49 | super(annotations); | 69 | super(annotations); |
50 | this.mac = mac; | 70 | this.mac = mac; |
51 | this.vlan = vlan; | 71 | this.vlan = vlan; |
52 | this.location = location; | 72 | this.location = location; |
53 | - this.ip = ip; | 73 | + this.ip = ImmutableSet.copyOf(ip); |
54 | } | 74 | } |
55 | 75 | ||
56 | @Override | 76 | @Override |
... | @@ -69,7 +89,7 @@ public class DefaultHostDescription extends AbstractDescription | ... | @@ -69,7 +89,7 @@ public class DefaultHostDescription extends AbstractDescription |
69 | } | 89 | } |
70 | 90 | ||
71 | @Override | 91 | @Override |
72 | - public IpPrefix ipAddress() { | 92 | + public Set<IpPrefix> ipAddress() { |
73 | return ip; | 93 | return ip; |
74 | } | 94 | } |
75 | 95 | ... | ... |
1 | package org.onlab.onos.net.host; | 1 | package org.onlab.onos.net.host; |
2 | 2 | ||
3 | +import java.util.Set; | ||
4 | + | ||
3 | import org.onlab.onos.net.Description; | 5 | import org.onlab.onos.net.Description; |
4 | import org.onlab.onos.net.HostLocation; | 6 | import org.onlab.onos.net.HostLocation; |
5 | import org.onlab.packet.IpPrefix; | 7 | import org.onlab.packet.IpPrefix; |
... | @@ -38,6 +40,6 @@ public interface HostDescription extends Description { | ... | @@ -38,6 +40,6 @@ public interface HostDescription extends Description { |
38 | * @return host IP address | 40 | * @return host IP address |
39 | */ | 41 | */ |
40 | // FIXME: Switch to IpAddress | 42 | // FIXME: Switch to IpAddress |
41 | - IpPrefix ipAddress(); | 43 | + Set<IpPrefix> ipAddress(); |
42 | 44 | ||
43 | } | 45 | } | ... | ... |
... | @@ -12,7 +12,7 @@ import static com.google.common.base.Preconditions.checkNotNull; | ... | @@ -12,7 +12,7 @@ import static com.google.common.base.Preconditions.checkNotNull; |
12 | /** | 12 | /** |
13 | * Abstraction of end-station to end-station bidirectional connectivity. | 13 | * Abstraction of end-station to end-station bidirectional connectivity. |
14 | */ | 14 | */ |
15 | -public class HostToHostIntent extends ConnectivityIntent { | 15 | +public final class HostToHostIntent extends ConnectivityIntent { |
16 | 16 | ||
17 | private final HostId one; | 17 | private final HostId one; |
18 | private final HostId two; | 18 | private final HostId two; | ... | ... |
... | @@ -14,7 +14,7 @@ import com.google.common.base.MoreObjects; | ... | @@ -14,7 +14,7 @@ import com.google.common.base.MoreObjects; |
14 | * Abstraction of a connectivity intent that is implemented by a set of path | 14 | * Abstraction of a connectivity intent that is implemented by a set of path |
15 | * segments. | 15 | * segments. |
16 | */ | 16 | */ |
17 | -public class LinkCollectionIntent extends ConnectivityIntent implements InstallableIntent { | 17 | +public final class LinkCollectionIntent extends ConnectivityIntent implements InstallableIntent { |
18 | 18 | ||
19 | private final Set<Link> links; | 19 | private final Set<Link> links; |
20 | 20 | ||
... | @@ -46,6 +46,12 @@ public class LinkCollectionIntent extends ConnectivityIntent implements Installa | ... | @@ -46,6 +46,12 @@ public class LinkCollectionIntent extends ConnectivityIntent implements Installa |
46 | return links; | 46 | return links; |
47 | } | 47 | } |
48 | 48 | ||
49 | + /** | ||
50 | + * Returns the set of links that represent the network connections needed | ||
51 | + * by this intent. | ||
52 | + * | ||
53 | + * @return Set of links for the network hops needed by this intent | ||
54 | + */ | ||
49 | public Set<Link> links() { | 55 | public Set<Link> links() { |
50 | return links; | 56 | return links; |
51 | } | 57 | } | ... | ... |
... | @@ -15,7 +15,7 @@ import static com.google.common.base.Preconditions.checkNotNull; | ... | @@ -15,7 +15,7 @@ import static com.google.common.base.Preconditions.checkNotNull; |
15 | /** | 15 | /** |
16 | * Abstraction of multiple source to single destination connectivity intent. | 16 | * Abstraction of multiple source to single destination connectivity intent. |
17 | */ | 17 | */ |
18 | -public class MultiPointToSinglePointIntent extends ConnectivityIntent { | 18 | +public final class MultiPointToSinglePointIntent extends ConnectivityIntent { |
19 | 19 | ||
20 | private final Set<ConnectPoint> ingressPoints; | 20 | private final Set<ConnectPoint> ingressPoints; |
21 | private final ConnectPoint egressPoint; | 21 | private final ConnectPoint egressPoint; | ... | ... |
1 | package org.onlab.onos.cluster; | 1 | package org.onlab.onos.cluster; |
2 | 2 | ||
3 | +import static com.google.common.base.Predicates.notNull; | ||
3 | import static org.junit.Assert.*; | 4 | import static org.junit.Assert.*; |
4 | import static org.onlab.onos.cluster.ControllerNodeToNodeId.toNodeId; | 5 | import static org.onlab.onos.cluster.ControllerNodeToNodeId.toNodeId; |
5 | 6 | ||
... | @@ -30,12 +31,13 @@ public class ControllerNodeToNodeIdTest { | ... | @@ -30,12 +31,13 @@ public class ControllerNodeToNodeIdTest { |
30 | @Test | 31 | @Test |
31 | public final void testToNodeId() { | 32 | public final void testToNodeId() { |
32 | 33 | ||
33 | - final Iterable<ControllerNode> nodes = Arrays.asList(CN1, CN2, CN3); | 34 | + final Iterable<ControllerNode> nodes = Arrays.asList(CN1, CN2, CN3, null); |
34 | final List<NodeId> nodeIds = Arrays.asList(NID1, NID2, NID3); | 35 | final List<NodeId> nodeIds = Arrays.asList(NID1, NID2, NID3); |
35 | 36 | ||
36 | assertEquals(nodeIds, | 37 | assertEquals(nodeIds, |
37 | FluentIterable.from(nodes) | 38 | FluentIterable.from(nodes) |
38 | .transform(toNodeId()) | 39 | .transform(toNodeId()) |
40 | + .filter(notNull()) | ||
39 | .toList()); | 41 | .toList()); |
40 | } | 42 | } |
41 | 43 | ... | ... |
... | @@ -48,10 +48,16 @@ public final class NetTestTools { | ... | @@ -48,10 +48,16 @@ public final class NetTestTools { |
48 | new HashSet<IpPrefix>()); | 48 | new HashSet<IpPrefix>()); |
49 | } | 49 | } |
50 | 50 | ||
51 | + // Short-hand for creating a connection point. | ||
52 | + public static ConnectPoint connectPoint(String id, int port) { | ||
53 | + return new ConnectPoint(did(id), portNumber(port)); | ||
54 | + } | ||
55 | + | ||
51 | // Short-hand for creating a link. | 56 | // Short-hand for creating a link. |
52 | public static Link link(String src, int sp, String dst, int dp) { | 57 | public static Link link(String src, int sp, String dst, int dp) { |
53 | - return new DefaultLink(PID, new ConnectPoint(did(src), portNumber(sp)), | 58 | + return new DefaultLink(PID, |
54 | - new ConnectPoint(did(dst), portNumber(dp)), | 59 | + connectPoint(src, sp), |
60 | + connectPoint(dst, dp), | ||
55 | Link.Type.DIRECT); | 61 | Link.Type.DIRECT); |
56 | } | 62 | } |
57 | 63 | ... | ... |
... | @@ -8,6 +8,8 @@ import org.onlab.packet.IpPrefix; | ... | @@ -8,6 +8,8 @@ import org.onlab.packet.IpPrefix; |
8 | import org.onlab.packet.MacAddress; | 8 | import org.onlab.packet.MacAddress; |
9 | import org.onlab.packet.VlanId; | 9 | import org.onlab.packet.VlanId; |
10 | 10 | ||
11 | +import com.google.common.collect.ImmutableSet; | ||
12 | + | ||
11 | import static org.junit.Assert.assertEquals; | 13 | import static org.junit.Assert.assertEquals; |
12 | import static org.junit.Assert.assertTrue; | 14 | import static org.junit.Assert.assertTrue; |
13 | 15 | ||
... | @@ -33,7 +35,7 @@ public class DefualtHostDecriptionTest { | ... | @@ -33,7 +35,7 @@ public class DefualtHostDecriptionTest { |
33 | assertEquals("incorrect mac", MAC, host.hwAddress()); | 35 | assertEquals("incorrect mac", MAC, host.hwAddress()); |
34 | assertEquals("incorrect vlan", VLAN, host.vlan()); | 36 | assertEquals("incorrect vlan", VLAN, host.vlan()); |
35 | assertEquals("incorrect location", LOC, host.location()); | 37 | assertEquals("incorrect location", LOC, host.location()); |
36 | - assertEquals("incorrect ip's", IP, host.ipAddress()); | 38 | + assertEquals("incorrect ip's", ImmutableSet.of(IP), host.ipAddress()); |
37 | assertTrue("incorrect toString", host.toString().contains("vlan=10")); | 39 | assertTrue("incorrect toString", host.toString().contains("vlan=10")); |
38 | } | 40 | } |
39 | 41 | ... | ... |
... | @@ -6,15 +6,15 @@ | ... | @@ -6,15 +6,15 @@ |
6 | 6 | ||
7 | <parent> | 7 | <parent> |
8 | <groupId>org.onlab.onos</groupId> | 8 | <groupId>org.onlab.onos</groupId> |
9 | - <artifactId>onos-core-hz</artifactId> | 9 | + <artifactId>onos-core</artifactId> |
10 | <version>1.0.0-SNAPSHOT</version> | 10 | <version>1.0.0-SNAPSHOT</version> |
11 | <relativePath>../pom.xml</relativePath> | 11 | <relativePath>../pom.xml</relativePath> |
12 | </parent> | 12 | </parent> |
13 | 13 | ||
14 | - <artifactId>onos-core-hz-net</artifactId> | 14 | + <artifactId>onos-json</artifactId> |
15 | <packaging>bundle</packaging> | 15 | <packaging>bundle</packaging> |
16 | 16 | ||
17 | - <description>ONOS Hazelcast based distributed store subsystems</description> | 17 | + <description>ONOS JSON encode/decode facilities</description> |
18 | 18 | ||
19 | <dependencies> | 19 | <dependencies> |
20 | <dependency> | 20 | <dependency> |
... | @@ -23,24 +23,22 @@ | ... | @@ -23,24 +23,22 @@ |
23 | </dependency> | 23 | </dependency> |
24 | <dependency> | 24 | <dependency> |
25 | <groupId>org.onlab.onos</groupId> | 25 | <groupId>org.onlab.onos</groupId> |
26 | - <artifactId>onos-core-hz-common</artifactId> | 26 | + <artifactId>onos-api</artifactId> |
27 | - <version>${project.version}</version> | 27 | + <classifier>tests</classifier> |
28 | + <scope>test</scope> | ||
28 | </dependency> | 29 | </dependency> |
30 | + | ||
29 | <dependency> | 31 | <dependency> |
30 | <groupId>org.onlab.onos</groupId> | 32 | <groupId>org.onlab.onos</groupId> |
31 | - <artifactId>onos-core-hz-common</artifactId> | 33 | + <artifactId>onos-core-trivial</artifactId> |
32 | - <classifier>tests</classifier> | ||
33 | - <scope>test</scope> | ||
34 | <version>${project.version}</version> | 34 | <version>${project.version}</version> |
35 | + <scope>test</scope> | ||
35 | </dependency> | 36 | </dependency> |
37 | + | ||
36 | <dependency> | 38 | <dependency> |
37 | <groupId>org.apache.felix</groupId> | 39 | <groupId>org.apache.felix</groupId> |
38 | <artifactId>org.apache.felix.scr.annotations</artifactId> | 40 | <artifactId>org.apache.felix.scr.annotations</artifactId> |
39 | </dependency> | 41 | </dependency> |
40 | - <dependency> | ||
41 | - <groupId>com.hazelcast</groupId> | ||
42 | - <artifactId>hazelcast</artifactId> | ||
43 | - </dependency> | ||
44 | </dependencies> | 42 | </dependencies> |
45 | 43 | ||
46 | <build> | 44 | <build> | ... | ... |
... | @@ -42,23 +42,6 @@ | ... | @@ -42,23 +42,6 @@ |
42 | <scope>test</scope> | 42 | <scope>test</scope> |
43 | </dependency> | 43 | </dependency> |
44 | 44 | ||
45 | - <!-- TODO Consider removing store dependency. | ||
46 | - Currently required for DistributedDeviceManagerTest. --> | ||
47 | - <dependency> | ||
48 | - <groupId>org.onlab.onos</groupId> | ||
49 | - <artifactId>onos-core-hz-net</artifactId> | ||
50 | - <version>${project.version}</version> | ||
51 | - <scope>test</scope> | ||
52 | - </dependency> | ||
53 | - <dependency> | ||
54 | - <groupId>org.onlab.onos</groupId> | ||
55 | - <!-- FIXME: should be somewhere else --> | ||
56 | - <artifactId>onos-core-hz-common</artifactId> | ||
57 | - <version>${project.version}</version> | ||
58 | - <classifier>tests</classifier> | ||
59 | - <scope>test</scope> | ||
60 | - </dependency> | ||
61 | - | ||
62 | <dependency> | 45 | <dependency> |
63 | <groupId>org.apache.felix</groupId> | 46 | <groupId>org.apache.felix</groupId> |
64 | <artifactId>org.apache.felix.scr.annotations</artifactId> | 47 | <artifactId>org.apache.felix.scr.annotations</artifactId> | ... | ... |
... | @@ -41,7 +41,7 @@ public class HostToHostIntentCompiler | ... | @@ -41,7 +41,7 @@ public class HostToHostIntentCompiler |
41 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 41 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
42 | protected HostService hostService; | 42 | protected HostService hostService; |
43 | 43 | ||
44 | - private IdGenerator<IntentId> intentIdGenerator; | 44 | + protected IdGenerator<IntentId> intentIdGenerator; |
45 | 45 | ||
46 | @Activate | 46 | @Activate |
47 | public void activate() { | 47 | public void activate() { | ... | ... |
... | @@ -37,7 +37,7 @@ public class MultiPointToSinglePointIntentCompiler | ... | @@ -37,7 +37,7 @@ public class MultiPointToSinglePointIntentCompiler |
37 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 37 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
38 | protected PathService pathService; | 38 | protected PathService pathService; |
39 | 39 | ||
40 | - private IdGenerator<IntentId> intentIdGenerator; | 40 | + protected IdGenerator<IntentId> intentIdGenerator; |
41 | 41 | ||
42 | @Activate | 42 | @Activate |
43 | public void activate() { | 43 | public void activate() { | ... | ... |
... | @@ -355,7 +355,7 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -355,7 +355,7 @@ public class ProxyArpManager implements ProxyArpService { |
355 | 355 | ||
356 | arp.setTargetProtocolAddress(((ARP) request.getPayload()) | 356 | arp.setTargetProtocolAddress(((ARP) request.getPayload()) |
357 | .getSenderProtocolAddress()); | 357 | .getSenderProtocolAddress()); |
358 | - arp.setSenderProtocolAddress(srcIp.toRealInt()); | 358 | + arp.setSenderProtocolAddress(srcIp.toInt()); |
359 | eth.setPayload(arp); | 359 | eth.setPayload(arp); |
360 | return eth; | 360 | return eth; |
361 | } | 361 | } | ... | ... |
1 | +package org.onlab.onos.net.intent; | ||
2 | + | ||
3 | +import java.util.ArrayList; | ||
4 | +import java.util.Arrays; | ||
5 | +import java.util.Collections; | ||
6 | +import java.util.HashSet; | ||
7 | +import java.util.List; | ||
8 | +import java.util.Set; | ||
9 | + | ||
10 | +import org.onlab.onos.net.ElementId; | ||
11 | +import org.onlab.onos.net.Path; | ||
12 | +import org.onlab.onos.net.flow.TrafficSelector; | ||
13 | +import org.onlab.onos.net.flow.TrafficTreatment; | ||
14 | +import org.onlab.onos.net.flow.criteria.Criterion; | ||
15 | +import org.onlab.onos.net.flow.instructions.Instruction; | ||
16 | +import org.onlab.onos.net.topology.LinkWeight; | ||
17 | +import org.onlab.onos.net.topology.PathService; | ||
18 | + | ||
19 | +import static org.onlab.onos.net.NetTestTools.createPath; | ||
20 | + | ||
21 | +/** | ||
22 | + * Common mocks used by the intent framework tests. | ||
23 | + */ | ||
24 | +public class IntentTestsMocks { | ||
25 | + /** | ||
26 | + * Mock traffic selector class used for satisfying API requirements. | ||
27 | + */ | ||
28 | + public static class MockSelector implements TrafficSelector { | ||
29 | + @Override | ||
30 | + public Set<Criterion> criteria() { | ||
31 | + return new HashSet<>(); | ||
32 | + } | ||
33 | + } | ||
34 | + | ||
35 | + /** | ||
36 | + * Mock traffic treatment class used for satisfying API requirements. | ||
37 | + */ | ||
38 | + public static class MockTreatment implements TrafficTreatment { | ||
39 | + @Override | ||
40 | + public List<Instruction> instructions() { | ||
41 | + return new ArrayList<>(); | ||
42 | + } | ||
43 | + } | ||
44 | + | ||
45 | + /** | ||
46 | + * Mock path service for creating paths within the test. | ||
47 | + */ | ||
48 | + public static class MockPathService implements PathService { | ||
49 | + | ||
50 | + final String[] pathHops; | ||
51 | + final String[] reversePathHops; | ||
52 | + | ||
53 | + /** | ||
54 | + * Constructor that provides a set of hops to mock. | ||
55 | + * | ||
56 | + * @param pathHops path hops to mock | ||
57 | + */ | ||
58 | + public MockPathService(String[] pathHops) { | ||
59 | + this.pathHops = pathHops; | ||
60 | + String[] reversed = pathHops.clone(); | ||
61 | + Collections.reverse(Arrays.asList(reversed)); | ||
62 | + reversePathHops = reversed; | ||
63 | + } | ||
64 | + | ||
65 | + @Override | ||
66 | + public Set<Path> getPaths(ElementId src, ElementId dst) { | ||
67 | + Set<Path> result = new HashSet<>(); | ||
68 | + | ||
69 | + String[] allHops = new String[pathHops.length]; | ||
70 | + | ||
71 | + if (src.toString().endsWith(pathHops[0])) { | ||
72 | + System.arraycopy(pathHops, 0, allHops, 0, pathHops.length); | ||
73 | + } else { | ||
74 | + System.arraycopy(reversePathHops, 0, allHops, 0, pathHops.length); | ||
75 | + } | ||
76 | + | ||
77 | + result.add(createPath(allHops)); | ||
78 | + return result; | ||
79 | + } | ||
80 | + | ||
81 | + @Override | ||
82 | + public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeight weight) { | ||
83 | + return getPaths(src, dst); | ||
84 | + } | ||
85 | + } | ||
86 | +} |
core/net/src/test/java/org/onlab/onos/net/intent/LinksHaveEntryWithSourceDestinationPairMatcher.java
0 → 100644
1 | +package org.onlab.onos.net.intent; | ||
2 | + | ||
3 | +import java.util.Collection; | ||
4 | + | ||
5 | +import org.hamcrest.Description; | ||
6 | +import org.hamcrest.TypeSafeMatcher; | ||
7 | +import org.onlab.onos.net.Link; | ||
8 | + | ||
9 | +/** | ||
10 | + * Matcher to determine if a Collection of Links contains a path between a source | ||
11 | + * and a destination. | ||
12 | + */ | ||
13 | +public class LinksHaveEntryWithSourceDestinationPairMatcher extends | ||
14 | + TypeSafeMatcher<Collection<Link>> { | ||
15 | + private final String source; | ||
16 | + private final String destination; | ||
17 | + | ||
18 | + /** | ||
19 | + * Creates a matcher for a given path represented by a source and | ||
20 | + * a destination. | ||
21 | + * | ||
22 | + * @param source string identifier for the source of the path | ||
23 | + * @param destination string identifier for the destination of the path | ||
24 | + */ | ||
25 | + LinksHaveEntryWithSourceDestinationPairMatcher(String source, | ||
26 | + String destination) { | ||
27 | + this.source = source; | ||
28 | + this.destination = destination; | ||
29 | + } | ||
30 | + | ||
31 | + @Override | ||
32 | + public boolean matchesSafely(Collection<Link> links) { | ||
33 | + for (Link link : links) { | ||
34 | + if (link.src().elementId().toString().endsWith(source) && | ||
35 | + link.dst().elementId().toString().endsWith(destination)) { | ||
36 | + return true; | ||
37 | + } | ||
38 | + } | ||
39 | + | ||
40 | + return false; | ||
41 | + } | ||
42 | + | ||
43 | + @Override | ||
44 | + public void describeTo(Description description) { | ||
45 | + description.appendText("link lookup for source \""); | ||
46 | + description.appendText(source); | ||
47 | + description.appendText(" and destination "); | ||
48 | + description.appendText(destination); | ||
49 | + description.appendText("\""); | ||
50 | + } | ||
51 | + | ||
52 | + @Override | ||
53 | + public void describeMismatchSafely(Collection<Link> links, | ||
54 | + Description mismatchDescription) { | ||
55 | + mismatchDescription.appendText("was "). | ||
56 | + appendText(links.toString()); | ||
57 | + } | ||
58 | + | ||
59 | + /** | ||
60 | + * Creates a link has path matcher. | ||
61 | + * | ||
62 | + * @param source string identifier for the source of the path | ||
63 | + * @param destination string identifier for the destination of the path | ||
64 | + * @return matcher to match the path | ||
65 | + */ | ||
66 | + public static LinksHaveEntryWithSourceDestinationPairMatcher linksHasPath( | ||
67 | + String source, | ||
68 | + String destination) { | ||
69 | + return new LinksHaveEntryWithSourceDestinationPairMatcher(source, | ||
70 | + destination); | ||
71 | + } | ||
72 | +} | ||
73 | + |
1 | +package org.onlab.onos.net.intent; | ||
2 | + | ||
3 | +import org.junit.Test; | ||
4 | +import org.onlab.onos.net.HostId; | ||
5 | +import org.onlab.onos.net.flow.TrafficSelector; | ||
6 | +import org.onlab.onos.net.flow.TrafficTreatment; | ||
7 | + | ||
8 | +import static org.hamcrest.MatcherAssert.assertThat; | ||
9 | +import static org.hamcrest.Matchers.equalTo; | ||
10 | +import static org.hamcrest.Matchers.is; | ||
11 | +import static org.hamcrest.Matchers.not; | ||
12 | +import static org.onlab.onos.net.NetTestTools.hid; | ||
13 | + | ||
14 | +/** | ||
15 | + * Unit tests for the HostToHostIntent class. | ||
16 | + */ | ||
17 | +public class TestHostToHostIntent { | ||
18 | + | ||
19 | + private TrafficSelector selector = new IntentTestsMocks.MockSelector(); | ||
20 | + private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment(); | ||
21 | + | ||
22 | + private HostToHostIntent makeHostToHost(long id, HostId one, HostId two) { | ||
23 | + return new HostToHostIntent(new IntentId(id), | ||
24 | + one, | ||
25 | + two, | ||
26 | + selector, | ||
27 | + treatment); | ||
28 | + } | ||
29 | + | ||
30 | + /** | ||
31 | + * Tests the equals() method where two HostToHostIntents have references | ||
32 | + * to the same hosts. These should compare equal. | ||
33 | + */ | ||
34 | + @Test | ||
35 | + public void testSameEquals() { | ||
36 | + | ||
37 | + HostId one = hid("00:00:00:00:00:01/-1"); | ||
38 | + HostId two = hid("00:00:00:00:00:02/-1"); | ||
39 | + HostToHostIntent i1 = makeHostToHost(12, one, two); | ||
40 | + HostToHostIntent i2 = makeHostToHost(12, one, two); | ||
41 | + | ||
42 | + assertThat(i1, is(equalTo(i2))); | ||
43 | + } | ||
44 | + | ||
45 | + /** | ||
46 | + * Tests the equals() method where two HostToHostIntents have references | ||
47 | + * to different Hosts. These should compare not equal. | ||
48 | + */ | ||
49 | + @Test | ||
50 | + public void testLinksDifferentEquals() { | ||
51 | + | ||
52 | + HostId one = hid("00:00:00:00:00:01/-1"); | ||
53 | + HostId two = hid("00:00:00:00:00:02/-1"); | ||
54 | + HostToHostIntent i1 = makeHostToHost(12, one, two); | ||
55 | + HostToHostIntent i2 = makeHostToHost(12, two, one); | ||
56 | + | ||
57 | + assertThat(i1, is(not(equalTo(i2)))); | ||
58 | + } | ||
59 | + | ||
60 | + /** | ||
61 | + * Tests the equals() method where two HostToHostIntents have different | ||
62 | + * ids. These should compare not equal. | ||
63 | + */ | ||
64 | + | ||
65 | + @Test | ||
66 | + public void testBaseDifferentEquals() { | ||
67 | + HostId one = hid("00:00:00:00:00:01/-1"); | ||
68 | + HostId two = hid("00:00:00:00:00:02/-1"); | ||
69 | + HostToHostIntent i1 = makeHostToHost(12, one, two); | ||
70 | + HostToHostIntent i2 = makeHostToHost(11, one, two); | ||
71 | + | ||
72 | + assertThat(i1, is(not(equalTo(i2)))); | ||
73 | + } | ||
74 | + | ||
75 | + /** | ||
76 | + * Tests that the hashCode() values for two equivalent HostToHostIntent | ||
77 | + * objects are the same. | ||
78 | + */ | ||
79 | + | ||
80 | + @Test | ||
81 | + public void testHashCodeEquals() { | ||
82 | + HostId one = hid("00:00:00:00:00:01/-1"); | ||
83 | + HostId two = hid("00:00:00:00:00:02/-1"); | ||
84 | + HostToHostIntent i1 = makeHostToHost(12, one, two); | ||
85 | + HostToHostIntent i2 = makeHostToHost(12, one, two); | ||
86 | + | ||
87 | + assertThat(i1.hashCode(), is(equalTo(i2.hashCode()))); | ||
88 | + } | ||
89 | + | ||
90 | + /** | ||
91 | + * Tests that the hashCode() values for two distinct LinkCollectionIntent | ||
92 | + * objects are different. | ||
93 | + */ | ||
94 | + | ||
95 | + @Test | ||
96 | + public void testHashCodeDifferent() { | ||
97 | + HostId one = hid("00:00:00:00:00:01/-1"); | ||
98 | + HostId two = hid("00:00:00:00:00:02/-1"); | ||
99 | + HostToHostIntent i1 = makeHostToHost(12, one, two); | ||
100 | + HostToHostIntent i2 = makeHostToHost(112, one, two); | ||
101 | + | ||
102 | + assertThat(i1.hashCode(), is(not(equalTo(i2.hashCode())))); | ||
103 | + } | ||
104 | + | ||
105 | + /** | ||
106 | + * Checks that the HostToHostIntent class is immutable. | ||
107 | + */ | ||
108 | + @Test | ||
109 | + public void checkImmutability() { | ||
110 | + ImmutableClassChecker.assertThatClassIsImmutable(HostToHostIntent.class); | ||
111 | + } | ||
112 | +} |
1 | package org.onlab.onos.net.intent; | 1 | package org.onlab.onos.net.intent; |
2 | 2 | ||
3 | -import java.util.ArrayList; | ||
4 | import java.util.HashSet; | 3 | import java.util.HashSet; |
5 | -import java.util.List; | ||
6 | import java.util.Set; | 4 | import java.util.Set; |
7 | 5 | ||
6 | +import org.junit.Before; | ||
8 | import org.junit.Test; | 7 | import org.junit.Test; |
9 | import org.onlab.onos.net.Link; | 8 | import org.onlab.onos.net.Link; |
10 | import org.onlab.onos.net.flow.TrafficSelector; | 9 | import org.onlab.onos.net.flow.TrafficSelector; |
11 | import org.onlab.onos.net.flow.TrafficTreatment; | 10 | import org.onlab.onos.net.flow.TrafficTreatment; |
12 | -import org.onlab.onos.net.flow.criteria.Criterion; | ||
13 | -import org.onlab.onos.net.flow.instructions.Instruction; | ||
14 | 11 | ||
12 | +import static org.hamcrest.CoreMatchers.not; | ||
15 | import static org.hamcrest.MatcherAssert.assertThat; | 13 | import static org.hamcrest.MatcherAssert.assertThat; |
14 | +import static org.hamcrest.Matchers.equalTo; | ||
16 | import static org.hamcrest.Matchers.is; | 15 | import static org.hamcrest.Matchers.is; |
16 | +import static org.onlab.onos.net.NetTestTools.link; | ||
17 | 17 | ||
18 | +/** | ||
19 | + * Unit tests for the LinkCollectionIntent class. | ||
20 | + */ | ||
18 | public class TestLinkCollectionIntent { | 21 | public class TestLinkCollectionIntent { |
19 | 22 | ||
20 | - private static class MockSelector implements TrafficSelector { | 23 | + private Link link1 = link("dev1", 1, "dev2", 2); |
21 | - @Override | 24 | + private Link link2 = link("dev1", 1, "dev3", 2); |
22 | - public Set<Criterion> criteria() { | 25 | + private Link link3 = link("dev2", 1, "dev3", 2); |
23 | - return new HashSet<Criterion>(); | 26 | + |
27 | + private Set<Link> links1; | ||
28 | + private Set<Link> links2; | ||
29 | + | ||
30 | + private TrafficSelector selector = new IntentTestsMocks.MockSelector(); | ||
31 | + private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment(); | ||
32 | + | ||
33 | + private LinkCollectionIntent makeLinkCollection(long id, Set<Link> links) { | ||
34 | + return new LinkCollectionIntent(new IntentId(id), | ||
35 | + selector, treatment, links); | ||
24 | } | 36 | } |
37 | + | ||
38 | + @Before | ||
39 | + public void setup() { | ||
40 | + links1 = new HashSet<>(); | ||
41 | + links2 = new HashSet<>(); | ||
25 | } | 42 | } |
26 | 43 | ||
27 | - private static class MockTreatment implements TrafficTreatment { | 44 | + /** |
28 | - @Override | 45 | + * Tests the equals() method where two LinkCollectionIntents have references |
29 | - public List<Instruction> instructions() { | 46 | + * to the same Links in different orders. These should compare equal. |
30 | - return new ArrayList<>(); | 47 | + */ |
48 | + @Test | ||
49 | + public void testSameEquals() { | ||
50 | + links1.add(link1); | ||
51 | + links1.add(link2); | ||
52 | + links1.add(link3); | ||
53 | + | ||
54 | + links2.add(link3); | ||
55 | + links2.add(link2); | ||
56 | + links2.add(link1); | ||
57 | + | ||
58 | + LinkCollectionIntent i1 = makeLinkCollection(12, links1); | ||
59 | + LinkCollectionIntent i2 = makeLinkCollection(12, links2); | ||
60 | + | ||
61 | + assertThat(i1, is(equalTo(i2))); | ||
31 | } | 62 | } |
63 | + | ||
64 | + /** | ||
65 | + * Tests the equals() method where two LinkCollectionIntents have references | ||
66 | + * to different Links. These should compare not equal. | ||
67 | + */ | ||
68 | + @Test | ||
69 | + public void testLinksDifferentEquals() { | ||
70 | + links1.add(link1); | ||
71 | + links1.add(link2); | ||
72 | + | ||
73 | + links2.add(link3); | ||
74 | + links2.add(link1); | ||
75 | + | ||
76 | + LinkCollectionIntent i1 = makeLinkCollection(12, links1); | ||
77 | + LinkCollectionIntent i2 = makeLinkCollection(12, links2); | ||
78 | + | ||
79 | + assertThat(i1, is(not(equalTo(i2)))); | ||
32 | } | 80 | } |
33 | 81 | ||
82 | + /** | ||
83 | + * Tests the equals() method where two LinkCollectionIntents have different | ||
84 | + * ids. These should compare not equal. | ||
85 | + */ | ||
34 | @Test | 86 | @Test |
35 | - public void testComparison() { | 87 | + public void testBaseDifferentEquals() { |
36 | - TrafficSelector selector = new MockSelector(); | 88 | + links1.add(link1); |
37 | - TrafficTreatment treatment = new MockTreatment(); | 89 | + links1.add(link2); |
38 | - Set<Link> links = new HashSet<>(); | ||
39 | - LinkCollectionIntent i1 = new LinkCollectionIntent(new IntentId(12), | ||
40 | - selector, treatment, links); | ||
41 | - LinkCollectionIntent i2 = new LinkCollectionIntent(new IntentId(12), | ||
42 | - selector, treatment, links); | ||
43 | 90 | ||
44 | - assertThat(i1.equals(i2), is(true)); | 91 | + links2.add(link2); |
92 | + links2.add(link1); | ||
93 | + | ||
94 | + LinkCollectionIntent i1 = makeLinkCollection(1, links1); | ||
95 | + LinkCollectionIntent i2 = makeLinkCollection(2, links2); | ||
96 | + | ||
97 | + assertThat(i1, is(not(equalTo(i2)))); | ||
98 | + } | ||
99 | + | ||
100 | + /** | ||
101 | + * Tests that the hashCode() values for two equivalent LinkCollectionIntent | ||
102 | + * objects are the same. | ||
103 | + */ | ||
104 | + @Test | ||
105 | + public void testHashCodeEquals() { | ||
106 | + links1.add(link1); | ||
107 | + links1.add(link2); | ||
108 | + links1.add(link3); | ||
109 | + | ||
110 | + links2.add(link3); | ||
111 | + links2.add(link2); | ||
112 | + links2.add(link1); | ||
113 | + | ||
114 | + LinkCollectionIntent i1 = makeLinkCollection(1, links1); | ||
115 | + LinkCollectionIntent i2 = makeLinkCollection(1, links2); | ||
116 | + | ||
117 | + assertThat(i1.hashCode(), is(equalTo(i2.hashCode()))); | ||
45 | } | 118 | } |
46 | 119 | ||
120 | + /** | ||
121 | + * Tests that the hashCode() values for two distinct LinkCollectionIntent | ||
122 | + * objects are different. | ||
123 | + */ | ||
124 | + @Test | ||
125 | + public void testHashCodeDifferent() { | ||
126 | + links1.add(link1); | ||
127 | + links1.add(link2); | ||
128 | + | ||
129 | + links2.add(link1); | ||
130 | + links2.add(link3); | ||
131 | + | ||
132 | + LinkCollectionIntent i1 = makeLinkCollection(1, links1); | ||
133 | + LinkCollectionIntent i2 = makeLinkCollection(1, links2); | ||
134 | + | ||
135 | + assertThat(i1.hashCode(), is(not(equalTo(i2.hashCode())))); | ||
136 | + } | ||
137 | + | ||
138 | + /** | ||
139 | + * Checks that the HostToHostIntent class is immutable. | ||
140 | + */ | ||
141 | + @Test | ||
142 | + public void checkImmutability() { | ||
143 | + ImmutableClassChecker.assertThatClassIsImmutable(LinkCollectionIntent.class); | ||
144 | + } | ||
47 | } | 145 | } | ... | ... |
1 | +package org.onlab.onos.net.intent; | ||
2 | + | ||
3 | +import java.util.HashSet; | ||
4 | +import java.util.Set; | ||
5 | + | ||
6 | +import org.junit.Before; | ||
7 | +import org.junit.Test; | ||
8 | +import org.onlab.onos.net.ConnectPoint; | ||
9 | +import org.onlab.onos.net.flow.TrafficSelector; | ||
10 | +import org.onlab.onos.net.flow.TrafficTreatment; | ||
11 | + | ||
12 | +import static org.hamcrest.CoreMatchers.not; | ||
13 | +import static org.hamcrest.MatcherAssert.assertThat; | ||
14 | +import static org.hamcrest.Matchers.equalTo; | ||
15 | +import static org.hamcrest.Matchers.is; | ||
16 | +import static org.onlab.onos.net.NetTestTools.connectPoint; | ||
17 | + | ||
18 | +/** | ||
19 | + * Unit tests for the MultiPointToSinglePointIntent class. | ||
20 | + */ | ||
21 | +public class TestMultiPointToSinglePointIntent { | ||
22 | + | ||
23 | + private ConnectPoint point1 = connectPoint("dev1", 1); | ||
24 | + private ConnectPoint point2 = connectPoint("dev2", 1); | ||
25 | + private ConnectPoint point3 = connectPoint("dev3", 1); | ||
26 | + | ||
27 | + private TrafficSelector selector = new IntentTestsMocks.MockSelector(); | ||
28 | + private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment(); | ||
29 | + | ||
30 | + Set<ConnectPoint> ingress1; | ||
31 | + Set<ConnectPoint> ingress2; | ||
32 | + | ||
33 | + /** | ||
34 | + * Creates a MultiPointToSinglePointIntent object. | ||
35 | + * | ||
36 | + * @param id identifier to use for the new intent | ||
37 | + * @param ingress set of ingress points | ||
38 | + * @param egress egress point | ||
39 | + * @return MultiPointToSinglePoint intent | ||
40 | + */ | ||
41 | + private MultiPointToSinglePointIntent makeIntent(long id, | ||
42 | + Set<ConnectPoint> ingress, | ||
43 | + ConnectPoint egress) { | ||
44 | + return new MultiPointToSinglePointIntent(new IntentId(id), | ||
45 | + selector, | ||
46 | + treatment, | ||
47 | + ingress, | ||
48 | + egress); | ||
49 | + } | ||
50 | + | ||
51 | + /** | ||
52 | + * Initializes the ingress sets. | ||
53 | + */ | ||
54 | + @Before | ||
55 | + public void setup() { | ||
56 | + ingress1 = new HashSet<>(); | ||
57 | + ingress2 = new HashSet<>(); | ||
58 | + } | ||
59 | + | ||
60 | + /** | ||
61 | + * Tests the equals() method where two MultiPointToSinglePoint have references | ||
62 | + * to the same Links in different orders. These should compare equal. | ||
63 | + */ | ||
64 | + @Test | ||
65 | + public void testSameEquals() { | ||
66 | + | ||
67 | + Set<ConnectPoint> ingress1 = new HashSet<>(); | ||
68 | + ingress1.add(point2); | ||
69 | + ingress1.add(point3); | ||
70 | + | ||
71 | + Set<ConnectPoint> ingress2 = new HashSet<>(); | ||
72 | + ingress2.add(point3); | ||
73 | + ingress2.add(point2); | ||
74 | + | ||
75 | + Intent i1 = makeIntent(12, ingress1, point1); | ||
76 | + Intent i2 = makeIntent(12, ingress2, point1); | ||
77 | + | ||
78 | + assertThat(i1, is(equalTo(i2))); | ||
79 | + } | ||
80 | + | ||
81 | + /** | ||
82 | + * Tests the equals() method where two MultiPointToSinglePoint have references | ||
83 | + * to different Links. These should compare not equal. | ||
84 | + */ | ||
85 | + @Test | ||
86 | + public void testLinksDifferentEquals() { | ||
87 | + ingress1.add(point3); | ||
88 | + | ||
89 | + ingress2.add(point3); | ||
90 | + ingress2.add(point2); | ||
91 | + | ||
92 | + Intent i1 = makeIntent(12, ingress1, point1); | ||
93 | + Intent i2 = makeIntent(12, ingress2, point1); | ||
94 | + | ||
95 | + assertThat(i1, is(not(equalTo(i2)))); | ||
96 | + } | ||
97 | + | ||
98 | + /** | ||
99 | + * Tests the equals() method where two MultiPointToSinglePoint have different | ||
100 | + * ids. These should compare not equal. | ||
101 | + */ | ||
102 | + @Test | ||
103 | + public void testBaseDifferentEquals() { | ||
104 | + ingress1.add(point3); | ||
105 | + ingress2.add(point3); | ||
106 | + | ||
107 | + Intent i1 = makeIntent(12, ingress1, point1); | ||
108 | + Intent i2 = makeIntent(11, ingress2, point1); | ||
109 | + | ||
110 | + assertThat(i1, is(not(equalTo(i2)))); | ||
111 | + } | ||
112 | + | ||
113 | + /** | ||
114 | + * Tests that the hashCode() values for two equivalent MultiPointToSinglePoint | ||
115 | + * objects are the same. | ||
116 | + */ | ||
117 | + @Test | ||
118 | + public void testHashCodeEquals() { | ||
119 | + ingress1.add(point2); | ||
120 | + ingress1.add(point3); | ||
121 | + | ||
122 | + ingress2.add(point3); | ||
123 | + ingress2.add(point2); | ||
124 | + | ||
125 | + Intent i1 = makeIntent(12, ingress1, point1); | ||
126 | + Intent i2 = makeIntent(12, ingress2, point1); | ||
127 | + | ||
128 | + assertThat(i1.hashCode(), is(equalTo(i2.hashCode()))); | ||
129 | + } | ||
130 | + | ||
131 | + /** | ||
132 | + * Tests that the hashCode() values for two distinct MultiPointToSinglePoint | ||
133 | + * objects are different. | ||
134 | + */ | ||
135 | + @Test | ||
136 | + public void testHashCodeDifferent() { | ||
137 | + ingress1.add(point2); | ||
138 | + | ||
139 | + ingress2.add(point3); | ||
140 | + ingress2.add(point2); | ||
141 | + | ||
142 | + Intent i1 = makeIntent(12, ingress1, point1); | ||
143 | + Intent i2 = makeIntent(12, ingress2, point1); | ||
144 | + | ||
145 | + | ||
146 | + assertThat(i1.hashCode(), is(not(equalTo(i2.hashCode())))); | ||
147 | + } | ||
148 | + | ||
149 | + /** | ||
150 | + * Checks that the MultiPointToSinglePointIntent class is immutable. | ||
151 | + */ | ||
152 | + @Test | ||
153 | + public void checkImmutability() { | ||
154 | + ImmutableClassChecker. | ||
155 | + assertThatClassIsImmutable(MultiPointToSinglePointIntent.class); | ||
156 | + } | ||
157 | +} |
1 | +package org.onlab.onos.net.intent.impl; | ||
2 | + | ||
3 | +import java.util.List; | ||
4 | + | ||
5 | +import org.hamcrest.Matchers; | ||
6 | +import org.junit.Before; | ||
7 | +import org.junit.Test; | ||
8 | +import org.onlab.onos.net.Host; | ||
9 | +import org.onlab.onos.net.HostId; | ||
10 | +import org.onlab.onos.net.flow.TrafficSelector; | ||
11 | +import org.onlab.onos.net.flow.TrafficTreatment; | ||
12 | +import org.onlab.onos.net.host.HostService; | ||
13 | +import org.onlab.onos.net.intent.HostToHostIntent; | ||
14 | +import org.onlab.onos.net.intent.Intent; | ||
15 | +import org.onlab.onos.net.intent.IntentId; | ||
16 | +import org.onlab.onos.net.intent.IntentTestsMocks; | ||
17 | +import org.onlab.onos.net.intent.PathIntent; | ||
18 | +import org.onlab.packet.MacAddress; | ||
19 | +import org.onlab.packet.VlanId; | ||
20 | + | ||
21 | +import static org.easymock.EasyMock.createMock; | ||
22 | +import static org.easymock.EasyMock.eq; | ||
23 | +import static org.easymock.EasyMock.expect; | ||
24 | +import static org.easymock.EasyMock.replay; | ||
25 | +import static org.hamcrest.CoreMatchers.notNullValue; | ||
26 | +import static org.hamcrest.MatcherAssert.assertThat; | ||
27 | +import static org.hamcrest.Matchers.hasSize; | ||
28 | +import static org.hamcrest.Matchers.is; | ||
29 | +import static org.onlab.onos.net.NetTestTools.hid; | ||
30 | +import static org.onlab.onos.net.intent.LinksHaveEntryWithSourceDestinationPairMatcher.linksHasPath; | ||
31 | + | ||
32 | +/** | ||
33 | + * Unit tests for the HostToHost intent compiler. | ||
34 | + */ | ||
35 | +public class TestHostToHostIntentCompiler { | ||
36 | + private static final String HOST_ONE_MAC = "00:00:00:00:00:01"; | ||
37 | + private static final String HOST_TWO_MAC = "00:00:00:00:00:02"; | ||
38 | + private static final String HOST_ONE_VLAN = "-1"; | ||
39 | + private static final String HOST_TWO_VLAN = "-1"; | ||
40 | + private static final String HOST_ONE = HOST_ONE_MAC + "/" + HOST_ONE_VLAN; | ||
41 | + private static final String HOST_TWO = HOST_TWO_MAC + "/" + HOST_TWO_VLAN; | ||
42 | + | ||
43 | + private TrafficSelector selector = new IntentTestsMocks.MockSelector(); | ||
44 | + private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment(); | ||
45 | + | ||
46 | + private HostId hostOneId = HostId.hostId(HOST_ONE); | ||
47 | + private HostId hostTwoId = HostId.hostId(HOST_TWO); | ||
48 | + private HostService mockHostService; | ||
49 | + | ||
50 | + @Before | ||
51 | + public void setup() { | ||
52 | + Host hostOne = createMock(Host.class); | ||
53 | + expect(hostOne.mac()).andReturn(new MacAddress(HOST_ONE_MAC.getBytes())).anyTimes(); | ||
54 | + expect(hostOne.vlan()).andReturn(VlanId.vlanId()).anyTimes(); | ||
55 | + replay(hostOne); | ||
56 | + | ||
57 | + Host hostTwo = createMock(Host.class); | ||
58 | + expect(hostTwo.mac()).andReturn(new MacAddress(HOST_TWO_MAC.getBytes())).anyTimes(); | ||
59 | + expect(hostTwo.vlan()).andReturn(VlanId.vlanId()).anyTimes(); | ||
60 | + replay(hostTwo); | ||
61 | + | ||
62 | + mockHostService = createMock(HostService.class); | ||
63 | + expect(mockHostService.getHost(eq(hostOneId))).andReturn(hostOne).anyTimes(); | ||
64 | + expect(mockHostService.getHost(eq(hostTwoId))).andReturn(hostTwo).anyTimes(); | ||
65 | + replay(mockHostService); | ||
66 | + } | ||
67 | + | ||
68 | + /** | ||
69 | + * Creates a HostToHost intent based on two host Ids. | ||
70 | + * | ||
71 | + * @param oneIdString string for host one id | ||
72 | + * @param twoIdString string for host two id | ||
73 | + * @return HostToHostIntent for the two hosts | ||
74 | + */ | ||
75 | + private HostToHostIntent makeIntent(String oneIdString, String twoIdString) { | ||
76 | + return new HostToHostIntent(new IntentId(12), | ||
77 | + hid(oneIdString), | ||
78 | + hid(twoIdString), | ||
79 | + selector, | ||
80 | + treatment); | ||
81 | + } | ||
82 | + | ||
83 | + /** | ||
84 | + * Creates a compiler for HostToHost intents. | ||
85 | + * | ||
86 | + * @param hops string array describing the path hops to use when compiling | ||
87 | + * @return HostToHost intent compiler | ||
88 | + */ | ||
89 | + private HostToHostIntentCompiler makeCompiler(String[] hops) { | ||
90 | + HostToHostIntentCompiler compiler = | ||
91 | + new HostToHostIntentCompiler(); | ||
92 | + compiler.pathService = new IntentTestsMocks.MockPathService(hops); | ||
93 | + compiler.hostService = mockHostService; | ||
94 | + IdBlockAllocator idBlockAllocator = new DummyIdBlockAllocator(); | ||
95 | + compiler.intentIdGenerator = | ||
96 | + new IdBlockAllocatorBasedIntentIdGenerator(idBlockAllocator); | ||
97 | + return compiler; | ||
98 | + } | ||
99 | + | ||
100 | + | ||
101 | + /** | ||
102 | + * Tests a pair of hosts with 8 hops between them. | ||
103 | + */ | ||
104 | + @Test | ||
105 | + public void testSingleLongPathCompilation() { | ||
106 | + | ||
107 | + HostToHostIntent intent = makeIntent(HOST_ONE, | ||
108 | + HOST_TWO); | ||
109 | + assertThat(intent, is(notNullValue())); | ||
110 | + | ||
111 | + String[] hops = {HOST_ONE, "h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8", HOST_TWO}; | ||
112 | + HostToHostIntentCompiler compiler = makeCompiler(hops); | ||
113 | + assertThat(compiler, is(notNullValue())); | ||
114 | + | ||
115 | + List<Intent> result = compiler.compile(intent); | ||
116 | + assertThat(result, is(Matchers.notNullValue())); | ||
117 | + assertThat(result, hasSize(2)); | ||
118 | + Intent forwardResultIntent = result.get(0); | ||
119 | + assertThat(forwardResultIntent instanceof PathIntent, is(true)); | ||
120 | + Intent reverseResultIntent = result.get(1); | ||
121 | + assertThat(reverseResultIntent instanceof PathIntent, is(true)); | ||
122 | + | ||
123 | + if (forwardResultIntent instanceof PathIntent) { | ||
124 | + PathIntent forwardPathIntent = (PathIntent) forwardResultIntent; | ||
125 | + assertThat(forwardPathIntent.path().links(), hasSize(9)); | ||
126 | + assertThat(forwardPathIntent.path().links(), linksHasPath(HOST_ONE, "h1")); | ||
127 | + assertThat(forwardPathIntent.path().links(), linksHasPath("h1", "h2")); | ||
128 | + assertThat(forwardPathIntent.path().links(), linksHasPath("h2", "h3")); | ||
129 | + assertThat(forwardPathIntent.path().links(), linksHasPath("h3", "h4")); | ||
130 | + assertThat(forwardPathIntent.path().links(), linksHasPath("h4", "h5")); | ||
131 | + assertThat(forwardPathIntent.path().links(), linksHasPath("h5", "h6")); | ||
132 | + assertThat(forwardPathIntent.path().links(), linksHasPath("h6", "h7")); | ||
133 | + assertThat(forwardPathIntent.path().links(), linksHasPath("h7", "h8")); | ||
134 | + assertThat(forwardPathIntent.path().links(), linksHasPath("h8", HOST_TWO)); | ||
135 | + } | ||
136 | + | ||
137 | + if (reverseResultIntent instanceof PathIntent) { | ||
138 | + PathIntent reversePathIntent = (PathIntent) reverseResultIntent; | ||
139 | + assertThat(reversePathIntent.path().links(), hasSize(9)); | ||
140 | + assertThat(reversePathIntent.path().links(), linksHasPath("h1", HOST_ONE)); | ||
141 | + assertThat(reversePathIntent.path().links(), linksHasPath("h2", "h1")); | ||
142 | + assertThat(reversePathIntent.path().links(), linksHasPath("h3", "h2")); | ||
143 | + assertThat(reversePathIntent.path().links(), linksHasPath("h4", "h3")); | ||
144 | + assertThat(reversePathIntent.path().links(), linksHasPath("h5", "h4")); | ||
145 | + assertThat(reversePathIntent.path().links(), linksHasPath("h6", "h5")); | ||
146 | + assertThat(reversePathIntent.path().links(), linksHasPath("h7", "h6")); | ||
147 | + assertThat(reversePathIntent.path().links(), linksHasPath("h8", "h7")); | ||
148 | + assertThat(reversePathIntent.path().links(), linksHasPath(HOST_TWO, "h8")); | ||
149 | + } | ||
150 | + } | ||
151 | +} |
core/net/src/test/java/org/onlab/onos/net/intent/impl/TestMultiPointToSinglePointIntentCompiler.java
0 → 100644
1 | +package org.onlab.onos.net.intent.impl; | ||
2 | + | ||
3 | +import java.util.HashSet; | ||
4 | +import java.util.List; | ||
5 | +import java.util.Set; | ||
6 | + | ||
7 | +import org.hamcrest.Matchers; | ||
8 | +import org.junit.Test; | ||
9 | +import org.onlab.onos.net.ConnectPoint; | ||
10 | +import org.onlab.onos.net.ElementId; | ||
11 | +import org.onlab.onos.net.Path; | ||
12 | +import org.onlab.onos.net.flow.TrafficSelector; | ||
13 | +import org.onlab.onos.net.flow.TrafficTreatment; | ||
14 | +import org.onlab.onos.net.intent.Intent; | ||
15 | +import org.onlab.onos.net.intent.IntentId; | ||
16 | +import org.onlab.onos.net.intent.IntentTestsMocks; | ||
17 | +import org.onlab.onos.net.intent.LinkCollectionIntent; | ||
18 | +import org.onlab.onos.net.intent.MultiPointToSinglePointIntent; | ||
19 | +import org.onlab.onos.net.topology.LinkWeight; | ||
20 | +import org.onlab.onos.net.topology.PathService; | ||
21 | + | ||
22 | +import static org.hamcrest.CoreMatchers.notNullValue; | ||
23 | +import static org.hamcrest.MatcherAssert.assertThat; | ||
24 | +import static org.hamcrest.Matchers.hasSize; | ||
25 | +import static org.hamcrest.Matchers.is; | ||
26 | +import static org.onlab.onos.net.NetTestTools.connectPoint; | ||
27 | +import static org.onlab.onos.net.NetTestTools.createPath; | ||
28 | +import static org.onlab.onos.net.intent.LinksHaveEntryWithSourceDestinationPairMatcher.linksHasPath; | ||
29 | + | ||
30 | +/** | ||
31 | + * Unit tests for the MultiPointToSinglePoint intent compiler. | ||
32 | + */ | ||
33 | +public class TestMultiPointToSinglePointIntentCompiler { | ||
34 | + | ||
35 | + private TrafficSelector selector = new IntentTestsMocks.MockSelector(); | ||
36 | + private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment(); | ||
37 | + | ||
38 | + /** | ||
39 | + * Mock path service for creating paths within the test. | ||
40 | + */ | ||
41 | + private static class MockPathService implements PathService { | ||
42 | + | ||
43 | + final String[] pathHops; | ||
44 | + | ||
45 | + /** | ||
46 | + * Constructor that provides a set of hops to mock. | ||
47 | + * | ||
48 | + * @param pathHops path hops to mock | ||
49 | + */ | ||
50 | + MockPathService(String[] pathHops) { | ||
51 | + this.pathHops = pathHops; | ||
52 | + } | ||
53 | + | ||
54 | + @Override | ||
55 | + public Set<Path> getPaths(ElementId src, ElementId dst) { | ||
56 | + Set<Path> result = new HashSet<>(); | ||
57 | + | ||
58 | + String[] allHops = new String[pathHops.length + 1]; | ||
59 | + allHops[0] = src.toString(); | ||
60 | + System.arraycopy(pathHops, 0, allHops, 1, pathHops.length); | ||
61 | + | ||
62 | + result.add(createPath(allHops)); | ||
63 | + return result; | ||
64 | + } | ||
65 | + | ||
66 | + @Override | ||
67 | + public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeight weight) { | ||
68 | + return null; | ||
69 | + } | ||
70 | + } | ||
71 | + | ||
72 | + /** | ||
73 | + * Creates a MultiPointToSinglePoint intent for a group of ingress points | ||
74 | + * and an egress point. | ||
75 | + * | ||
76 | + * @param ingressIds array of ingress device ids | ||
77 | + * @param egressId device id of the egress point | ||
78 | + * @return MultiPointToSinglePoint intent | ||
79 | + */ | ||
80 | + private MultiPointToSinglePointIntent makeIntent(String[] ingressIds, String egressId) { | ||
81 | + Set<ConnectPoint> ingressPoints = new HashSet<>(); | ||
82 | + ConnectPoint egressPoint = connectPoint(egressId, 1); | ||
83 | + | ||
84 | + for (String ingressId : ingressIds) { | ||
85 | + ingressPoints.add(connectPoint(ingressId, 1)); | ||
86 | + } | ||
87 | + | ||
88 | + return new MultiPointToSinglePointIntent( | ||
89 | + new IntentId(12), | ||
90 | + selector, | ||
91 | + treatment, | ||
92 | + ingressPoints, | ||
93 | + egressPoint); | ||
94 | + } | ||
95 | + | ||
96 | + /** | ||
97 | + * Creates a compiler for MultiPointToSinglePoint intents. | ||
98 | + * | ||
99 | + * @param hops hops to use while computing paths for this intent | ||
100 | + * @return MultiPointToSinglePoint intent | ||
101 | + */ | ||
102 | + private MultiPointToSinglePointIntentCompiler makeCompiler(String[] hops) { | ||
103 | + MultiPointToSinglePointIntentCompiler compiler = | ||
104 | + new MultiPointToSinglePointIntentCompiler(); | ||
105 | + compiler.pathService = new MockPathService(hops); | ||
106 | + IdBlockAllocator idBlockAllocator = new DummyIdBlockAllocator(); | ||
107 | + compiler.intentIdGenerator = | ||
108 | + new IdBlockAllocatorBasedIntentIdGenerator(idBlockAllocator); | ||
109 | + return compiler; | ||
110 | + } | ||
111 | + | ||
112 | + /** | ||
113 | + * Tests a single ingress point with 8 hops to its egress point. | ||
114 | + */ | ||
115 | + @Test | ||
116 | + public void testSingleLongPathCompilation() { | ||
117 | + | ||
118 | + String[] ingress = {"ingress"}; | ||
119 | + String egress = "egress"; | ||
120 | + | ||
121 | + MultiPointToSinglePointIntent intent = makeIntent(ingress, egress); | ||
122 | + assertThat(intent, is(notNullValue())); | ||
123 | + | ||
124 | + String[] hops = {"h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8", | ||
125 | + egress}; | ||
126 | + MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops); | ||
127 | + assertThat(compiler, is(notNullValue())); | ||
128 | + | ||
129 | + List<Intent> result = compiler.compile(intent); | ||
130 | + assertThat(result, is(Matchers.notNullValue())); | ||
131 | + assertThat(result, hasSize(1)); | ||
132 | + Intent resultIntent = result.get(0); | ||
133 | + assertThat(resultIntent instanceof LinkCollectionIntent, is(true)); | ||
134 | + | ||
135 | + if (resultIntent instanceof LinkCollectionIntent) { | ||
136 | + LinkCollectionIntent linkIntent = (LinkCollectionIntent) resultIntent; | ||
137 | + assertThat(linkIntent.links(), hasSize(9)); | ||
138 | + assertThat(linkIntent.links(), linksHasPath("ingress", "h1")); | ||
139 | + assertThat(linkIntent.links(), linksHasPath("h1", "h2")); | ||
140 | + assertThat(linkIntent.links(), linksHasPath("h2", "h3")); | ||
141 | + assertThat(linkIntent.links(), linksHasPath("h4", "h5")); | ||
142 | + assertThat(linkIntent.links(), linksHasPath("h5", "h6")); | ||
143 | + assertThat(linkIntent.links(), linksHasPath("h7", "h8")); | ||
144 | + assertThat(linkIntent.links(), linksHasPath("h8", "egress")); | ||
145 | + } | ||
146 | + } | ||
147 | + | ||
148 | + /** | ||
149 | + * Tests a simple topology where two ingress points share some path segments | ||
150 | + * and some path segments are not shared. | ||
151 | + */ | ||
152 | + @Test | ||
153 | + public void testTwoIngressCompilation() { | ||
154 | + String[] ingress = {"ingress1", "ingress2"}; | ||
155 | + String egress = "egress"; | ||
156 | + | ||
157 | + MultiPointToSinglePointIntent intent = makeIntent(ingress, egress); | ||
158 | + assertThat(intent, is(notNullValue())); | ||
159 | + | ||
160 | + final String[] hops = {"inner1", "inner2", egress}; | ||
161 | + MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops); | ||
162 | + assertThat(compiler, is(notNullValue())); | ||
163 | + | ||
164 | + List<Intent> result = compiler.compile(intent); | ||
165 | + assertThat(result, is(notNullValue())); | ||
166 | + assertThat(result, hasSize(1)); | ||
167 | + Intent resultIntent = result.get(0); | ||
168 | + assertThat(resultIntent instanceof LinkCollectionIntent, is(true)); | ||
169 | + | ||
170 | + if (resultIntent instanceof LinkCollectionIntent) { | ||
171 | + LinkCollectionIntent linkIntent = (LinkCollectionIntent) resultIntent; | ||
172 | + assertThat(linkIntent.links(), hasSize(4)); | ||
173 | + assertThat(linkIntent.links(), linksHasPath("ingress1", "inner1")); | ||
174 | + assertThat(linkIntent.links(), linksHasPath("ingress2", "inner1")); | ||
175 | + assertThat(linkIntent.links(), linksHasPath("inner1", "inner2")); | ||
176 | + assertThat(linkIntent.links(), linksHasPath("inner2", "egress")); | ||
177 | + } | ||
178 | + } | ||
179 | + | ||
180 | + /** | ||
181 | + * Tests a large number of ingress points that share a common path to the | ||
182 | + * egress point. | ||
183 | + */ | ||
184 | + @Test | ||
185 | + public void testMultiIngressCompilation() { | ||
186 | + String[] ingress = {"i1", "i2", "i3", "i4", "i5", | ||
187 | + "i6", "i7", "i8", "i9", "i10"}; | ||
188 | + String egress = "e"; | ||
189 | + | ||
190 | + MultiPointToSinglePointIntent intent = makeIntent(ingress, egress); | ||
191 | + assertThat(intent, is(notNullValue())); | ||
192 | + | ||
193 | + final String[] hops = {"n1", egress}; | ||
194 | + MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops); | ||
195 | + assertThat(compiler, is(notNullValue())); | ||
196 | + | ||
197 | + List<Intent> result = compiler.compile(intent); | ||
198 | + assertThat(result, is(notNullValue())); | ||
199 | + assertThat(result, hasSize(1)); | ||
200 | + Intent resultIntent = result.get(0); | ||
201 | + assertThat(resultIntent instanceof LinkCollectionIntent, is(true)); | ||
202 | + | ||
203 | + if (resultIntent instanceof LinkCollectionIntent) { | ||
204 | + LinkCollectionIntent linkIntent = (LinkCollectionIntent) resultIntent; | ||
205 | + assertThat(linkIntent.links(), hasSize(ingress.length + 1)); | ||
206 | + for (String ingressToCheck : ingress) { | ||
207 | + assertThat(linkIntent.links(), | ||
208 | + linksHasPath(ingressToCheck, | ||
209 | + "n1")); | ||
210 | + } | ||
211 | + assertThat(linkIntent.links(), linksHasPath("n1", egress)); | ||
212 | + } | ||
213 | + } | ||
214 | +} |
... | @@ -19,21 +19,10 @@ | ... | @@ -19,21 +19,10 @@ |
19 | <dependencies> | 19 | <dependencies> |
20 | <dependency> | 20 | <dependency> |
21 | <groupId>org.onlab.onos</groupId> | 21 | <groupId>org.onlab.onos</groupId> |
22 | - <artifactId>onos-api</artifactId> | ||
23 | - </dependency> | ||
24 | - <dependency> | ||
25 | - <groupId>org.onlab.onos</groupId> | ||
26 | <artifactId>onos-core-serializers</artifactId> | 22 | <artifactId>onos-core-serializers</artifactId> |
27 | <version>${project.version}</version> | 23 | <version>${project.version}</version> |
28 | </dependency> | 24 | </dependency> |
29 | 25 | ||
30 | - | ||
31 | - <dependency> | ||
32 | - <groupId>org.onlab.onos</groupId> | ||
33 | - <artifactId>onlab-nio</artifactId> | ||
34 | - <version>${project.version}</version> | ||
35 | - </dependency> | ||
36 | - | ||
37 | <dependency> | 26 | <dependency> |
38 | <groupId>org.onlab.onos</groupId> | 27 | <groupId>org.onlab.onos</groupId> |
39 | <artifactId>onlab-netty</artifactId> | 28 | <artifactId>onlab-netty</artifactId> |
... | @@ -50,10 +39,6 @@ | ... | @@ -50,10 +39,6 @@ |
50 | </dependency> | 39 | </dependency> |
51 | 40 | ||
52 | <dependency> | 41 | <dependency> |
53 | - <groupId>org.apache.felix</groupId> | ||
54 | - <artifactId>org.apache.felix.scr.annotations</artifactId> | ||
55 | - </dependency> | ||
56 | - <dependency> | ||
57 | <groupId>com.google.guava</groupId> | 42 | <groupId>com.google.guava</groupId> |
58 | <artifactId>guava-testlib</artifactId> | 43 | <artifactId>guava-testlib</artifactId> |
59 | <scope>test</scope> | 44 | <scope>test</scope> |
... | @@ -69,13 +54,4 @@ | ... | @@ -69,13 +54,4 @@ |
69 | </dependency> | 54 | </dependency> |
70 | </dependencies> | 55 | </dependencies> |
71 | 56 | ||
72 | - <build> | ||
73 | - <plugins> | ||
74 | - <plugin> | ||
75 | - <groupId>org.apache.felix</groupId> | ||
76 | - <artifactId>maven-scr-plugin</artifactId> | ||
77 | - </plugin> | ||
78 | - </plugins> | ||
79 | - </build> | ||
80 | - | ||
81 | </project> | 57 | </project> | ... | ... |
... | @@ -114,7 +114,7 @@ public class ClusterCommunicationManager | ... | @@ -114,7 +114,7 @@ public class ClusterCommunicationManager |
114 | message.subject().value(), SERIALIZER.encode(message)); | 114 | message.subject().value(), SERIALIZER.encode(message)); |
115 | return true; | 115 | return true; |
116 | } catch (IOException e) { | 116 | } catch (IOException e) { |
117 | - log.error("Failed to send cluster message to nodeId: " + toNodeId, e); | 117 | + log.trace("Failed to send cluster message to nodeId: " + toNodeId, e); |
118 | throw e; | 118 | throw e; |
119 | } | 119 | } |
120 | } | 120 | } | ... | ... |
... | @@ -15,7 +15,7 @@ import org.onlab.onos.net.device.DefaultPortDescription; | ... | @@ -15,7 +15,7 @@ import org.onlab.onos.net.device.DefaultPortDescription; |
15 | import org.onlab.onos.net.device.DeviceDescription; | 15 | import org.onlab.onos.net.device.DeviceDescription; |
16 | import org.onlab.onos.net.device.PortDescription; | 16 | import org.onlab.onos.net.device.PortDescription; |
17 | import org.onlab.onos.store.Timestamp; | 17 | import org.onlab.onos.store.Timestamp; |
18 | -import org.onlab.onos.store.common.impl.Timestamped; | 18 | +import org.onlab.onos.store.impl.Timestamped; |
19 | 19 | ||
20 | /* | 20 | /* |
21 | * Collection of Description of a Device and Ports, given from a Provider. | 21 | * Collection of Description of a Device and Ports, given from a Provider. | ... | ... |
... | @@ -38,7 +38,7 @@ import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService; | ... | @@ -38,7 +38,7 @@ import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService; |
38 | import org.onlab.onos.store.cluster.messaging.ClusterMessage; | 38 | import org.onlab.onos.store.cluster.messaging.ClusterMessage; |
39 | import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler; | 39 | import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler; |
40 | import org.onlab.onos.store.cluster.messaging.MessageSubject; | 40 | import org.onlab.onos.store.cluster.messaging.MessageSubject; |
41 | -import org.onlab.onos.store.common.impl.Timestamped; | 41 | +import org.onlab.onos.store.impl.Timestamped; |
42 | import org.onlab.onos.store.serializers.KryoSerializer; | 42 | import org.onlab.onos.store.serializers.KryoSerializer; |
43 | import org.onlab.onos.store.serializers.DistributedStoreSerializers; | 43 | import org.onlab.onos.store.serializers.DistributedStoreSerializers; |
44 | import org.onlab.packet.ChassisId; | 44 | import org.onlab.packet.ChassisId; |
... | @@ -516,12 +516,12 @@ public class GossipDeviceStore | ... | @@ -516,12 +516,12 @@ public class GossipDeviceStore |
516 | Map<PortNumber, Port> ports, | 516 | Map<PortNumber, Port> ports, |
517 | Set<PortNumber> processed) { | 517 | Set<PortNumber> processed) { |
518 | List<DeviceEvent> events = new ArrayList<>(); | 518 | List<DeviceEvent> events = new ArrayList<>(); |
519 | - Iterator<PortNumber> iterator = ports.keySet().iterator(); | 519 | + Iterator<Entry<PortNumber, Port>> iterator = ports.entrySet().iterator(); |
520 | while (iterator.hasNext()) { | 520 | while (iterator.hasNext()) { |
521 | - PortNumber portNumber = iterator.next(); | 521 | + Entry<PortNumber, Port> e = iterator.next(); |
522 | + PortNumber portNumber = e.getKey(); | ||
522 | if (!processed.contains(portNumber)) { | 523 | if (!processed.contains(portNumber)) { |
523 | - events.add(new DeviceEvent(PORT_REMOVED, device, | 524 | + events.add(new DeviceEvent(PORT_REMOVED, device, e.getValue())); |
524 | - ports.get(portNumber))); | ||
525 | iterator.remove(); | 525 | iterator.remove(); |
526 | } | 526 | } |
527 | } | 527 | } |
... | @@ -1139,7 +1139,7 @@ public class GossipDeviceStore | ... | @@ -1139,7 +1139,7 @@ public class GossipDeviceStore |
1139 | try { | 1139 | try { |
1140 | unicastMessage(peer, DEVICE_ADVERTISE, ad); | 1140 | unicastMessage(peer, DEVICE_ADVERTISE, ad); |
1141 | } catch (IOException e) { | 1141 | } catch (IOException e) { |
1142 | - log.error("Failed to send anti-entropy advertisement", e); | 1142 | + log.debug("Failed to send anti-entropy advertisement to {}", peer); |
1143 | return; | 1143 | return; |
1144 | } | 1144 | } |
1145 | } catch (Exception e) { | 1145 | } catch (Exception e) { | ... | ... |
core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InitDeviceDescs.java
deleted
100644 → 0
1 | -package org.onlab.onos.store.device.impl; | ||
2 | - | ||
3 | -import static com.google.common.base.Preconditions.checkNotNull; | ||
4 | - | ||
5 | -import org.apache.commons.lang3.concurrent.ConcurrentException; | ||
6 | -import org.apache.commons.lang3.concurrent.ConcurrentInitializer; | ||
7 | -import org.onlab.onos.net.device.DeviceDescription; | ||
8 | -import org.onlab.onos.store.common.impl.Timestamped; | ||
9 | - | ||
10 | -// FIXME: consider removing this class | ||
11 | -public final class InitDeviceDescs | ||
12 | - implements ConcurrentInitializer<DeviceDescriptions> { | ||
13 | - | ||
14 | - private final Timestamped<DeviceDescription> deviceDesc; | ||
15 | - | ||
16 | - public InitDeviceDescs(Timestamped<DeviceDescription> deviceDesc) { | ||
17 | - this.deviceDesc = checkNotNull(deviceDesc); | ||
18 | - } | ||
19 | - @Override | ||
20 | - public DeviceDescriptions get() throws ConcurrentException { | ||
21 | - return new DeviceDescriptions(deviceDesc); | ||
22 | - } | ||
23 | -} |
... | @@ -3,7 +3,7 @@ package org.onlab.onos.store.device.impl; | ... | @@ -3,7 +3,7 @@ package org.onlab.onos.store.device.impl; |
3 | import org.onlab.onos.net.DeviceId; | 3 | import org.onlab.onos.net.DeviceId; |
4 | import org.onlab.onos.net.device.DeviceDescription; | 4 | import org.onlab.onos.net.device.DeviceDescription; |
5 | import org.onlab.onos.net.provider.ProviderId; | 5 | import org.onlab.onos.net.provider.ProviderId; |
6 | -import org.onlab.onos.store.common.impl.Timestamped; | 6 | +import org.onlab.onos.store.impl.Timestamped; |
7 | 7 | ||
8 | import com.google.common.base.MoreObjects; | 8 | import com.google.common.base.MoreObjects; |
9 | 9 | ... | ... |
... | @@ -3,7 +3,7 @@ package org.onlab.onos.store.device.impl; | ... | @@ -3,7 +3,7 @@ package org.onlab.onos.store.device.impl; |
3 | import org.onlab.onos.net.DeviceId; | 3 | import org.onlab.onos.net.DeviceId; |
4 | import org.onlab.onos.net.device.DeviceDescription; | 4 | import org.onlab.onos.net.device.DeviceDescription; |
5 | import org.onlab.onos.net.provider.ProviderId; | 5 | import org.onlab.onos.net.provider.ProviderId; |
6 | -import org.onlab.onos.store.common.impl.Timestamped; | 6 | +import org.onlab.onos.store.impl.Timestamped; |
7 | 7 | ||
8 | import com.esotericsoftware.kryo.Kryo; | 8 | import com.esotericsoftware.kryo.Kryo; |
9 | import com.esotericsoftware.kryo.Serializer; | 9 | import com.esotericsoftware.kryo.Serializer; | ... | ... |
... | @@ -5,7 +5,7 @@ import java.util.List; | ... | @@ -5,7 +5,7 @@ import java.util.List; |
5 | import org.onlab.onos.net.DeviceId; | 5 | import org.onlab.onos.net.DeviceId; |
6 | import org.onlab.onos.net.device.PortDescription; | 6 | import org.onlab.onos.net.device.PortDescription; |
7 | import org.onlab.onos.net.provider.ProviderId; | 7 | import org.onlab.onos.net.provider.ProviderId; |
8 | -import org.onlab.onos.store.common.impl.Timestamped; | 8 | +import org.onlab.onos.store.impl.Timestamped; |
9 | 9 | ||
10 | import com.google.common.base.MoreObjects; | 10 | import com.google.common.base.MoreObjects; |
11 | 11 | ... | ... |
... | @@ -5,7 +5,7 @@ import java.util.List; | ... | @@ -5,7 +5,7 @@ import java.util.List; |
5 | import org.onlab.onos.net.DeviceId; | 5 | import org.onlab.onos.net.DeviceId; |
6 | import org.onlab.onos.net.device.PortDescription; | 6 | import org.onlab.onos.net.device.PortDescription; |
7 | import org.onlab.onos.net.provider.ProviderId; | 7 | import org.onlab.onos.net.provider.ProviderId; |
8 | -import org.onlab.onos.store.common.impl.Timestamped; | 8 | +import org.onlab.onos.store.impl.Timestamped; |
9 | 9 | ||
10 | import com.esotericsoftware.kryo.Kryo; | 10 | import com.esotericsoftware.kryo.Kryo; |
11 | import com.esotericsoftware.kryo.Serializer; | 11 | import com.esotericsoftware.kryo.Serializer; | ... | ... |
... | @@ -3,7 +3,7 @@ package org.onlab.onos.store.device.impl; | ... | @@ -3,7 +3,7 @@ package org.onlab.onos.store.device.impl; |
3 | import org.onlab.onos.net.DeviceId; | 3 | import org.onlab.onos.net.DeviceId; |
4 | import org.onlab.onos.net.device.PortDescription; | 4 | import org.onlab.onos.net.device.PortDescription; |
5 | import org.onlab.onos.net.provider.ProviderId; | 5 | import org.onlab.onos.net.provider.ProviderId; |
6 | -import org.onlab.onos.store.common.impl.Timestamped; | 6 | +import org.onlab.onos.store.impl.Timestamped; |
7 | 7 | ||
8 | import com.google.common.base.MoreObjects; | 8 | import com.google.common.base.MoreObjects; |
9 | 9 | ... | ... |
... | @@ -3,7 +3,7 @@ package org.onlab.onos.store.device.impl; | ... | @@ -3,7 +3,7 @@ package org.onlab.onos.store.device.impl; |
3 | import org.onlab.onos.net.DeviceId; | 3 | import org.onlab.onos.net.DeviceId; |
4 | import org.onlab.onos.net.device.PortDescription; | 4 | import org.onlab.onos.net.device.PortDescription; |
5 | import org.onlab.onos.net.provider.ProviderId; | 5 | import org.onlab.onos.net.provider.ProviderId; |
6 | -import org.onlab.onos.store.common.impl.Timestamped; | 6 | +import org.onlab.onos.store.impl.Timestamped; |
7 | 7 | ||
8 | import com.esotericsoftware.kryo.Kryo; | 8 | import com.esotericsoftware.kryo.Kryo; |
9 | import com.esotericsoftware.kryo.Serializer; | 9 | import com.esotericsoftware.kryo.Serializer; | ... | ... |
1 | +package org.onlab.onos.store.flow; | ||
2 | + | ||
3 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
4 | + | ||
5 | +import java.util.Collection; | ||
6 | +import java.util.Collections; | ||
7 | + | ||
8 | +import org.onlab.onos.cluster.NodeId; | ||
9 | + | ||
10 | +import com.google.common.base.Optional; | ||
11 | + | ||
12 | +/** | ||
13 | + * Class to represent placement information about Master/Backup copy. | ||
14 | + */ | ||
15 | +public final class ReplicaInfo { | ||
16 | + | ||
17 | + private final Optional<NodeId> master; | ||
18 | + private final Collection<NodeId> backups; | ||
19 | + | ||
20 | + /** | ||
21 | + * Creates a ReplicaInfo instance. | ||
22 | + * | ||
23 | + * @param master NodeId of the node where the master copy should be | ||
24 | + * @param backups collection of NodeId, where backup copies should be placed | ||
25 | + */ | ||
26 | + public ReplicaInfo(NodeId master, Collection<NodeId> backups) { | ||
27 | + this.master = Optional.fromNullable(master); | ||
28 | + this.backups = checkNotNull(backups); | ||
29 | + } | ||
30 | + | ||
31 | + /** | ||
32 | + * Returns the NodeId, if there is a Node where the master copy should be. | ||
33 | + * | ||
34 | + * @return NodeId, where the master copy should be placed | ||
35 | + */ | ||
36 | + public Optional<NodeId> master() { | ||
37 | + return master; | ||
38 | + } | ||
39 | + | ||
40 | + /** | ||
41 | + * Returns the collection of NodeId, where backup copies should be placed. | ||
42 | + * | ||
43 | + * @return collection of NodeId, where backup copies should be placed | ||
44 | + */ | ||
45 | + public Collection<NodeId> backups() { | ||
46 | + return backups; | ||
47 | + } | ||
48 | + | ||
49 | + // for Serializer | ||
50 | + private ReplicaInfo() { | ||
51 | + this.master = Optional.absent(); | ||
52 | + this.backups = Collections.emptyList(); | ||
53 | + } | ||
54 | +} |
1 | +package org.onlab.onos.store.flow; | ||
2 | + | ||
3 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
4 | + | ||
5 | +import org.onlab.onos.event.AbstractEvent; | ||
6 | +import org.onlab.onos.net.DeviceId; | ||
7 | + | ||
8 | +/** | ||
9 | + * Describes a device replicainfo event. | ||
10 | + */ | ||
11 | +public class ReplicaInfoEvent extends AbstractEvent<ReplicaInfoEvent.Type, DeviceId> { | ||
12 | + | ||
13 | + private final ReplicaInfo replicaInfo; | ||
14 | + | ||
15 | + /** | ||
16 | + * Types of Replica info event. | ||
17 | + */ | ||
18 | + public enum Type { | ||
19 | + /** | ||
20 | + * Event to notify that master placement should be changed. | ||
21 | + */ | ||
22 | + MASTER_CHANGED, | ||
23 | + // | ||
24 | + // BACKUPS_CHANGED? | ||
25 | + } | ||
26 | + | ||
27 | + | ||
28 | + /** | ||
29 | + * Creates an event of a given type and for the specified device, | ||
30 | + * and replica info. | ||
31 | + * | ||
32 | + * @param type replicainfo event type | ||
33 | + * @param device event device subject | ||
34 | + * @param replicaInfo replicainfo | ||
35 | + */ | ||
36 | + public ReplicaInfoEvent(Type type, DeviceId device, ReplicaInfo replicaInfo) { | ||
37 | + super(type, device); | ||
38 | + this.replicaInfo = checkNotNull(replicaInfo); | ||
39 | + } | ||
40 | + | ||
41 | + /** | ||
42 | + * Returns the current replica information for the subject. | ||
43 | + * | ||
44 | + * @return replica information for the subject | ||
45 | + */ | ||
46 | + public ReplicaInfo replicaInfo() { | ||
47 | + return replicaInfo; | ||
48 | + }; | ||
49 | +} |
1 | +package org.onlab.onos.store.flow; | ||
2 | + | ||
3 | +import org.onlab.onos.net.DeviceId; | ||
4 | + | ||
5 | +/** | ||
6 | + * Service to return where the Replica should be placed. | ||
7 | + */ | ||
8 | +public interface ReplicaInfoService { | ||
9 | + | ||
10 | + // returns where it should be. | ||
11 | + /** | ||
12 | + * Returns the placement information for given Device. | ||
13 | + * | ||
14 | + * @param deviceId identifier of the device | ||
15 | + * @return placement information | ||
16 | + */ | ||
17 | + ReplicaInfo getReplicaInfoFor(DeviceId deviceId); | ||
18 | +} |
1 | +package org.onlab.onos.store.flow.impl; | ||
2 | + | ||
3 | +import static org.slf4j.LoggerFactory.getLogger; | ||
4 | +import static org.onlab.onos.store.flow.ReplicaInfoEvent.Type.MASTER_CHANGED; | ||
5 | + | ||
6 | +import java.util.Collections; | ||
7 | +import java.util.List; | ||
8 | + | ||
9 | +import org.apache.felix.scr.annotations.Activate; | ||
10 | +import org.apache.felix.scr.annotations.Component; | ||
11 | +import org.apache.felix.scr.annotations.Deactivate; | ||
12 | +import org.apache.felix.scr.annotations.Reference; | ||
13 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
14 | +import org.apache.felix.scr.annotations.Service; | ||
15 | +import org.onlab.onos.cluster.NodeId; | ||
16 | +import org.onlab.onos.event.AbstractListenerRegistry; | ||
17 | +import org.onlab.onos.event.EventDeliveryService; | ||
18 | +import org.onlab.onos.mastership.MastershipEvent; | ||
19 | +import org.onlab.onos.mastership.MastershipListener; | ||
20 | +import org.onlab.onos.mastership.MastershipService; | ||
21 | +import org.onlab.onos.net.DeviceId; | ||
22 | +import org.onlab.onos.store.flow.ReplicaInfo; | ||
23 | +import org.onlab.onos.store.flow.ReplicaInfoEvent; | ||
24 | +import org.onlab.onos.store.flow.ReplicaInfoEventListener; | ||
25 | +import org.onlab.onos.store.flow.ReplicaInfoService; | ||
26 | +import org.slf4j.Logger; | ||
27 | + | ||
28 | +/** | ||
29 | + * Manages replica placement information. | ||
30 | + */ | ||
31 | +@Component(immediate = true) | ||
32 | +@Service | ||
33 | +public class ReplicaInfoManager implements ReplicaInfoService { | ||
34 | + | ||
35 | + private final Logger log = getLogger(getClass()); | ||
36 | + | ||
37 | + private final MastershipListener mastershipListener = new InternalMastershipListener(); | ||
38 | + | ||
39 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
40 | + protected EventDeliveryService eventDispatcher; | ||
41 | + | ||
42 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
43 | + protected MastershipService mastershipService; | ||
44 | + | ||
45 | + protected final AbstractListenerRegistry<ReplicaInfoEvent, ReplicaInfoEventListener> | ||
46 | + listenerRegistry = new AbstractListenerRegistry<>(); | ||
47 | + | ||
48 | + @Activate | ||
49 | + public void activate() { | ||
50 | + eventDispatcher.addSink(ReplicaInfoEvent.class, listenerRegistry); | ||
51 | + mastershipService.addListener(mastershipListener); | ||
52 | + log.info("Started"); | ||
53 | + } | ||
54 | + | ||
55 | + @Deactivate | ||
56 | + public void deactivate() { | ||
57 | + eventDispatcher.removeSink(ReplicaInfoEvent.class); | ||
58 | + mastershipService.removeListener(mastershipListener); | ||
59 | + log.info("Stopped"); | ||
60 | + } | ||
61 | + | ||
62 | + @Override | ||
63 | + public ReplicaInfo getReplicaInfoFor(DeviceId deviceId) { | ||
64 | + // TODO: populate backup List when we reach the point we need them. | ||
65 | + return new ReplicaInfo(mastershipService.getMasterFor(deviceId), | ||
66 | + Collections.<NodeId>emptyList()); | ||
67 | + } | ||
68 | + | ||
69 | + final class InternalMastershipListener implements MastershipListener { | ||
70 | + | ||
71 | + @Override | ||
72 | + public void event(MastershipEvent event) { | ||
73 | + // TODO: distinguish stby list update, when MastershipService, | ||
74 | + // start publishing them | ||
75 | + final List<NodeId> standbyList = Collections.<NodeId>emptyList(); | ||
76 | + eventDispatcher.post(new ReplicaInfoEvent(MASTER_CHANGED, | ||
77 | + event.subject(), | ||
78 | + new ReplicaInfo(event.master(), standbyList))); | ||
79 | + } | ||
80 | + } | ||
81 | + | ||
82 | +} |
This diff is collapsed. Click to expand it.
... | @@ -4,6 +4,11 @@ import org.onlab.onos.store.cluster.messaging.MessageSubject; | ... | @@ -4,6 +4,11 @@ import org.onlab.onos.store.cluster.messaging.MessageSubject; |
4 | 4 | ||
5 | public final class GossipHostStoreMessageSubjects { | 5 | public final class GossipHostStoreMessageSubjects { |
6 | private GossipHostStoreMessageSubjects() {} | 6 | private GossipHostStoreMessageSubjects() {} |
7 | - public static final MessageSubject HOST_UPDATED = new MessageSubject("peer-host-updated"); | 7 | + |
8 | - public static final MessageSubject HOST_REMOVED = new MessageSubject("peer-host-removed"); | 8 | + public static final MessageSubject HOST_UPDATED |
9 | + = new MessageSubject("peer-host-updated"); | ||
10 | + public static final MessageSubject HOST_REMOVED | ||
11 | + = new MessageSubject("peer-host-removed"); | ||
12 | + public static final MessageSubject HOST_ANTI_ENTROPY_ADVERTISEMENT | ||
13 | + = new MessageSubject("host-enti-entropy-advertisement");; | ||
9 | } | 14 | } | ... | ... |
core/store/dist/src/main/java/org/onlab/onos/store/host/impl/HostAntiEntropyAdvertisement.java
0 → 100644
1 | +package org.onlab.onos.store.host.impl; | ||
2 | + | ||
3 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
4 | + | ||
5 | +import java.util.Map; | ||
6 | + | ||
7 | +import org.onlab.onos.cluster.NodeId; | ||
8 | +import org.onlab.onos.net.HostId; | ||
9 | +import org.onlab.onos.store.Timestamp; | ||
10 | + | ||
11 | +/** | ||
12 | + * Host AE Advertisement message. | ||
13 | + */ | ||
14 | +public final class HostAntiEntropyAdvertisement { | ||
15 | + | ||
16 | + private final NodeId sender; | ||
17 | + private final Map<HostFragmentId, Timestamp> timestamps; | ||
18 | + private final Map<HostId, Timestamp> tombstones; | ||
19 | + | ||
20 | + | ||
21 | + public HostAntiEntropyAdvertisement(NodeId sender, | ||
22 | + Map<HostFragmentId, Timestamp> timestamps, | ||
23 | + Map<HostId, Timestamp> tombstones) { | ||
24 | + this.sender = checkNotNull(sender); | ||
25 | + this.timestamps = checkNotNull(timestamps); | ||
26 | + this.tombstones = checkNotNull(tombstones); | ||
27 | + } | ||
28 | + | ||
29 | + public NodeId sender() { | ||
30 | + return sender; | ||
31 | + } | ||
32 | + | ||
33 | + public Map<HostFragmentId, Timestamp> timestamps() { | ||
34 | + return timestamps; | ||
35 | + } | ||
36 | + | ||
37 | + public Map<HostId, Timestamp> tombstones() { | ||
38 | + return tombstones; | ||
39 | + } | ||
40 | + | ||
41 | + // For serializer | ||
42 | + @SuppressWarnings("unused") | ||
43 | + private HostAntiEntropyAdvertisement() { | ||
44 | + this.sender = null; | ||
45 | + this.timestamps = null; | ||
46 | + this.tombstones = null; | ||
47 | + } | ||
48 | +} |
1 | +package org.onlab.onos.store.host.impl; | ||
2 | + | ||
3 | +import java.util.Objects; | ||
4 | + | ||
5 | +import org.onlab.onos.net.HostId; | ||
6 | +import org.onlab.onos.net.provider.ProviderId; | ||
7 | + | ||
8 | +import com.google.common.base.MoreObjects; | ||
9 | + | ||
10 | +/** | ||
11 | + * Identifier for HostDescription from a Provider. | ||
12 | + */ | ||
13 | +public final class HostFragmentId { | ||
14 | + public final ProviderId providerId; | ||
15 | + public final HostId hostId; | ||
16 | + | ||
17 | + public HostFragmentId(HostId hostId, ProviderId providerId) { | ||
18 | + this.providerId = providerId; | ||
19 | + this.hostId = hostId; | ||
20 | + } | ||
21 | + | ||
22 | + public HostId hostId() { | ||
23 | + return hostId; | ||
24 | + } | ||
25 | + | ||
26 | + public ProviderId providerId() { | ||
27 | + return providerId; | ||
28 | + } | ||
29 | + | ||
30 | + @Override | ||
31 | + public int hashCode() { | ||
32 | + return Objects.hash(providerId, hostId); | ||
33 | + } | ||
34 | + | ||
35 | + @Override | ||
36 | + public boolean equals(Object obj) { | ||
37 | + if (this == obj) { | ||
38 | + return true; | ||
39 | + } | ||
40 | + if (!(obj instanceof HostFragmentId)) { | ||
41 | + return false; | ||
42 | + } | ||
43 | + HostFragmentId that = (HostFragmentId) obj; | ||
44 | + return Objects.equals(this.hostId, that.hostId) && | ||
45 | + Objects.equals(this.providerId, that.providerId); | ||
46 | + } | ||
47 | + | ||
48 | + @Override | ||
49 | + public String toString() { | ||
50 | + return MoreObjects.toStringHelper(getClass()) | ||
51 | + .add("providerId", providerId) | ||
52 | + .add("hostId", hostId) | ||
53 | + .toString(); | ||
54 | + } | ||
55 | + | ||
56 | + // for serializer | ||
57 | + @SuppressWarnings("unused") | ||
58 | + private HostFragmentId() { | ||
59 | + this.providerId = null; | ||
60 | + this.hostId = null; | ||
61 | + } | ||
62 | +} |
1 | -package org.onlab.onos.store.common.impl; | 1 | +package org.onlab.onos.store.impl; |
2 | 2 | ||
3 | import static com.google.common.base.Preconditions.checkNotNull; | 3 | import static com.google.common.base.Preconditions.checkNotNull; |
4 | 4 | ||
... | @@ -58,12 +58,12 @@ public final class Timestamped<T> { | ... | @@ -58,12 +58,12 @@ public final class Timestamped<T> { |
58 | } | 58 | } |
59 | 59 | ||
60 | /** | 60 | /** |
61 | - * Tests if this timestamp is newer thatn the specified timestamp. | 61 | + * Tests if this timestamp is newer than the specified timestamp. |
62 | - * @param timestamp to compare agains | 62 | + * @param other timestamp to compare against |
63 | * @return true if this instance is newer | 63 | * @return true if this instance is newer |
64 | */ | 64 | */ |
65 | - public boolean isNewer(Timestamp timestamp) { | 65 | + public boolean isNewer(Timestamp other) { |
66 | - return this.timestamp.compareTo(checkNotNull(timestamp)) > 0; | 66 | + return this.timestamp.compareTo(checkNotNull(other)) > 0; |
67 | } | 67 | } |
68 | 68 | ||
69 | @Override | 69 | @Override | ... | ... |
This diff is collapsed. Click to expand it.
... | @@ -4,7 +4,7 @@ import com.google.common.base.MoreObjects; | ... | @@ -4,7 +4,7 @@ import com.google.common.base.MoreObjects; |
4 | 4 | ||
5 | import org.onlab.onos.net.link.LinkDescription; | 5 | import org.onlab.onos.net.link.LinkDescription; |
6 | import org.onlab.onos.net.provider.ProviderId; | 6 | import org.onlab.onos.net.provider.ProviderId; |
7 | -import org.onlab.onos.store.common.impl.Timestamped; | 7 | +import org.onlab.onos.store.impl.Timestamped; |
8 | 8 | ||
9 | /** | 9 | /** |
10 | * Information published by GossipDeviceStore to notify peers of a device | 10 | * Information published by GossipDeviceStore to notify peers of a device | ... | ... |
1 | package org.onlab.onos.store.serializers; | 1 | package org.onlab.onos.store.serializers; |
2 | 2 | ||
3 | -import org.onlab.onos.store.common.impl.Timestamped; | ||
4 | import org.onlab.onos.store.impl.MastershipBasedTimestamp; | 3 | import org.onlab.onos.store.impl.MastershipBasedTimestamp; |
4 | +import org.onlab.onos.store.impl.Timestamped; | ||
5 | import org.onlab.onos.store.impl.WallClockTimestamp; | 5 | import org.onlab.onos.store.impl.WallClockTimestamp; |
6 | import org.onlab.util.KryoPool; | 6 | import org.onlab.util.KryoPool; |
7 | 7 | ... | ... |
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
core/store/hz/net/src/main/java/org/onlab/onos/store/flow/impl/DistributedFlowRuleStore.java
deleted
100644 → 0
This diff is collapsed. Click to expand it.
core/store/hz/net/src/main/java/org/onlab/onos/store/host/impl/DistributedHostStore.java
deleted
100644 → 0
This diff is collapsed. Click to expand it.
core/store/hz/net/src/main/java/org/onlab/onos/store/link/impl/DistributedLinkStore.java
deleted
100644 → 0
This diff is collapsed. Click to expand it.
core/store/hz/net/src/main/java/org/onlab/onos/store/topology/impl/DefaultTopology.java
deleted
100644 → 0
This diff is collapsed. Click to expand it.
core/store/hz/net/src/main/java/org/onlab/onos/store/topology/impl/DefaultTopologyGraph.java
deleted
100644 → 0
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
core/store/hz/net/src/test/java/org/onlab/onos/store/link/impl/DistributedLinkStoreTest.java
deleted
100644 → 0
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
core/store/serializers/src/main/java/org/onlab/onos/store/serializers/HostLocationSerializer.java
0 → 100644
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
core/store/serializers/src/main/java/org/onlab/onos/store/serializers/MacAddressSerializer.java
0 → 100644
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
providers/openflow/link/src/main/java/org/onlab/onos/provider/of/link/impl/OpenFlowLinkProvider.java
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
tools/dev/onos.cshrc
0 → 100644
This diff is collapsed. Click to expand it.
tools/test/bin/onos-list-cells
0 → 100755
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
tools/test/bin/onos-show-cell
0 → 100755
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
utils/thirdparty/pom.xml
0 → 100644
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
-
Please register or login to post a comment