Ayaka Koshibe

Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next

Showing 162 changed files with 8291 additions and 523 deletions
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 +/**
2 + * Application providing integration between OSCARS and ONOS intent
3 + * framework via REST API.
4 + */
5 +package org.onlab.onos.calendar;
...\ No newline at end of file ...\ No newline at end of file
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
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-optical</artifactId>
15 + <packaging>bundle</packaging>
16 +
17 + <description>ONOS application for packet/optical deployments</description>
18 +
19 + <dependencies>
20 +
21 + <dependency>
22 + <groupId>org.onlab.onos</groupId>
23 + <artifactId>onos-cli</artifactId>
24 + <version>${project.version}</version>
25 + </dependency>
26 + <dependency>
27 + <groupId>org.apache.karaf.shell</groupId>
28 + <artifactId>org.apache.karaf.shell.console</artifactId>
29 + </dependency>
30 +
31 + <dependency>
32 + <groupId>org.codehaus.jackson</groupId>
33 + <artifactId>jackson-core-asl</artifactId>
34 + </dependency>
35 + <dependency>
36 + <groupId>org.codehaus.jackson</groupId>
37 + <artifactId>jackson-mapper-asl</artifactId>
38 + </dependency>
39 + <dependency>
40 + <groupId>com.fasterxml.jackson.core</groupId>
41 + <artifactId>jackson-annotations</artifactId>
42 + <scope>provided</scope>
43 + </dependency>
44 +
45 + </dependencies>
46 +
47 +</project>
1 +package org.onlab.onos.optical.cfg;
2 +
3 +import static org.onlab.onos.net.DeviceId.deviceId;
4 +
5 +import java.io.File;
6 +import java.io.IOException;
7 +import java.util.ArrayList;
8 +import java.util.Iterator;
9 +import java.util.List;
10 +import java.util.Map;
11 +import java.util.Set;
12 +
13 +import org.apache.felix.scr.annotations.Activate;
14 +import org.apache.felix.scr.annotations.Component;
15 +import org.apache.felix.scr.annotations.Deactivate;
16 +import org.apache.felix.scr.annotations.Reference;
17 +import org.apache.felix.scr.annotations.ReferenceCardinality;
18 +import org.codehaus.jackson.JsonNode;
19 +import org.codehaus.jackson.JsonParseException;
20 +import org.codehaus.jackson.annotate.JsonIgnoreProperties;
21 +import org.codehaus.jackson.map.JsonMappingException;
22 +import org.codehaus.jackson.map.ObjectMapper;
23 +import org.onlab.onos.net.ConnectPoint;
24 +import org.onlab.onos.net.DefaultAnnotations;
25 +import org.onlab.onos.net.Device;
26 +import org.onlab.onos.net.DeviceId;
27 +import org.onlab.onos.net.Link;
28 +import org.onlab.onos.net.MastershipRole;
29 +import org.onlab.onos.net.PortNumber;
30 +import org.onlab.onos.net.device.DefaultDeviceDescription;
31 +import org.onlab.onos.net.device.DeviceDescription;
32 +import org.onlab.onos.net.device.DeviceProvider;
33 +import org.onlab.onos.net.device.DeviceProviderRegistry;
34 +import org.onlab.onos.net.device.DeviceProviderService;
35 +import org.onlab.onos.net.link.DefaultLinkDescription;
36 +import org.onlab.onos.net.link.LinkProvider;
37 +import org.onlab.onos.net.link.LinkProviderRegistry;
38 +import org.onlab.onos.net.link.LinkProviderService;
39 +import org.onlab.onos.net.provider.AbstractProvider;
40 +import org.onlab.onos.net.provider.ProviderId;
41 +import org.onlab.packet.ChassisId;
42 +import org.slf4j.Logger;
43 +import org.slf4j.LoggerFactory;
44 +
45 +/**
46 + * OpticalConfigProvider emulates the SB network provider for optical switches,
47 + * optical links and any other state that needs to be configured for correct network
48 + * operations.
49 + *
50 + */
51 +
52 +@JsonIgnoreProperties(ignoreUnknown = true)
53 +@Component(immediate = true)
54 +public class OpticalConfigProvider extends AbstractProvider implements DeviceProvider, LinkProvider {
55 +
56 + protected static final Logger log = LoggerFactory
57 + .getLogger(OpticalConfigProvider.class);
58 +
59 + // TODO: fix hard coded file path later.
60 + private static final String DEFAULT_CONFIG_FILE =
61 + "/opt/onos/config/demo-3-roadm-2-ps.json";
62 + private String configFileName = DEFAULT_CONFIG_FILE;
63 +
64 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
65 + protected LinkProviderRegistry linkProviderRegistry;
66 +
67 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
68 + protected DeviceProviderRegistry deviceProviderRegistry;
69 +
70 + private static final String OPTICAL_ANNOTATION = "optical.";
71 +
72 + private LinkProviderService linkProviderService;
73 + private DeviceProviderService deviceProviderService;
74 +
75 + private static final List<Roadm> RAW_ROADMS = new ArrayList<>();
76 + private static final List<WdmLink> RAW_WDMLINKS = new ArrayList<>();
77 + private static final List<PktOptLink> RAW_PKTOPTLINKS = new ArrayList<>();
78 +
79 + private static final String ROADM = "Roadm";
80 + private static final String WDM_LINK = "wdmLink";
81 + private static final String PKT_OPT_LINK = "pktOptLink";
82 +
83 + protected OpticalNetworkConfig opticalNetworkConfig;
84 +
85 + public OpticalConfigProvider() {
86 + super(new ProviderId("of", "org.onlab.onos.provider.opticalConfig", true));
87 + }
88 +
89 + @Activate
90 + protected void activate() {
91 + linkProviderService = linkProviderRegistry.register(this);
92 + deviceProviderService = deviceProviderRegistry.register(this);
93 + log.info("Starting optical network configuration process...");
94 + log.info("Optical config file set to {}", configFileName);
95 +
96 + loadOpticalConfig();
97 + parseOpticalConfig();
98 + publishOpticalConfig();
99 + }
100 +
101 + @Deactivate
102 + protected void deactivate() {
103 + linkProviderRegistry.unregister(this);
104 + linkProviderService = null;
105 + deviceProviderRegistry.unregister(this);
106 + deviceProviderService = null;
107 + RAW_ROADMS.clear();
108 + RAW_WDMLINKS.clear();
109 + RAW_PKTOPTLINKS.clear();
110 + log.info("Stopped");
111 + }
112 +
113 + private void loadOpticalConfig() {
114 + ObjectMapper mapper = new ObjectMapper();
115 + opticalNetworkConfig = new OpticalNetworkConfig();
116 + try {
117 + opticalNetworkConfig = mapper.readValue(new File(configFileName), OpticalNetworkConfig.class);
118 + } catch (JsonParseException e) {
119 + String err = String.format("JsonParseException while loading network "
120 + + "config from file: %s: %s", configFileName, e.getMessage());
121 + log.error(err, e);
122 + } catch (JsonMappingException e) {
123 + String err = String.format(
124 + "JsonMappingException while loading network config "
125 + + "from file: %s: %s", configFileName, e.getMessage());
126 + log.error(err, e);
127 + } catch (IOException e) {
128 + String err = String.format("IOException while loading network config "
129 + + "from file: %s %s", configFileName, e.getMessage());
130 + log.error(err, e);
131 + }
132 + }
133 +
134 + private void parseOpticalConfig() {
135 + List<OpticalSwitchDescription> swList = opticalNetworkConfig.getOpticalSwitches();
136 + List<OpticalLinkDescription> lkList = opticalNetworkConfig.getOpticalLinks();
137 +
138 + for (OpticalSwitchDescription sw : swList) {
139 + String swtype = sw.getType();
140 + boolean allow = sw.isAllowed();
141 + if (swtype.equals(ROADM) && allow) {
142 + int regNum = 0;
143 + Set<Map.Entry<String, JsonNode>> m = sw.params.entrySet();
144 + for (Map.Entry<String, JsonNode> e : m) {
145 + String key = e.getKey();
146 + JsonNode j = e.getValue();
147 + if (key.equals("numRegen")) {
148 + regNum = j.asInt();
149 + }
150 + }
151 +
152 + Roadm newRoadm = new Roadm();
153 + newRoadm.setName(sw.name);
154 + newRoadm.setNodeId(sw.nodeDpid);
155 + newRoadm.setLongtitude(sw.longitude);
156 + newRoadm.setLatitude(sw.latitude);
157 + newRoadm.setRegenNum(regNum);
158 +
159 + RAW_ROADMS.add(newRoadm);
160 + log.info(newRoadm.toString());
161 + }
162 + }
163 +
164 + for (OpticalLinkDescription lk : lkList) {
165 + String lktype = lk.getType();
166 + switch (lktype) {
167 + case WDM_LINK:
168 + WdmLink newWdmLink = new WdmLink();
169 + newWdmLink.setSrcNodeId(lk.getNodeDpid1());
170 + newWdmLink.setSnkNodeId(lk.getNodeDpid2());
171 + newWdmLink.setAdminWeight(1000); // default weight for each WDM link.
172 + Set<Map.Entry<String, JsonNode>> m = lk.params.entrySet();
173 + for (Map.Entry<String, JsonNode> e : m) {
174 + String key = e.getKey();
175 + JsonNode j = e.getValue();
176 + if (key.equals("nodeName1")) {
177 + newWdmLink.setSrcNodeName(j.asText());
178 + } else if (key.equals("nodeName2")) {
179 + newWdmLink.setSnkNodeName(j.asText());
180 + } else if (key.equals("port1")) {
181 + newWdmLink.setSrcPort(j.asInt());
182 + } else if (key.equals("port2")) {
183 + newWdmLink.setSnkPort(j.asInt());
184 + } else if (key.equals("distKms")) {
185 + newWdmLink.setDistance(j.asDouble());
186 + } else if (key.equals("numWaves")) {
187 + newWdmLink.setWavelengthNumber(j.asInt());
188 + } else {
189 + log.error("error found");
190 + // TODO add exception processing;
191 + }
192 + }
193 + RAW_WDMLINKS.add(newWdmLink);
194 + log.info(newWdmLink.toString());
195 +
196 + break;
197 +
198 + case PKT_OPT_LINK:
199 + PktOptLink newPktOptLink = new PktOptLink();
200 + newPktOptLink.setSrcNodeId(lk.getNodeDpid1());
201 + newPktOptLink.setSnkNodeId(lk.getNodeDpid2());
202 + newPktOptLink.setAdminWeight(10); // default weight for each packet-optical link.
203 + Set<Map.Entry<String, JsonNode>> ptm = lk.params.entrySet();
204 + for (Map.Entry<String, JsonNode> e : ptm) {
205 + String key = e.getKey();
206 + JsonNode j = e.getValue();
207 + if (key.equals("nodeName1")) {
208 + newPktOptLink.setSrcNodeName(j.asText());
209 + } else if (key.equals("nodeName2")) {
210 + newPktOptLink.setSnkNodeName(j.asText());
211 + } else if (key.equals("port1")) {
212 + newPktOptLink.setSrcPort(j.asInt());
213 + } else if (key.equals("port2")) {
214 + newPktOptLink.setSnkPort(j.asInt());
215 + } else if (key.equals("bandWidth")) {
216 + newPktOptLink.setBandwdith(j.asDouble());
217 + } else {
218 + log.error("error found");
219 + // TODO add exception processing;
220 + }
221 + }
222 +
223 + RAW_PKTOPTLINKS.add(newPktOptLink);
224 + log.info(newPktOptLink.toString());
225 + break;
226 + default:
227 + }
228 + }
229 + }
230 +
231 + private void publishOpticalConfig() {
232 + if (deviceProviderService == null || linkProviderService == null) {
233 + return;
234 + }
235 +
236 + // Discover the optical ROADM objects
237 + Iterator<Roadm> iterWdmNode = RAW_ROADMS.iterator();
238 + while (iterWdmNode.hasNext()) {
239 + Roadm value = iterWdmNode.next();
240 + DeviceId did = deviceId("of:" + value.getNodeId().replace(":", ""));
241 + ChassisId cid = new ChassisId(value.getNodeId());
242 + DefaultAnnotations extendedAttributes = DefaultAnnotations.builder()
243 + .set(OPTICAL_ANNOTATION + "switchType", "ROADM")
244 + .set(OPTICAL_ANNOTATION + "switchName", value.getName())
245 + .set(OPTICAL_ANNOTATION + "latitude", Double.toString(value.getLatitude()))
246 + .set(OPTICAL_ANNOTATION + "longtitude", Double.toString(value.getLongtitude()))
247 + .set(OPTICAL_ANNOTATION + "regNum", Integer.toString(value.getRegenNum()))
248 + .build();
249 +
250 + DeviceDescription description =
251 + new DefaultDeviceDescription(did.uri(),
252 + Device.Type.SWITCH,
253 + "",
254 + "",
255 + "",
256 + "",
257 + cid,
258 + extendedAttributes);
259 + deviceProviderService.deviceConnected(did, description);
260 + }
261 +
262 + // Discover the optical WDM link objects
263 + Iterator<WdmLink> iterWdmlink = RAW_WDMLINKS.iterator();
264 + while (iterWdmlink.hasNext()) {
265 + WdmLink value = iterWdmlink.next();
266 +
267 + DeviceId srcNodeId = deviceId("of:" + value.getSrcNodeId().replace(":", ""));
268 + DeviceId snkNodeId = deviceId("of:" + value.getSnkNodeId().replace(":", ""));
269 +
270 + PortNumber srcPort = PortNumber.portNumber(value.getSrcPort());
271 + PortNumber snkPort = PortNumber.portNumber(value.getSnkPort());
272 +
273 + ConnectPoint srcPoint = new ConnectPoint(srcNodeId, srcPort);
274 + ConnectPoint snkPoint = new ConnectPoint(snkNodeId, snkPort);
275 +
276 + DefaultAnnotations extendedAttributes = DefaultAnnotations.builder()
277 + .set(OPTICAL_ANNOTATION + "linkType", "WDM")
278 + .set(OPTICAL_ANNOTATION + "distance", Double.toString(value.getDistance()))
279 + .set(OPTICAL_ANNOTATION + "cost", Double.toString(value.getDistance()))
280 + .set(OPTICAL_ANNOTATION + "adminWeight", Double.toString(value.getAdminWeight()))
281 + .set(OPTICAL_ANNOTATION + "wavelengthNum", Integer.toString(value.getWavelengthNumber()))
282 + .build();
283 +
284 + DefaultLinkDescription linkDescription =
285 + new DefaultLinkDescription(srcPoint,
286 + snkPoint,
287 + Link.Type.DIRECT,
288 + extendedAttributes);
289 +
290 + linkProviderService.linkDetected(linkDescription);
291 + log.info(String.format("WDM link: %s : %s",
292 + linkDescription.src().toString(), linkDescription.dst().toString()));
293 + }
294 +
295 + // Discover the packet optical link objects
296 + Iterator<PktOptLink> iterPktOptlink = RAW_PKTOPTLINKS.iterator();
297 + while (iterPktOptlink.hasNext()) {
298 + PktOptLink value = iterPktOptlink.next();
299 + DeviceId srcNodeId = deviceId("of:" + value.getSrcNodeId().replace(":", ""));
300 + DeviceId snkNodeId = deviceId("of:" + value.getSnkNodeId().replace(":", ""));
301 +
302 + PortNumber srcPort = PortNumber.portNumber(value.getSrcPort());
303 + PortNumber snkPort = PortNumber.portNumber(value.getSnkPort());
304 +
305 + ConnectPoint srcPoint = new ConnectPoint(srcNodeId, srcPort);
306 + ConnectPoint snkPoint = new ConnectPoint(snkNodeId, snkPort);
307 +
308 + DefaultAnnotations extendedAttributes = DefaultAnnotations.builder()
309 + .set(OPTICAL_ANNOTATION + "linkType", "PktOptLink")
310 + .set(OPTICAL_ANNOTATION + "bandwidth", Double.toString(value.getBandwidth()))
311 + .set(OPTICAL_ANNOTATION + "cost", Double.toString(value.getBandwidth()))
312 + .set(OPTICAL_ANNOTATION + "adminWeight", Double.toString(value.getAdminWeight()))
313 + .build();
314 +
315 + DefaultLinkDescription linkDescription =
316 + new DefaultLinkDescription(srcPoint,
317 + snkPoint,
318 + Link.Type.DIRECT,
319 + extendedAttributes);
320 +
321 + linkProviderService.linkDetected(linkDescription);
322 + log.info(String.format("Packet-optical link: %s : %s",
323 + linkDescription.src().toString(), linkDescription.dst().toString()));
324 + }
325 +
326 + }
327 +
328 + @Override
329 + public void triggerProbe(Device device) {
330 + // TODO We may want to consider re-reading config files and publishing them based on this event.
331 + }
332 +
333 + @Override
334 + public void roleChanged(Device device, MastershipRole newRole) {
335 + // TODO Auto-generated method stub.
336 + }
337 +
338 +}
1 +package org.onlab.onos.optical.cfg;
2 +
3 +import java.util.Map;
4 +import org.codehaus.jackson.JsonNode;
5 +import org.onlab.util.HexString;
6 +
7 +/**
8 + * Public class corresponding to JSON described data model.
9 + */
10 +public class OpticalLinkDescription {
11 + protected String type;
12 + protected Boolean allowed;
13 + protected long dpid1;
14 + protected long dpid2;
15 + protected String nodeDpid1;
16 + protected String nodeDpid2;
17 + protected Map<String, JsonNode> params;
18 + protected Map<String, String> publishAttributes;
19 +
20 + public String getType() {
21 + return type;
22 + }
23 +
24 + public void setType(String type) {
25 + this.type = type;
26 + }
27 +
28 + public Boolean isAllowed() {
29 + return allowed;
30 + }
31 +
32 + public void setAllowed(Boolean allowed) {
33 + this.allowed = allowed;
34 + }
35 +
36 + public String getNodeDpid1() {
37 + return nodeDpid1;
38 + }
39 +
40 + public void setNodeDpid1(String nodeDpid1) {
41 + this.nodeDpid1 = nodeDpid1;
42 + this.dpid1 = HexString.toLong(nodeDpid1);
43 + }
44 +
45 + public String getNodeDpid2() {
46 + return nodeDpid2;
47 + }
48 +
49 + public void setNodeDpid2(String nodeDpid2) {
50 + this.nodeDpid2 = nodeDpid2;
51 + this.dpid2 = HexString.toLong(nodeDpid2);
52 + }
53 +
54 + public long getDpid1() {
55 + return dpid1;
56 + }
57 +
58 + public void setDpid1(long dpid1) {
59 + this.dpid1 = dpid1;
60 + this.nodeDpid1 = HexString.toHexString(dpid1);
61 + }
62 +
63 + public long getDpid2() {
64 + return dpid2;
65 + }
66 +
67 + public void setDpid2(long dpid2) {
68 + this.dpid2 = dpid2;
69 + this.nodeDpid2 = HexString.toHexString(dpid2);
70 + }
71 +
72 + public Map<String, JsonNode> getParams() {
73 + return params;
74 + }
75 +
76 + public void setParams(Map<String, JsonNode> params) {
77 + this.params = params;
78 + }
79 +
80 + public Map<String, String> getPublishAttributes() {
81 + return publishAttributes;
82 + }
83 +
84 + public void setPublishAttributes(Map<String, String> publishAttributes) {
85 + this.publishAttributes = publishAttributes;
86 + }
87 +
88 +}
89 +
1 +package org.onlab.onos.optical.cfg;
2 +
3 +import java.util.ArrayList;
4 +import java.util.List;
5 +
6 +import org.slf4j.Logger;
7 +import org.slf4j.LoggerFactory;
8 +
9 +/**
10 + * Public class corresponding to JSON described data model.
11 + */
12 +public class OpticalNetworkConfig {
13 + protected static final Logger log = LoggerFactory.getLogger(OpticalNetworkConfig.class);
14 +
15 + private List<OpticalSwitchDescription> opticalSwitches;
16 + private List<OpticalLinkDescription> opticalLinks;
17 +
18 + public OpticalNetworkConfig() {
19 + opticalSwitches = new ArrayList<OpticalSwitchDescription>();
20 + opticalLinks = new ArrayList<OpticalLinkDescription>();
21 + }
22 +
23 + public List<OpticalSwitchDescription> getOpticalSwitches() {
24 + return opticalSwitches;
25 + }
26 +
27 + public void setOpticalSwitches(List<OpticalSwitchDescription> switches) {
28 + this.opticalSwitches = switches;
29 + }
30 +
31 + public List<OpticalLinkDescription> getOpticalLinks() {
32 + return opticalLinks;
33 + }
34 +
35 + public void setOpticalLinks(List<OpticalLinkDescription> links) {
36 + this.opticalLinks = links;
37 + }
38 +
39 +}
40 +
1 +package org.onlab.onos.optical.cfg;
2 +
3 +import java.util.Map;
4 +import org.codehaus.jackson.JsonNode;
5 +import org.codehaus.jackson.annotate.JsonProperty;
6 +import org.onlab.util.HexString;
7 +
8 +/**
9 + * Public class corresponding to JSON described data model.
10 + */
11 +public class OpticalSwitchDescription {
12 + protected String name;
13 + protected long dpid;
14 + protected String nodeDpid;
15 + protected String type;
16 + protected double latitude;
17 + protected double longitude;
18 + protected boolean allowed;
19 + protected Map<String, JsonNode> params;
20 + protected Map<String, String> publishAttributes;
21 +
22 + public String getName() {
23 + return name;
24 + }
25 + @JsonProperty("name")
26 + public void setName(String name) {
27 + this.name = name;
28 + }
29 +
30 + public long getDpid() {
31 + return dpid;
32 + }
33 + @JsonProperty("dpid")
34 + public void setDpid(long dpid) {
35 + this.dpid = dpid;
36 + this.nodeDpid = HexString.toHexString(dpid);
37 + }
38 +
39 + public String getNodeDpid() {
40 + return nodeDpid;
41 + }
42 +
43 + public String getHexDpid() {
44 + return nodeDpid;
45 + }
46 +
47 + public void setNodeDpid(String nodeDpid) {
48 + this.nodeDpid = nodeDpid;
49 + this.dpid = HexString.toLong(nodeDpid);
50 + }
51 +
52 + public String getType() {
53 + return type;
54 + }
55 +
56 + public void setType(String type) {
57 + this.type = type;
58 + }
59 +
60 + public double getLatitude() {
61 + return latitude;
62 + }
63 +
64 + public void setLatitude(double latitude) {
65 + this.latitude = latitude;
66 + }
67 +
68 + public double getLongitude() {
69 + return longitude;
70 + }
71 +
72 + public void setLongitude(double longitude) {
73 + this.longitude = longitude;
74 + }
75 +
76 + public boolean isAllowed() {
77 + return allowed;
78 + }
79 +
80 + public void setAllowed(boolean allowed) {
81 + this.allowed = allowed;
82 + }
83 +
84 + public Map<String, JsonNode> getParams() {
85 + return params;
86 + }
87 +
88 + public void setParams(Map<String, JsonNode> params) {
89 + this.params = params;
90 + }
91 +
92 + public Map<String, String> getPublishAttributes() {
93 + return publishAttributes;
94 + }
95 +
96 + public void setPublishAttributes(Map<String, String> publishAttributes) {
97 + this.publishAttributes = publishAttributes;
98 + }
99 +
100 +}
1 +package org.onlab.onos.optical.cfg;
2 +
3 +/**
4 + * Packet-optical link Java data object.
5 + */
6 +class PktOptLink {
7 + private String srcNodeName;
8 + private String snkNodeName;
9 + private String srcNodeId;
10 + private String snkNodeId;
11 + private int srcPort;
12 + private int snkPort;
13 + private double bandwidth;
14 + private double cost;
15 + private long adminWeight;
16 +
17 + public PktOptLink(String srcName, String snkName) {
18 + this.srcNodeName = srcName;
19 + this.snkNodeName = snkName;
20 + }
21 +
22 + public PktOptLink() {
23 + // TODO Auto-generated constructor stub
24 + }
25 +
26 + public void setSrcNodeName(String name) {
27 + this.srcNodeName = name;
28 + }
29 +
30 + public String getSrcNodeName() {
31 + return this.srcNodeName;
32 + }
33 +
34 + public void setSnkNodeName(String name) {
35 + this.snkNodeName = name;
36 + }
37 +
38 + public String getSnkNodeName() {
39 + return this.snkNodeName;
40 + }
41 +
42 + public void setSrcNodeId(String nodeId) {
43 + this.srcNodeId = nodeId;
44 + }
45 +
46 + public String getSrcNodeId() {
47 + return this.srcNodeId;
48 + }
49 +
50 + public void setSnkNodeId(String nodeId) {
51 + this.snkNodeId = nodeId;
52 + }
53 +
54 + public String getSnkNodeId() {
55 + return this.snkNodeId;
56 + }
57 +
58 + public void setSrcPort(int port) {
59 + this.srcPort = port;
60 + }
61 +
62 + public int getSrcPort() {
63 + return this.srcPort;
64 + }
65 +
66 + public void setSnkPort(int port) {
67 + this.snkPort = port;
68 + }
69 +
70 + public int getSnkPort() {
71 + return this.snkPort;
72 + }
73 +
74 + public void setBandwdith(double x) {
75 + this.bandwidth = x;
76 + }
77 +
78 + public double getBandwidth() {
79 + return this.bandwidth;
80 + }
81 +
82 + public void setCost(double x) {
83 + this.cost = x;
84 + }
85 +
86 + public double getCost() {
87 + return this.cost;
88 + }
89 +
90 + public void setAdminWeight(long x) {
91 + this.adminWeight = x;
92 + }
93 +
94 + public long getAdminWeight() {
95 + return this.adminWeight;
96 + }
97 +
98 + @Override
99 + public String toString() {
100 + return new StringBuilder(" srcNodeName: ").append(this.srcNodeName)
101 + .append(" snkNodeName: ").append(this.snkNodeName)
102 + .append(" srcNodeId: ").append(this.srcNodeId)
103 + .append(" snkNodeId: ").append(this.snkNodeId)
104 + .append(" srcPort: ").append(this.srcPort)
105 + .append(" snkPort: ").append(this.snkPort)
106 + .append(" bandwidth: ").append(this.bandwidth)
107 + .append(" cost: ").append(this.cost)
108 + .append(" adminWeight: ").append(this.adminWeight).toString();
109 + }
110 +}
1 +package org.onlab.onos.optical.cfg;
2 +
3 +/**
4 + * ROADM java data object converted from a JSON file.
5 + */
6 +class Roadm {
7 + private String name;
8 + private String nodeID;
9 + private double longtitude;
10 + private double latitude;
11 + private int regenNum;
12 +
13 + //TODO use the following attributes when needed for configurations
14 + private int tPort10G;
15 + private int tPort40G;
16 + private int tPort100G;
17 + private int wPort;
18 +
19 + public Roadm() {
20 + }
21 +
22 + public Roadm(String name) {
23 + this.name = name;
24 + }
25 +
26 + public void setName(String name) {
27 + this.name = name;
28 + }
29 +
30 + public String getName() {
31 + return this.name;
32 + }
33 +
34 + public void setNodeId(String nameId) {
35 + this.nodeID = nameId;
36 + }
37 +
38 + public String getNodeId() {
39 + return this.nodeID;
40 + }
41 +
42 + public void setLongtitude(double x) {
43 + this.longtitude = x;
44 + }
45 +
46 + public double getLongtitude() {
47 + return this.longtitude;
48 + }
49 +
50 + public void setLatitude(double y) {
51 + this.latitude = y;
52 + }
53 +
54 + public double getLatitude() {
55 + return this.latitude;
56 + }
57 +
58 + public void setRegenNum(int num) {
59 + this.regenNum = num;
60 + }
61 + public int getRegenNum() {
62 + return this.regenNum;
63 + }
64 +
65 + public void setTport10GNum(int num) {
66 + this.tPort10G = num;
67 + }
68 + public int getTport10GNum() {
69 + return this.tPort10G;
70 + }
71 +
72 + public void setTport40GNum(int num) {
73 + this.tPort40G = num;
74 + }
75 + public int getTport40GNum() {
76 + return this.tPort40G;
77 + }
78 +
79 + public void setTport100GNum(int num) {
80 + this.tPort100G = num;
81 + }
82 + public int getTport100GNum() {
83 + return this.tPort100G;
84 + }
85 +
86 + public void setWportNum(int num) {
87 + this.wPort = num;
88 + }
89 + public int getWportNum() {
90 + return this.wPort;
91 + }
92 +
93 + @Override
94 + public String toString() {
95 + return new StringBuilder(" ROADM Name: ").append(this.name)
96 + .append(" nodeID: ").append(this.nodeID)
97 + .append(" longtitude: ").append(this.longtitude)
98 + .append(" latitude: ").append(this.latitude)
99 + .append(" regenNum: ").append(this.regenNum)
100 + .append(" 10GTportNum: ").append(this.tPort10G)
101 + .append(" 40GTportNum: ").append(this.tPort40G)
102 + .append(" 100GTportNum: ").append(this.tPort100G)
103 + .append(" WportNum: ").append(this.wPort).toString();
104 + }
105 +}
106 +
1 +package org.onlab.onos.optical.cfg;
2 +
3 +/**
4 + * WDM Link Java data object converted from a JSON file.
5 + */
6 +class WdmLink {
7 + private String srcNodeName;
8 + private String snkNodeName;
9 + private String srcNodeId;
10 + private String snkNodeId;
11 + private int srcPort;
12 + private int snkPort;
13 + private double distance;
14 + private double cost;
15 + private int wavelengthNumber;
16 + private long adminWeight;
17 +
18 + public WdmLink(String name1, String name2) {
19 + this.srcNodeName = name1;
20 + this.snkNodeName = name2;
21 + }
22 +
23 + public WdmLink() {
24 + // TODO Auto-generated constructor stub
25 + }
26 +
27 + public void setSrcNodeName(String name) {
28 + this.srcNodeName = name;
29 + }
30 +
31 + public String getSrcNodeName() {
32 + return this.srcNodeName;
33 + }
34 +
35 + public void setSnkNodeName(String name) {
36 + this.snkNodeName = name;
37 + }
38 +
39 + public String getSnkNodeName() {
40 + return this.snkNodeName;
41 + }
42 +
43 + public void setSrcNodeId(String nodeId) {
44 + this.srcNodeId = nodeId;
45 + }
46 +
47 + public String getSrcNodeId() {
48 + return this.srcNodeId;
49 + }
50 +
51 + public void setSnkNodeId(String nodeId) {
52 + this.snkNodeId = nodeId;
53 + }
54 +
55 + public String getSnkNodeId() {
56 + return this.snkNodeId;
57 + }
58 +
59 + public void setSrcPort(int port) {
60 + this.srcPort = port;
61 + }
62 +
63 + public int getSrcPort() {
64 + return this.srcPort;
65 + }
66 +
67 + public void setSnkPort(int port) {
68 + this.snkPort = port;
69 + }
70 +
71 + public int getSnkPort() {
72 + return this.snkPort;
73 + }
74 +
75 + public void setDistance(double x) {
76 + this.distance = x;
77 + }
78 +
79 + public double getDistance() {
80 + return this.distance;
81 + }
82 +
83 + public void setCost(double x) {
84 + this.cost = x;
85 + }
86 +
87 + public double getCost() {
88 + return this.cost;
89 + }
90 +
91 + public void setWavelengthNumber(int x) {
92 + this.wavelengthNumber = x;
93 + }
94 +
95 + public int getWavelengthNumber() {
96 + return this.wavelengthNumber;
97 + }
98 +
99 + public void setAdminWeight(long x) {
100 + this.adminWeight = x;
101 + }
102 +
103 + public long getAdminWeight() {
104 + return this.adminWeight;
105 + }
106 +
107 + @Override
108 + public String toString() {
109 + return new StringBuilder(" srcNodeName: ").append(this.srcNodeName)
110 + .append(" snkNodeName: ").append(this.snkNodeName)
111 + .append(" srcNodeId: ").append(this.srcNodeId)
112 + .append(" snkNodeId: ").append(this.snkNodeId)
113 + .append(" srcPort: ").append(this.srcPort)
114 + .append(" snkPort: ").append(this.snkPort)
115 + .append(" distance: ").append(this.distance)
116 + .append(" cost: ").append(this.cost)
117 + .append(" wavelengthNumber: ").append(this.wavelengthNumber)
118 + .append(" adminWeight: ").append(this.adminWeight).toString();
119 + }
120 +}
121 +
1 +{
2 + "opticalSwitches": [
3 + {
4 + "allowed": true,
5 + "latitude": 37.6,
6 + "longitude": 122.3,
7 + "name": "SFO-W10",
8 + "nodeDpid": "00:00:ff:ff:ff:ff:ff:01",
9 + "params": {
10 + "numRegen": 0
11 + },
12 + "type": "Roadm"
13 + },
14 +
15 + {
16 + "allowed": true,
17 + "latitude": 37.3,
18 + "longitude": 121.9,
19 + "name": "SJC-W10",
20 + "nodeDpid": "00:00:ff:ff:ff:ff:ff:02",
21 + "params": {
22 + "numRegen": 0
23 + },
24 + "type": "Roadm"
25 + },
26 +
27 + {
28 + "allowed": true,
29 + "latitude": 33.9,
30 + "longitude": 118.4
31 + "name": "LAX-W10",
32 + "nodeDpid": "00:00:ff:ff:ff:ff:ff:03",
33 + "params": {
34 + "numRegen": 0
35 + },
36 + "type": "Roadm"
37 + },
38 +
39 + {
40 + "allowed": true,
41 + "latitude": 32.8,
42 + "longitude": 117.1,
43 + "name": "SDG-W10",
44 + "nodeDpid": "00:00:ff:ff:ff:ff:ff:04",
45 + "params": {
46 + "numRegen": 3
47 + },
48 + "type": "Roadm"
49 + },
50 +
51 + {
52 + "allowed": true,
53 + "latitude": 44.8,
54 + "longitude": 93.1,
55 + "name": "MSP-M10",
56 + "nodeDpid": "00:00:ff:ff:ff:ff:ff:05",
57 + "params": {
58 + "numRegen": 3
59 + },
60 + "type": "Roadm"
61 + },
62 +
63 + {
64 + "allowed": true,
65 + "latitude": 32.8,
66 + "longitude": 97.1,
67 + "name": "DFW-M10",
68 + "nodeDpid": "00:00:ff:ff:ff:ff:ff:06",
69 + "params": {
70 + "numRegen": 3
71 + },
72 + "type": "Roadm"
73 + },
74 +
75 + {
76 + "allowed": true,
77 + "latitude": 41.8,
78 + "longitude": 120.1,
79 + "name": "CHG-N10",
80 + "nodeDpid": "00:00:ff:ff:ff:ff:ff:07",
81 + "params": {
82 + "numRegen": 3
83 + },
84 + "type": "Roadm"
85 + },
86 +
87 + {
88 + "allowed": true,
89 + "latitude": 38.8,
90 + "longitude": 77.1,
91 + "name": "IAD-M10",
92 + "nodeDpid": "00:00:ff:ff:ff:ff:ff:08",
93 + "params": {
94 + "numRegen": 3
95 + },
96 + "type": "Roadm"
97 + },
98 +
99 + {
100 + "allowed": true,
101 + "latitude": 40.8,
102 + "longitude": 73.1,
103 + "name": "JFK-E10",
104 + "nodeDpid": "00:00:ff:ff:ff:ff:ff:09",
105 + "params": {
106 + "numRegen": 0
107 + },
108 + "type": "Roadm"
109 +
110 + },
111 +
112 + {
113 + "allowed": true,
114 + "latitude": 33.8,
115 + "longitude": 84.1,
116 + "name": "ATL-S10",
117 + "nodeDpid": "00:00:ff:ff:ff:ff:ff:0A",
118 + "params": {
119 + "numRegen": 0
120 + },
121 + "type": "Roadm"
122 + }
123 +
124 + ],
125 +
126 + "opticalLinks": [
127 + {
128 + "allowed": true,
129 + "nodeDpid1": "00:00:ff:ff:ff:ff:ff:01",
130 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:02",
131 + "params": {
132 + "distKms": 1000,
133 + "nodeName1": "SFO-W10",
134 + "nodeName2": "SJC-W10",
135 + "numWaves": 80,
136 + "port1": 10,
137 + "port2": 10
138 + },
139 + "type": "wdmLink"
140 + },
141 +
142 + {
143 + "allowed": true,
144 + "nodeDpid1": "00:00:ff:ff:ff:ff:ff:02",
145 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:03",
146 + "params": {
147 + "distKms": 1000,
148 + "nodeName1": "SJC-W10",
149 + "nodeName2": "LAX-W10",
150 + "numWaves": 80,
151 + "port1": 20,
152 + "port2": 10
153 + },
154 + "type": "wdmLink"
155 + },
156 +
157 + {
158 + "allowed": true,
159 + "nodeDpid1": "00:00:ff:ff:ff:ff:ff:03",
160 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:04",
161 + "params": {
162 + "distKms": 1000,
163 + "nodeName1": "LAX-W10",
164 + "nodeName2": "SDG-W10",
165 + "numWaves": 80,
166 + "port1": 30,
167 + "port2": 10
168 + },
169 + "type": "wdmLink"
170 + },
171 +
172 + {
173 + "allowed": true,
174 + "nodeDpid1": "00:00:ff:ff:ff:ff:ff:02",
175 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:05",
176 + "params": {
177 + "distKms": 4000,
178 + "nodeName1": "SJC-W10",
179 + "nodeName2": "MSP-M10",
180 + "numWaves": 80,
181 + "port1": 20,
182 + "port2": 10
183 + },
184 + "type": "wdmLink"
185 + },
186 +
187 + {
188 +
189 + "allowed": true,
190 + "nodeDpid1": "00:00:ff:ff:ff:ff:ff:03",
191 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:06",
192 + "params": {
193 + "distKms": 5000,
194 + "nodeName1": "LAX-W10",
195 + "nodeName2": "DFW-M10",
196 + "numWaves": 80,
197 + "port1": 20,
198 + "port2": 10
199 + },
200 + "type": "wdmLink"
201 + },
202 +
203 + {
204 + "allowed": true,
205 + "nodeDpid1": "00:00:ff:ff:ff:ff:ff:05",
206 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:06",
207 + "params": {
208 + "distKms": 3000,
209 + "nodeName1": "MSP-M10",
210 + "nodeName2": "DFW-M10",
211 + "numWaves": 80,
212 + "port1": 30,
213 + "port2": 20
214 + },
215 + "type": "wdmLink"
216 + },
217 +
218 + {
219 + "allowed": true,
220 + "nodeDpid1": "00:00:ff:ff:ff:ff:ff:05",
221 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:07",
222 + "params": {
223 + "distKms": 3000,
224 + "nodeName1": "MSP-M10",
225 + "nodeName2": "CHG-N10",
226 + "numWaves": 80,
227 + "port1": 20,
228 + "port2": 21
229 + },
230 + "type": "wdmLink"
231 + },
232 +
233 + {
234 +
235 + "allowed": true,
236 + "nodeDpid1": "00:00:ff:ff:ff:ff:ff:06",
237 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:08",
238 + "params": {
239 + "distKms": 4000,
240 + "nodeName1": "DFW-M10",
241 + "nodeName2": "IAD-M10",
242 + "numWaves": 80,
243 + "port1": 30,
244 + "port2": 10
245 + },
246 + "type": "wdmLink"
247 + },
248 +
249 + {
250 +
251 + "allowed": true,
252 + "nodeDpid1": "00:00:ff:ff:ff:ff:ff:07",
253 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:08",
254 + "params": {
255 + "distKms": 4000,
256 + "nodeName1": "CHG-M10",
257 + "nodeName2": "IAD-M10",
258 + "numWaves": 80,
259 + "port1": 30,
260 + "port2": 20
261 + },
262 + "type": "wdmLink"
263 + },
264 +
265 + {
266 + "allowed": true,
267 + "nodeDpid1": "00:00:ff:ff:ff:ff:ff:07",
268 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:09",
269 + "params": {
270 + "distKms": 5000,
271 + "nodeName1": "CHG-M10",
272 + "nodeName2": "JFK-E10",
273 + "numWaves": 80,
274 + "port1": 20,
275 + "port2": 10
276 + },
277 + "type": "wdmLink"
278 + },
279 +
280 + {
281 + "allowed": true,
282 + "nodeDpid1": "00:00:ff:ff:ff:ff:ff:08",
283 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:0A",
284 + "params": {
285 + "distKms": 3000,
286 + "nodeName1": "IAD-M10",
287 + "nodeName2": "ATL-S10",
288 + "numWaves": 80,
289 + "port1": 30,
290 + "port2": 10
291 + },
292 + "type": "wdmLink"
293 + },
294 +
295 + {
296 +
297 + "allowed": true,
298 + "nodeDpid1": "00:00:ff:ff:ff:ff:ff:09",
299 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:0A",
300 + "params": {
301 + "distKms": 4000,
302 + "nodeName1": "JFK-E10",
303 + "nodeName2": "ATL-S10",
304 + "numWaves": 80,
305 + "port1": 20,
306 + "port2": 20
307 + },
308 + "type": "wdmLink"
309 + },
310 +
311 +
312 + {
313 + "allowed": true,
314 + "nodeDpid1": "00:00:ff:ff:ff:ff:00:01",
315 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:01",
316 + "params": {
317 + "nodeName1": "SFO-R10",
318 + "nodeName2": "SFO-W10",
319 + "port1": 10,
320 + "port2": 1
321 + },
322 + "type": "pktOptLink"
323 + },
324 +
325 + {
326 + "allowed": true,
327 + "nodeDpid1": "00:00:ff:ff:ff:ff:00:03",
328 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:03",
329 + "params": {
330 + "nodeName1": "LAX-R10",
331 + "nodeName2": "LAX-W10",
332 + "port1": 10,
333 + "port2": 1
334 + },
335 + "type": "pktOptLink"
336 + },
337 +
338 + {
339 + "allowed": true,
340 + "nodeDpid1": "00:00:ff:ff:ff:ff:00:04",
341 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:04",
342 + "params": {
343 + "nodeName1": "SDG-R10",
344 + "nodeName2": "SDG-W10",
345 + "port1": 10,
346 + "port2": 1
347 + },
348 + "type": "pktOptLink"
349 + },
350 +
351 + {
352 + "allowed": true,
353 + "nodeDpid1": "00:00:ff:ff:ff:ff:00:07",
354 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:07",
355 + "params": {
356 + "nodeName1": "CHG-R10",
357 + "nodeName2": "CHG-W10",
358 + "port1": 10,
359 + "port2": 1
360 + },
361 + "type": "pktOptLink"
362 + },
363 +
364 + {
365 + "allowed": true,
366 + "nodeDpid1": "00:00:ff:ff:ff:ff:00:09",
367 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:09",
368 + "params": {
369 + "nodeName1": "JFK-R10",
370 + "nodeName2": "JFK-W10",
371 + "port1": 10,
372 + "port2": 1
373 + },
374 + "type": "pktOptLink"
375 + },
376 +
377 + {
378 + "allowed": true,
379 + "nodeDpid1": "00:00:ff:ff:ff:ff:00:0A",
380 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:0A",
381 + "params": {
382 + "nodeName1": "ATL-R10",
383 + "nodeName2": "ATL-W10",
384 + "port1": 10,
385 + "port2": 1
386 + },
387 + "type": "pktOptLink"
388 + },
389 +
390 + ]
391 +}
1 +{
2 + "opticalSwitches": [
3 + {
4 + "allowed": true,
5 + "latitude": 37.6,
6 + "longitude": 122.3,
7 + "name": "ROADM1",
8 + "nodeDpid": "00:00:ff:ff:ff:ff:ff:01",
9 + "params": {
10 + "numRegen": 0
11 + },
12 + "type": "Roadm"
13 + },
14 +
15 + {
16 + "allowed": true,
17 + "latitude": 37.3,
18 + "longitude": 121.9,
19 + "name": "ROADM2",
20 + "nodeDpid": "00:00:ff:ff:ff:ff:ff:02",
21 + "params": {
22 + "numRegen": 0
23 + },
24 + "type": "Roadm"
25 + },
26 +
27 + {
28 + "allowed": true,
29 + "latitude": 33.9,
30 + "longitude": 118.4,
31 + "name": "ROADM3",
32 + "nodeDpid": "00:00:ff:ff:ff:ff:ff:03",
33 + "params": {
34 + "numRegen": 2
35 + },
36 + "type": "Roadm"
37 + }
38 + ],
39 +
40 + "opticalLinks": [
41 + {
42 + "allowed": true,
43 + "nodeDpid1": "00:00:ff:ff:ff:ff:ff:01",
44 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:03",
45 + "params": {
46 + "distKms": 1000,
47 + "nodeName1": "ROADM1",
48 + "nodeName2": "ROADM3",
49 + "numWaves": 80,
50 + "port1": 10,
51 + "port2": 30
52 + },
53 + "type": "wdmLink"
54 + },
55 +
56 + {
57 + "allowed": true,
58 + "nodeDpid1": "00:00:ff:ff:ff:ff:ff:03",
59 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:02",
60 + "params": {
61 + "distKms": 2000,
62 + "nodeName1": "ROADM3",
63 + "nodeName2": "ROADM2",
64 + "numWaves": 80,
65 + "port1": 31,
66 + "port2": 20
67 + },
68 + "type": "wdmLink"
69 + },
70 +
71 +
72 + {
73 + "allowed": true,
74 + "nodeDpid1": "00:00:ff:ff:ff:ff:00:01",
75 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:01",
76 + "params": {
77 + "nodeName1": "ROUTER1",
78 + "nodeName2": "ROADM1",
79 + "bandWidth": 100000,
80 + "port1": 10,
81 + "port2": 11
82 + },
83 + "type": "pktOptLink"
84 + },
85 +
86 + {
87 + "allowed": true,
88 + "nodeDpid1": "00:00:ff:ff:ff:ff:00:02",
89 + "nodeDpid2": "00:00:ff:ff:ff:ff:ff:02",
90 + "params": {
91 + "nodeName1": "ROUTER2",
92 + "nodeName2": "ROADM2",
93 + "bandWidth": 100000,
94 + "port1": 10,
95 + "port2": 21
96 + },
97 + "type": "pktOptLink"
98 + }
99 +
100 + ]
101 +}
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
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>
29 + <module>optical</module>
28 </modules> 30 </modules>
29 31
30 <properties> 32 <properties>
......
...@@ -42,6 +42,30 @@ ...@@ -42,6 +42,30 @@
42 <artifactId>onlab-thirdparty</artifactId> 42 <artifactId>onlab-thirdparty</artifactId>
43 </dependency> 43 </dependency>
44 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>
45 </dependencies> 69 </dependencies>
46 70
47 </project> 71 </project>
......
...@@ -25,10 +25,10 @@ import org.slf4j.LoggerFactory; ...@@ -25,10 +25,10 @@ import org.slf4j.LoggerFactory;
25 /** 25 /**
26 * Manages the connectivity requirements between peers. 26 * Manages the connectivity requirements between peers.
27 */ 27 */
28 -public class PeerConnectivity { 28 +public class PeerConnectivityManager {
29 29
30 private static final Logger log = LoggerFactory.getLogger( 30 private static final Logger log = LoggerFactory.getLogger(
31 - PeerConnectivity.class); 31 + PeerConnectivityManager.class);
32 32
33 // TODO these shouldn't be defined here 33 // TODO these shouldn't be defined here
34 private static final short BGP_PORT = 179; 34 private static final short BGP_PORT = 179;
...@@ -41,7 +41,7 @@ public class PeerConnectivity { ...@@ -41,7 +41,7 @@ public class PeerConnectivity {
41 // TODO this sucks. 41 // TODO this sucks.
42 private int intentId = 0; 42 private int intentId = 0;
43 43
44 - public PeerConnectivity(SdnIpConfigService configInfoService, 44 + public PeerConnectivityManager(SdnIpConfigService configInfoService,
45 InterfaceService interfaceService, IntentService intentService) { 45 InterfaceService interfaceService, IntentService intentService) {
46 this.configInfoService = configInfoService; 46 this.configInfoService = configInfoService;
47 this.interfaceService = interfaceService; 47 this.interfaceService = interfaceService;
......
...@@ -62,10 +62,8 @@ public class Router implements RouteListener { ...@@ -62,10 +62,8 @@ public class Router implements RouteListener {
62 62
63 private static final Logger log = LoggerFactory.getLogger(Router.class); 63 private static final Logger log = LoggerFactory.getLogger(Router.class);
64 64
65 - // Store all route updates in a InvertedRadixTree. 65 + // Store all route updates in a radix tree.
66 - // The key in this Tree is the binary sting of prefix of route. 66 + // The key in this tree is the binary string of prefix of the route.
67 - // The Ip4Address is the next hop address of route, and is also the value
68 - // of each entry.
69 private InvertedRadixTree<RouteEntry> bgpRoutes; 67 private InvertedRadixTree<RouteEntry> bgpRoutes;
70 68
71 // Stores all incoming route updates in a queue. 69 // Stores all incoming route updates in a queue.
...@@ -102,7 +100,7 @@ public class Router implements RouteListener { ...@@ -102,7 +100,7 @@ public class Router implements RouteListener {
102 * Class constructor. 100 * Class constructor.
103 * 101 *
104 * @param intentService the intent service 102 * @param intentService the intent service
105 - * @param proxyArp the proxy ARP service 103 + * @param hostService the host service
106 * @param configInfoService the configuration service 104 * @param configInfoService the configuration service
107 * @param interfaceService the interface service 105 * @param interfaceService the interface service
108 */ 106 */
...@@ -135,6 +133,10 @@ public class Router implements RouteListener { ...@@ -135,6 +133,10 @@ public class Router implements RouteListener {
135 */ 133 */
136 public void start() { 134 public void start() {
137 135
136 + // TODO hack to enable SDN-IP now for testing
137 + isElectedLeader = true;
138 + isActivatedLeader = true;
139 +
138 bgpUpdatesExecutor.execute(new Runnable() { 140 bgpUpdatesExecutor.execute(new Runnable() {
139 @Override 141 @Override
140 public void run() { 142 public void run() {
...@@ -441,8 +443,8 @@ public class Router implements RouteListener { ...@@ -441,8 +443,8 @@ public class Router implements RouteListener {
441 /** 443 /**
442 * Processes adding a route entry. 444 * Processes adding a route entry.
443 * <p/> 445 * <p/>
444 - * Put new route entry into InvertedRadixTree. If there was an existing 446 + * Put new route entry into the radix tree. If there was an existing
445 - * nexthop for this prefix, but the next hop was different, then execute 447 + * next hop for this prefix, but the next hop was different, then execute
446 * deleting old route entry. If the next hop is the SDN domain, we do not 448 * deleting old route entry. If the next hop is the SDN domain, we do not
447 * handle it at the moment. Otherwise, execute adding a route. 449 * handle it at the moment. Otherwise, execute adding a route.
448 * 450 *
...@@ -623,8 +625,8 @@ public class Router implements RouteListener { ...@@ -623,8 +625,8 @@ public class Router implements RouteListener {
623 /** 625 /**
624 * Executes deleting a route entry. 626 * Executes deleting a route entry.
625 * <p/> 627 * <p/>
626 - * Removes prefix from InvertedRadixTree, if success, then try to delete 628 + * Removes prefix from radix tree, and if successful, then try to delete
627 - * the relative intent. 629 + * the related intent.
628 * 630 *
629 * @param routeEntry the route entry to delete 631 * @param routeEntry the route entry to delete
630 */ 632 */
...@@ -690,9 +692,9 @@ public class Router implements RouteListener { ...@@ -690,9 +692,9 @@ public class Router implements RouteListener {
690 public void arpResponse(IpAddress ipAddress, MacAddress macAddress) { 692 public void arpResponse(IpAddress ipAddress, MacAddress macAddress) {
691 log.debug("Received ARP response: {} => {}", ipAddress, macAddress); 693 log.debug("Received ARP response: {} => {}", ipAddress, macAddress);
692 694
693 - // We synchronize on this to prevent changes to the InvertedRadixTree 695 + // We synchronize on this to prevent changes to the radix tree
694 - // while we're pushing intent. If the InvertedRadixTree changes, the 696 + // while we're pushing intents. If the tree changes, the
695 - // InvertedRadixTree and intent could get out of sync. 697 + // tree and intents could get out of sync.
696 synchronized (this) { 698 synchronized (this) {
697 699
698 Set<RouteEntry> routesToPush = 700 Set<RouteEntry> routesToPush =
...@@ -709,14 +711,14 @@ public class Router implements RouteListener { ...@@ -709,14 +711,14 @@ public class Router implements RouteListener {
709 log.debug("Pushing prefix {} next hop {}", 711 log.debug("Pushing prefix {} next hop {}",
710 routeEntry.prefix(), routeEntry.nextHop()); 712 routeEntry.prefix(), routeEntry.nextHop());
711 // We only push prefix flows if the prefix is still in the 713 // We only push prefix flows if the prefix is still in the
712 - // InvertedRadixTree and the next hop is the same as our 714 + // radix tree and the next hop is the same as our
713 // update. 715 // update.
714 // The prefix could have been removed while we were waiting 716 // The prefix could have been removed while we were waiting
715 // for the ARP, or the next hop could have changed. 717 // for the ARP, or the next hop could have changed.
716 addRouteIntentToNextHop(prefix, ipAddress, macAddress); 718 addRouteIntentToNextHop(prefix, ipAddress, macAddress);
717 } else { 719 } else {
718 log.debug("Received ARP response, but {}/{} is no longer in" 720 log.debug("Received ARP response, but {}/{} is no longer in"
719 - + " InvertedRadixTree", routeEntry.prefix(), 721 + + " the radix tree", routeEntry.prefix(),
720 routeEntry.nextHop()); 722 routeEntry.nextHop());
721 } 723 }
722 } 724 }
......
...@@ -2,14 +2,18 @@ package org.onlab.onos.sdnip; ...@@ -2,14 +2,18 @@ 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;
12 import org.onlab.onos.sdnip.RouteUpdate.Type; 15 import org.onlab.onos.sdnip.RouteUpdate.Type;
16 +import org.onlab.onos.sdnip.bgp.BgpRouteEntry;
13 import org.onlab.onos.sdnip.bgp.BgpSessionManager; 17 import org.onlab.onos.sdnip.bgp.BgpSessionManager;
14 import org.onlab.onos.sdnip.config.SdnIpConfigReader; 18 import org.onlab.onos.sdnip.config.SdnIpConfigReader;
15 import org.onlab.packet.IpAddress; 19 import org.onlab.packet.IpAddress;
...@@ -17,10 +21,11 @@ import org.onlab.packet.IpPrefix; ...@@ -17,10 +21,11 @@ import org.onlab.packet.IpPrefix;
17 import org.slf4j.Logger; 21 import org.slf4j.Logger;
18 22
19 /** 23 /**
20 - * Placeholder SDN-IP component. 24 + * Component for the SDN-IP peering application.
21 */ 25 */
22 @Component(immediate = true) 26 @Component(immediate = true)
23 -public class SdnIp { 27 +@Service
28 +public class SdnIp implements SdnIpService {
24 29
25 private final Logger log = getLogger(getClass()); 30 private final Logger log = getLogger(getClass());
26 31
...@@ -31,7 +36,7 @@ public class SdnIp { ...@@ -31,7 +36,7 @@ public class SdnIp {
31 protected HostService hostService; 36 protected HostService hostService;
32 37
33 private SdnIpConfigReader config; 38 private SdnIpConfigReader config;
34 - private PeerConnectivity peerConnectivity; 39 + private PeerConnectivityManager peerConnectivity;
35 private Router router; 40 private Router router;
36 private BgpSessionManager bgpSessionManager; 41 private BgpSessionManager bgpSessionManager;
37 42
...@@ -44,7 +49,7 @@ public class SdnIp { ...@@ -44,7 +49,7 @@ public class SdnIp {
44 49
45 InterfaceService interfaceService = new HostServiceBasedInterfaceService(hostService); 50 InterfaceService interfaceService = new HostServiceBasedInterfaceService(hostService);
46 51
47 - peerConnectivity = new PeerConnectivity(config, interfaceService, intentService); 52 + peerConnectivity = new PeerConnectivityManager(config, interfaceService, intentService);
48 peerConnectivity.start(); 53 peerConnectivity.start();
49 54
50 router = new Router(intentService, hostService, config, interfaceService); 55 router = new Router(intentService, hostService, config, interfaceService);
...@@ -64,4 +69,18 @@ public class SdnIp { ...@@ -64,4 +69,18 @@ public class SdnIp {
64 protected void deactivate() { 69 protected void deactivate() {
65 log.info("Stopped"); 70 log.info("Stopped");
66 } 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 + }
82 +
83 + static String dpidToUri(String dpid) {
84 + return "of:" + dpid.replace(":", "");
85 + }
67 } 86 }
......
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 +}
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.easymock.EasyMock.createMock;
4 +import static org.easymock.EasyMock.expect;
5 +import static org.easymock.EasyMock.replay;
6 +import static org.easymock.EasyMock.reportMatcher;
7 +import static org.easymock.EasyMock.reset;
8 +import static org.easymock.EasyMock.verify;
9 +
10 +import java.util.ArrayList;
11 +import java.util.Collections;
12 +import java.util.HashMap;
13 +import java.util.LinkedList;
14 +import java.util.List;
15 +import java.util.Map;
16 +
17 +import org.easymock.IArgumentMatcher;
18 +import org.junit.Before;
19 +import org.junit.Ignore;
20 +import org.junit.Test;
21 +import org.onlab.onos.net.ConnectPoint;
22 +import org.onlab.onos.net.DeviceId;
23 +import org.onlab.onos.net.PortNumber;
24 +import org.onlab.onos.net.flow.DefaultTrafficSelector;
25 +import org.onlab.onos.net.flow.DefaultTrafficTreatment;
26 +import org.onlab.onos.net.flow.TrafficSelector;
27 +import org.onlab.onos.net.flow.TrafficTreatment;
28 +import org.onlab.onos.net.intent.IntentId;
29 +import org.onlab.onos.net.intent.IntentService;
30 +import org.onlab.onos.net.intent.PointToPointIntent;
31 +import org.onlab.onos.sdnip.bgp.BgpConstants;
32 +import org.onlab.onos.sdnip.config.BgpPeer;
33 +import org.onlab.onos.sdnip.config.BgpSpeaker;
34 +import org.onlab.onos.sdnip.config.Interface;
35 +import org.onlab.onos.sdnip.config.InterfaceAddress;
36 +import org.onlab.onos.sdnip.config.SdnIpConfigService;
37 +import org.onlab.packet.Ethernet;
38 +import org.onlab.packet.IPv4;
39 +import org.onlab.packet.IpAddress;
40 +import org.onlab.packet.IpPrefix;
41 +import org.onlab.packet.MacAddress;
42 +
43 +import com.google.common.collect.Sets;
44 +
45 +/**
46 + * Unit tests for PeerConnectivityManager interface.
47 + */
48 +public class PeerConnectivityManagerTest {
49 +
50 + private PeerConnectivityManager peerConnectivityManager;
51 + private IntentService intentService;
52 + private SdnIpConfigService configInfoService;
53 + private InterfaceService interfaceService;
54 +
55 + private Map<String, BgpSpeaker> bgpSpeakers;
56 + private Map<String, Interface> interfaces;
57 + private Map<IpAddress, BgpPeer> peers;
58 +
59 + private Map<String, BgpSpeaker> configuredBgpSpeakers;
60 + private Map<String, Interface> configuredInterfaces;
61 + private Map<IpAddress, BgpPeer> configuredPeers;
62 + private List<PointToPointIntent> intentList;
63 +
64 + private final String dpid1 = "00:00:00:00:00:00:00:01";
65 + private final String dpid2 = "00:00:00:00:00:00:00:02";
66 +
67 + private final DeviceId deviceId1 =
68 + DeviceId.deviceId(SdnIp.dpidToUri(dpid1));
69 + private final DeviceId deviceId2 =
70 + DeviceId.deviceId(SdnIp.dpidToUri(dpid2));
71 +
72 + // Interfaces connected to BGP speakers
73 + private final ConnectPoint s1Eth100 =
74 + new ConnectPoint(deviceId1, PortNumber.portNumber(100));
75 + private final ConnectPoint s2Eth100 =
76 + new ConnectPoint(deviceId2, PortNumber.portNumber(100));
77 +
78 + // Interfaces connected to BGP peers
79 + private final ConnectPoint s1Eth1 =
80 + new ConnectPoint(deviceId1, PortNumber.portNumber(1));
81 + private final ConnectPoint s2Eth1 =
82 + new ConnectPoint(deviceId2, PortNumber.portNumber(1));
83 +
84 + // We don't compare the intent ID so all expected intents can use the same ID
85 + private final IntentId testIntentId = new IntentId(0);
86 +
87 + private final TrafficTreatment noTreatment =
88 + DefaultTrafficTreatment.builder().build();
89 +
90 + @Before
91 + public void setUp() throws Exception {
92 + bgpSpeakers = Collections.unmodifiableMap(setUpBgpSpeakers());
93 + interfaces = Collections.unmodifiableMap(setUpInterfaces());
94 + peers = Collections.unmodifiableMap(setUpPeers());
95 +
96 + initPeerConnectivity();
97 + intentList = setUpIntentList();
98 + }
99 +
100 + /**
101 + * Sets up BGP speakers.
102 + *
103 + * @return configured BGP speakers as a map from speaker name to speaker
104 + */
105 + private Map<String, BgpSpeaker> setUpBgpSpeakers() {
106 +
107 + configuredBgpSpeakers = new HashMap<>();
108 +
109 + BgpSpeaker bgpSpeaker1 = new BgpSpeaker(
110 + "bgpSpeaker1",
111 + "00:00:00:00:00:00:00:01", 100,
112 + "00:00:00:00:00:01");
113 + List<InterfaceAddress> interfaceAddresses1 =
114 + new LinkedList<InterfaceAddress>();
115 + interfaceAddresses1.add(new InterfaceAddress(dpid1, 1, "192.168.10.101"));
116 + interfaceAddresses1.add(new InterfaceAddress(dpid2, 1, "192.168.20.101"));
117 + bgpSpeaker1.setInterfaceAddresses(interfaceAddresses1);
118 + configuredBgpSpeakers.put(bgpSpeaker1.name(), bgpSpeaker1);
119 +
120 + // BGP speaker2 is attached to the same switch port with speaker1
121 + BgpSpeaker bgpSpeaker2 = new BgpSpeaker(
122 + "bgpSpeaker2",
123 + "00:00:00:00:00:00:00:01", 100,
124 + "00:00:00:00:00:02");
125 + List<InterfaceAddress> interfaceAddresses2 =
126 + new LinkedList<InterfaceAddress>();
127 + interfaceAddresses2.add(new InterfaceAddress(dpid1, 1, "192.168.10.102"));
128 + interfaceAddresses2.add(new InterfaceAddress(dpid2, 1, "192.168.20.102"));
129 + bgpSpeaker2.setInterfaceAddresses(interfaceAddresses2);
130 + configuredBgpSpeakers.put(bgpSpeaker2.name(), bgpSpeaker2);
131 +
132 + BgpSpeaker bgpSpeaker3 = new BgpSpeaker(
133 + "bgpSpeaker3",
134 + "00:00:00:00:00:00:00:02", 100,
135 + "00:00:00:00:00:03");
136 + List<InterfaceAddress> interfaceAddresses3 =
137 + new LinkedList<InterfaceAddress>();
138 + interfaceAddresses3.add(new InterfaceAddress(dpid1, 1, "192.168.10.103"));
139 + interfaceAddresses3.add(new InterfaceAddress(dpid2, 1, "192.168.20.103"));
140 + bgpSpeaker3.setInterfaceAddresses(interfaceAddresses3);
141 + configuredBgpSpeakers.put(bgpSpeaker3.name(), bgpSpeaker3);
142 +
143 + return configuredBgpSpeakers;
144 + }
145 +
146 + /**
147 + * Sets up logical interfaces, which emulate the configured interfaces
148 + * in SDN-IP application.
149 + *
150 + * @return configured interfaces as a MAP from Interface name to Interface
151 + */
152 + private Map<String, Interface> setUpInterfaces() {
153 +
154 + configuredInterfaces = new HashMap<>();
155 +
156 + String interfaceSw1Eth1 = "s1-eth1";
157 + Interface intfsw1eth1 = new Interface(s1Eth1,
158 + Collections.singleton(IpPrefix.valueOf("192.168.10.0/24")),
159 + MacAddress.valueOf("00:00:00:00:00:01"));
160 +
161 + configuredInterfaces.put(interfaceSw1Eth1, intfsw1eth1);
162 + String interfaceSw2Eth1 = "s2-eth1";
163 + Interface intfsw2eth1 = new Interface(s2Eth1,
164 + Collections.singleton(IpPrefix.valueOf("192.168.20.0/24")),
165 + MacAddress.valueOf("00:00:00:00:00:02"));
166 + configuredInterfaces.put(interfaceSw2Eth1, intfsw2eth1);
167 +
168 + interfaceService = createMock(InterfaceService.class);
169 +
170 + expect(interfaceService.getInterface(s1Eth1))
171 + .andReturn(intfsw1eth1).anyTimes();
172 + expect(interfaceService.getInterface(s2Eth1))
173 + .andReturn(intfsw2eth1).anyTimes();
174 +
175 + // Non-existent interface used during one of the tests
176 + expect(interfaceService.getInterface(new ConnectPoint(
177 + DeviceId.deviceId(SdnIp.dpidToUri("00:00:00:00:00:00:01:00")),
178 + PortNumber.portNumber(1))))
179 + .andReturn(null).anyTimes();
180 +
181 + expect(interfaceService.getInterfaces()).andReturn(
182 + Sets.newHashSet(configuredInterfaces.values())).anyTimes();
183 + replay(interfaceService);
184 +
185 + return configuredInterfaces;
186 + }
187 +
188 + /**
189 + * Sets up BGP daemon peers.
190 + *
191 + * @return configured BGP peers as a MAP from peer IP address to BgpPeer
192 + */
193 + private Map<IpAddress, BgpPeer> setUpPeers() {
194 +
195 + configuredPeers = new HashMap<>();
196 +
197 + String peerSw1Eth1 = "192.168.10.1";
198 + configuredPeers.put(IpAddress.valueOf(peerSw1Eth1),
199 + new BgpPeer(dpid1, 1, peerSw1Eth1));
200 +
201 + // Two BGP peers are connected to switch 2 port 1.
202 + String peer1Sw2Eth1 = "192.168.20.1";
203 + configuredPeers.put(IpAddress.valueOf(peer1Sw2Eth1),
204 + new BgpPeer(dpid2, 1, peer1Sw2Eth1));
205 +
206 + String peer2Sw2Eth1 = "192.168.20.2";
207 + configuredPeers.put(IpAddress.valueOf(peer2Sw2Eth1),
208 + new BgpPeer(dpid2, 1, peer2Sw2Eth1));
209 +
210 + return configuredPeers;
211 + }
212 +
213 + /**
214 + * Sets up expected point to point intent list.
215 + *
216 + * @return point to point intent list
217 + */
218 + private List<PointToPointIntent> setUpIntentList() {
219 +
220 + intentList = new ArrayList<PointToPointIntent>();
221 +
222 + setUpBgpIntents();
223 + setUpIcmpIntents();
224 +
225 + return intentList;
226 +
227 + }
228 +
229 + /**
230 + * Constructs a BGP intent and put it into the intentList.
231 + * <p/>
232 + * The purpose of this method is too simplify the setUpBgpIntents() method,
233 + * and to make the setUpBgpIntents() easy to read.
234 + *
235 + * @param srcPrefix source IP prefix to match
236 + * @param dstPrefix destination IP prefix to match
237 + * @param srcTcpPort source TCP port to match
238 + * @param dstTcpPort destination TCP port to match
239 + * @param srcConnectPoint source connect point for PointToPointIntent
240 + * @param dstConnectPoint destination connect point for PointToPointIntent
241 + */
242 + private void bgpPathintentConstructor(String srcPrefix, String dstPrefix,
243 + Short srcTcpPort, Short dstTcpPort,
244 + ConnectPoint srcConnectPoint, ConnectPoint dstConnectPoint) {
245 +
246 + TrafficSelector.Builder builder = DefaultTrafficSelector.builder()
247 + .matchEthType(Ethernet.TYPE_IPV4)
248 + .matchIPProtocol(IPv4.PROTOCOL_TCP)
249 + .matchIPSrc(IpPrefix.valueOf(srcPrefix))
250 + .matchIPDst(IpPrefix.valueOf(dstPrefix));
251 +
252 + if (srcTcpPort != null) {
253 + builder.matchTcpSrc(srcTcpPort);
254 + }
255 + if (dstTcpPort != null) {
256 + builder.matchTcpDst(dstTcpPort);
257 + }
258 +
259 + PointToPointIntent intent = new PointToPointIntent(
260 + testIntentId, builder.build(), noTreatment,
261 + srcConnectPoint, dstConnectPoint);
262 +
263 + intentList.add(intent);
264 + }
265 +
266 + /**
267 + * Sets up intents for BGP paths.
268 + */
269 + private void setUpBgpIntents() {
270 +
271 + Short bgpPort = Short.valueOf((short) BgpConstants.BGP_PORT);
272 +
273 + // Start to build intents between BGP speaker1 and BGP peer1
274 + bgpPathintentConstructor(
275 + "192.168.10.101/32", "192.168.10.1/32", null, bgpPort,
276 + s1Eth100, s1Eth1);
277 + bgpPathintentConstructor(
278 + "192.168.10.101/32", "192.168.10.1/32", bgpPort, null,
279 + s1Eth100, s1Eth1);
280 +
281 + bgpPathintentConstructor(
282 + "192.168.10.1/32", "192.168.10.101/32", null, bgpPort,
283 + s1Eth1, s1Eth100);
284 + bgpPathintentConstructor(
285 + "192.168.10.1/32", "192.168.10.101/32", bgpPort, null,
286 + s1Eth1, s1Eth100);
287 +
288 + // Start to build intents between BGP speaker1 and BGP peer2
289 + bgpPathintentConstructor(
290 + "192.168.20.101/32", "192.168.20.1/32", null, bgpPort,
291 + s1Eth100, s2Eth1);
292 + bgpPathintentConstructor(
293 + "192.168.20.101/32", "192.168.20.1/32", bgpPort, null,
294 + s1Eth100, s2Eth1);
295 +
296 + bgpPathintentConstructor(
297 + "192.168.20.1/32", "192.168.20.101/32", null, bgpPort,
298 + s2Eth1, s1Eth100);
299 + bgpPathintentConstructor(
300 + "192.168.20.1/32", "192.168.20.101/32", bgpPort, null,
301 + s2Eth1, s1Eth100);
302 +
303 + // Start to build intents between BGP speaker1 and BGP peer3
304 + bgpPathintentConstructor(
305 + "192.168.20.101/32", "192.168.20.2/32", null, bgpPort,
306 + s1Eth100, s2Eth1);
307 + bgpPathintentConstructor(
308 + "192.168.20.101/32", "192.168.20.2/32", bgpPort, null,
309 + s1Eth100, s2Eth1);
310 +
311 + bgpPathintentConstructor(
312 + "192.168.20.2/32", "192.168.20.101/32", null, bgpPort,
313 + s2Eth1, s1Eth100);
314 + bgpPathintentConstructor(
315 + "192.168.20.2/32", "192.168.20.101/32", bgpPort, null,
316 + s2Eth1, s1Eth100);
317 +
318 + //
319 + // Start to build intents between BGP speaker2 and BGP peer1
320 + bgpPathintentConstructor(
321 + "192.168.10.102/32", "192.168.10.1/32", null, bgpPort,
322 + s1Eth100, s1Eth1);
323 + bgpPathintentConstructor(
324 + "192.168.10.102/32", "192.168.10.1/32", bgpPort, null,
325 + s1Eth100, s1Eth1);
326 +
327 + bgpPathintentConstructor(
328 + "192.168.10.1/32", "192.168.10.102/32", null, bgpPort,
329 + s1Eth1, s1Eth100);
330 + bgpPathintentConstructor(
331 + "192.168.10.1/32", "192.168.10.102/32", bgpPort, null,
332 + s1Eth1, s1Eth100);
333 + // Start to build intents between BGP speaker2 and BGP peer2
334 + bgpPathintentConstructor(
335 + "192.168.20.102/32", "192.168.20.1/32", null, bgpPort,
336 + s1Eth100, s2Eth1);
337 + bgpPathintentConstructor(
338 + "192.168.20.102/32", "192.168.20.1/32", bgpPort, null,
339 + s1Eth100, s2Eth1);
340 +
341 + bgpPathintentConstructor(
342 + "192.168.20.1/32", "192.168.20.102/32", null, bgpPort,
343 + s2Eth1, s1Eth100);
344 + bgpPathintentConstructor(
345 + "192.168.20.1/32", "192.168.20.102/32", bgpPort, null,
346 + s2Eth1, s1Eth100);
347 +
348 + // Start to build intents between BGP speaker2 and BGP peer3
349 + bgpPathintentConstructor(
350 + "192.168.20.102/32", "192.168.20.2/32", null, bgpPort,
351 + s1Eth100, s2Eth1);
352 + bgpPathintentConstructor(
353 + "192.168.20.102/32", "192.168.20.2/32", bgpPort, null,
354 + s1Eth100, s2Eth1);
355 +
356 + bgpPathintentConstructor(
357 + "192.168.20.2/32", "192.168.20.102/32", null, bgpPort,
358 + s2Eth1, s1Eth100);
359 + bgpPathintentConstructor(
360 + "192.168.20.2/32", "192.168.20.102/32", bgpPort, null,
361 + s2Eth1, s1Eth100);
362 +
363 + //
364 + // Start to build intents between BGP speaker3 and BGP peer1
365 + bgpPathintentConstructor(
366 + "192.168.10.103/32", "192.168.10.1/32", null, bgpPort,
367 + s2Eth100, s1Eth1);
368 + bgpPathintentConstructor(
369 + "192.168.10.103/32", "192.168.10.1/32", bgpPort, null,
370 + s2Eth100, s1Eth1);
371 +
372 + bgpPathintentConstructor(
373 + "192.168.10.1/32", "192.168.10.103/32", null, bgpPort,
374 + s1Eth1, s2Eth100);
375 + bgpPathintentConstructor(
376 + "192.168.10.1/32", "192.168.10.103/32", bgpPort, null,
377 + s1Eth1, s2Eth100);
378 +
379 + // Start to build intents between BGP speaker3 and BGP peer2
380 + bgpPathintentConstructor(
381 + "192.168.20.103/32", "192.168.20.1/32", null, bgpPort,
382 + s2Eth100, s2Eth1);
383 + bgpPathintentConstructor(
384 + "192.168.20.103/32", "192.168.20.1/32", bgpPort, null,
385 + s2Eth100, s2Eth1);
386 +
387 + bgpPathintentConstructor(
388 + "192.168.20.1/32", "192.168.20.103/32", null, bgpPort,
389 + s2Eth1, s2Eth100);
390 + bgpPathintentConstructor(
391 + "192.168.20.1/32", "192.168.20.103/32", bgpPort, null,
392 + s2Eth1, s2Eth100);
393 +
394 + // Start to build intents between BGP speaker3 and BGP peer3
395 + bgpPathintentConstructor(
396 + "192.168.20.103/32", "192.168.20.2/32", null, bgpPort,
397 + s2Eth100, s2Eth1);
398 + bgpPathintentConstructor(
399 + "192.168.20.103/32", "192.168.20.2/32", bgpPort, null,
400 + s2Eth100, s2Eth1);
401 +
402 + bgpPathintentConstructor(
403 + "192.168.20.2/32", "192.168.20.103/32", null, bgpPort,
404 + s2Eth1, s2Eth100);
405 + bgpPathintentConstructor(
406 + "192.168.20.2/32", "192.168.20.103/32", bgpPort, null,
407 + s2Eth1, s2Eth100);
408 + }
409 +
410 + /**
411 + * Constructs a BGP intent and put it into the intentList.
412 + * <p/>
413 + * The purpose of this method is too simplify the setUpBgpIntents() method,
414 + * and to make the setUpBgpIntents() easy to read.
415 + *
416 + * @param srcPrefix source IP prefix to match
417 + * @param dstPrefix destination IP prefix to match
418 + * @param srcConnectPoint source connect point for PointToPointIntent
419 + * @param dstConnectPoint destination connect point for PointToPointIntent
420 + */
421 + private void icmpPathintentConstructor(String srcPrefix, String dstPrefix,
422 + ConnectPoint srcConnectPoint, ConnectPoint dstConnectPoint) {
423 +
424 + TrafficSelector selector = DefaultTrafficSelector.builder()
425 + .matchEthType(Ethernet.TYPE_IPV4)
426 + .matchIPProtocol(IPv4.PROTOCOL_ICMP)
427 + .matchIPSrc(IpPrefix.valueOf(srcPrefix))
428 + .matchIPDst(IpPrefix.valueOf(dstPrefix))
429 + .build();
430 +
431 + PointToPointIntent intent = new PointToPointIntent(
432 + testIntentId, selector, noTreatment,
433 + srcConnectPoint, dstConnectPoint);
434 +
435 + intentList.add(intent);
436 + }
437 +
438 + /**
439 + * Sets up intents for ICMP paths.
440 + */
441 + private void setUpIcmpIntents() {
442 +
443 + // Start to build intents between BGP speaker1 and BGP peer1
444 + icmpPathintentConstructor(
445 + "192.168.10.101/32", "192.168.10.1/32", s1Eth100, s1Eth1);
446 + icmpPathintentConstructor(
447 + "192.168.10.1/32", "192.168.10.101/32", s1Eth1, s1Eth100);
448 +
449 + // Start to build intents between BGP speaker1 and BGP peer2
450 + icmpPathintentConstructor(
451 + "192.168.20.101/32", "192.168.20.1/32", s1Eth100, s2Eth1);
452 + icmpPathintentConstructor(
453 + "192.168.20.1/32", "192.168.20.101/32", s2Eth1, s1Eth100);
454 +
455 + // Start to build intents between BGP speaker1 and BGP peer3
456 + icmpPathintentConstructor(
457 + "192.168.20.101/32", "192.168.20.2/32", s1Eth100, s2Eth1);
458 + icmpPathintentConstructor(
459 + "192.168.20.2/32", "192.168.20.101/32", s2Eth1, s1Eth100);
460 +
461 + //
462 + // Start to build intents between BGP speaker2 and BGP peer1
463 + icmpPathintentConstructor(
464 + "192.168.10.102/32", "192.168.10.1/32", s1Eth100, s1Eth1);
465 + icmpPathintentConstructor(
466 + "192.168.10.1/32", "192.168.10.102/32", s1Eth1, s1Eth100);
467 +
468 + // Start to build intents between BGP speaker2 and BGP peer2
469 + icmpPathintentConstructor(
470 + "192.168.20.102/32", "192.168.20.1/32", s1Eth100, s2Eth1);
471 + icmpPathintentConstructor(
472 + "192.168.20.1/32", "192.168.20.102/32", s2Eth1, s1Eth100);
473 +
474 + // Start to build intents between BGP speaker2 and BGP peer3
475 + icmpPathintentConstructor(
476 + "192.168.20.102/32", "192.168.20.2/32", s1Eth100, s2Eth1);
477 + icmpPathintentConstructor(
478 + "192.168.20.2/32", "192.168.20.102/32", s2Eth1, s1Eth100);
479 +
480 + //
481 + // Start to build intents between BGP speaker3 and BGP peer1
482 + icmpPathintentConstructor(
483 + "192.168.10.103/32", "192.168.10.1/32", s2Eth100, s1Eth1);
484 + icmpPathintentConstructor(
485 + "192.168.10.1/32", "192.168.10.103/32", s1Eth1, s2Eth100);
486 +
487 + // Start to build intents between BGP speaker3 and BGP peer2
488 + icmpPathintentConstructor(
489 + "192.168.20.103/32", "192.168.20.1/32", s2Eth100, s2Eth1);
490 + icmpPathintentConstructor(
491 + "192.168.20.1/32", "192.168.20.103/32", s2Eth1, s2Eth100);
492 +
493 + // Start to build intents between BGP speaker3 and BGP peer3
494 + icmpPathintentConstructor(
495 + "192.168.20.103/32", "192.168.20.2/32", s2Eth100, s2Eth1);
496 + icmpPathintentConstructor(
497 + "192.168.20.2/32", "192.168.20.103/32", s2Eth1, s2Eth100);
498 +
499 + }
500 +
501 + /**
502 + * Initializes peer connectivity testing environment.
503 + */
504 + private void initPeerConnectivity() {
505 +
506 + configInfoService = createMock(SdnIpConfigService.class);
507 + expect(configInfoService.getBgpPeers()).andReturn(peers).anyTimes();
508 + expect(configInfoService.getBgpSpeakers()).andReturn(bgpSpeakers).anyTimes();
509 + replay(configInfoService);
510 +
511 + intentService = createMock(IntentService.class);
512 + replay(intentService);
513 +
514 + peerConnectivityManager = new PeerConnectivityManager(configInfoService,
515 + interfaceService, intentService);
516 + }
517 +
518 + /*
519 + * EasyMock matcher that matches {@link PointToPointIntent}s but
520 + * ignores the {@link IntentId} when matching.
521 + * <p/>
522 + * The normal intent equals method tests that the intent IDs are equal,
523 + * however in these tests we can't know what the intent IDs will be in
524 + * advance, so we can't set up expected intents with the correct IDs. Thus,
525 + * the solution is to use an EasyMock matcher that verifies that all the
526 + * value properties of the provided intent match the expected values, but
527 + * ignores the intent ID when testing equality.
528 + */
529 + private static final class IdAgnosticPointToPointIntentMatcher implements
530 + IArgumentMatcher {
531 +
532 + private final PointToPointIntent intent;
533 + private String providedIntentString;
534 +
535 + /**
536 + * Constructor taking the expected intent to match against.
537 + *
538 + * @param intent the expected intent
539 + */
540 + public IdAgnosticPointToPointIntentMatcher(PointToPointIntent intent) {
541 + this.intent = intent;
542 + }
543 +
544 + @Override
545 + public void appendTo(StringBuffer strBuffer) {
546 + strBuffer.append("PointToPointIntentMatcher unable to match: "
547 + + providedIntentString);
548 + }
549 +
550 + @Override
551 + public boolean matches(Object object) {
552 + if (!(object instanceof PointToPointIntent)) {
553 + return false;
554 + }
555 +
556 + PointToPointIntent providedIntent = (PointToPointIntent) object;
557 + providedIntentString = providedIntent.toString();
558 +
559 + PointToPointIntent matchIntent =
560 + new PointToPointIntent(providedIntent.id(),
561 + intent.selector(), intent.treatment(),
562 + intent.ingressPoint(), intent.egressPoint());
563 +
564 + return matchIntent.equals(providedIntent);
565 + }
566 + }
567 +
568 + /**
569 + * Matcher method to set an expected intent to match against (ignoring the
570 + * the intent ID).
571 + *
572 + * @param intent the expected intent
573 + * @return something of type PointToPointIntent
574 + */
575 + private static PointToPointIntent eqExceptId(
576 + PointToPointIntent intent) {
577 + reportMatcher(new IdAgnosticPointToPointIntentMatcher(intent));
578 + return null;
579 + }
580 +
581 + /**
582 + * Tests whether peer connectivity manager can set up correct BGP and
583 + * ICMP intents according to specific configuration.
584 + * <p/>
585 + * Two tricky cases included in the configuration are: 2 peers on a same
586 + * switch port, peer on the same switch with BGPd.
587 + */
588 + @Test
589 + public void testConnectionSetup() {
590 +
591 + reset(intentService);
592 +
593 + // Sets up the expected PointToPoint intents.
594 + for (int i = 0; i < intentList.size(); i++) {
595 + intentService.submit(eqExceptId(intentList.get(i)));
596 + }
597 +
598 + replay(intentService);
599 +
600 + // Running the interface to be tested.
601 + peerConnectivityManager.start();
602 +
603 + verify(intentService);
604 +
605 + }
606 +
607 + /**
608 + * Tests a corner case, when there are no interfaces in the configuration.
609 + */
610 + @Test
611 + public void testNullInterfaces() {
612 + reset(interfaceService);
613 + expect(interfaceService.getInterfaces()).andReturn(
614 + Sets.<Interface>newHashSet()).anyTimes();
615 + expect(interfaceService.getInterface(s2Eth1))
616 + .andReturn(null).anyTimes();
617 + expect(interfaceService.getInterface(s1Eth1))
618 + .andReturn(null).anyTimes();
619 + replay(interfaceService);
620 +
621 + reset(configInfoService);
622 + expect(configInfoService.getBgpPeers()).andReturn(peers).anyTimes();
623 + expect(configInfoService.getBgpSpeakers()).andReturn(bgpSpeakers).anyTimes();
624 + replay(configInfoService);
625 +
626 + reset(intentService);
627 + replay(intentService);
628 + peerConnectivityManager.start();
629 + verify(intentService);
630 + }
631 +
632 + /**
633 + * Tests a corner case, when there are no BGP peers in the configuration.
634 + */
635 + @Test
636 + public void testNullBgpPeers() {
637 + reset(interfaceService);
638 + expect(interfaceService.getInterfaces()).andReturn(
639 + Sets.newHashSet(interfaces.values())).anyTimes();
640 + replay(interfaceService);
641 +
642 + reset(configInfoService);
643 + expect(configInfoService.getBgpPeers()).andReturn(
644 + new HashMap<IpAddress, BgpPeer>()).anyTimes();
645 + expect(configInfoService.getBgpSpeakers()).andReturn(
646 + bgpSpeakers).anyTimes();
647 + replay(configInfoService);
648 +
649 + reset(intentService);
650 + replay(intentService);
651 + peerConnectivityManager.start();
652 + verify(intentService);
653 + }
654 +
655 + /**
656 + * Tests a corner case, when there is no BGP speakers in the configuration.
657 + */
658 + @Test
659 + public void testNullBgpSpeakers() {
660 + reset(interfaceService);
661 + expect(interfaceService.getInterfaces()).andReturn(
662 + Sets.newHashSet(interfaces.values())).anyTimes();
663 + replay(interfaceService);
664 +
665 + reset(configInfoService);
666 + expect(configInfoService.getBgpPeers()).andReturn(
667 + peers).anyTimes();
668 + expect(configInfoService.getBgpSpeakers()).andReturn(
669 + null).anyTimes();
670 + replay(configInfoService);
671 +
672 + reset(intentService);
673 + replay(intentService);
674 + peerConnectivityManager.start();
675 + verify(intentService);
676 + }
677 +
678 + /**
679 + * Tests a corner case, when there is no Interface configured for one BGP
680 + * peer.
681 + */
682 + @Test
683 + public void testNoPeerInterface() {
684 + String peerSw100Eth1 = "192.168.200.1";
685 + configuredPeers.put(IpAddress.valueOf(peerSw100Eth1),
686 + new BgpPeer("00:00:00:00:00:00:01:00", 1, peerSw100Eth1));
687 + testConnectionSetup();
688 + }
689 +
690 + /**
691 + * Tests a corner case, when there is no Interface configured for one BGP
692 + * speaker.
693 + * TODO: we should add a configuration correctness checking module/method
694 + * before testing this corner case.
695 + */
696 + @Ignore
697 + @Test
698 + public void testNoSpeakerInterface() {
699 + BgpSpeaker bgpSpeaker100 = new BgpSpeaker(
700 + "bgpSpeaker100",
701 + "00:00:00:00:00:00:01:00", 100,
702 + "00:00:00:00:01:00");
703 + List<InterfaceAddress> interfaceAddresses100 =
704 + new LinkedList<InterfaceAddress>();
705 + interfaceAddresses100.add(new InterfaceAddress(dpid1, 1, "192.168.10.201"));
706 + interfaceAddresses100.add(new InterfaceAddress(dpid2, 1, "192.168.20.201"));
707 + bgpSpeaker100.setInterfaceAddresses(interfaceAddresses100);
708 + configuredBgpSpeakers.put(bgpSpeaker100.name(), bgpSpeaker100);
709 + testConnectionSetup();
710 + }
711 +}
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 +}
1 +package org.onlab.onos.sdnip.bgp;
2 +
3 +import static org.easymock.EasyMock.createMock;
4 +import static org.easymock.EasyMock.expect;
5 +import static org.easymock.EasyMock.replay;
6 +import static org.hamcrest.Matchers.is;
7 +import static org.hamcrest.Matchers.not;
8 +import static org.junit.Assert.assertThat;
9 +
10 +import java.util.ArrayList;
11 +
12 +import org.junit.Before;
13 +import org.junit.Test;
14 +import org.onlab.packet.IpAddress;
15 +import org.onlab.packet.IpPrefix;
16 +
17 +/**
18 + * Unit tests for the BgpRouteEntry class.
19 + */
20 +public class BgpRouteEntryTest {
21 + private BgpSession bgpSession;
22 + private static final IpAddress BGP_SESSION_BGP_ID =
23 + IpAddress.valueOf("10.0.0.1");
24 + private static final IpAddress BGP_SESSION_IP_ADDRESS =
25 + IpAddress.valueOf("20.0.0.1");
26 +
27 + private BgpSession bgpSession2;
28 + private static final IpAddress BGP_SESSION_BGP_ID2 =
29 + IpAddress.valueOf("10.0.0.2");
30 + private static final IpAddress BGP_SESSION_IP_ADDRESS2 =
31 + IpAddress.valueOf("20.0.0.1");
32 +
33 + private BgpSession bgpSession3;
34 + private static final IpAddress BGP_SESSION_BGP_ID3 =
35 + IpAddress.valueOf("10.0.0.1");
36 + private static final IpAddress BGP_SESSION_IP_ADDRESS3 =
37 + IpAddress.valueOf("20.0.0.2");
38 +
39 + @Before
40 + public void setUp() throws Exception {
41 + // Mock objects for testing
42 + bgpSession = createMock(BgpSession.class);
43 + bgpSession2 = createMock(BgpSession.class);
44 + bgpSession3 = createMock(BgpSession.class);
45 +
46 + // Setup the BGP Sessions
47 + expect(bgpSession.getRemoteBgpId())
48 + .andReturn(BGP_SESSION_BGP_ID).anyTimes();
49 + expect(bgpSession.getRemoteIp4Address())
50 + .andReturn(BGP_SESSION_IP_ADDRESS).anyTimes();
51 + //
52 + expect(bgpSession2.getRemoteBgpId())
53 + .andReturn(BGP_SESSION_BGP_ID2).anyTimes();
54 + expect(bgpSession2.getRemoteIp4Address())
55 + .andReturn(BGP_SESSION_IP_ADDRESS2).anyTimes();
56 + //
57 + expect(bgpSession3.getRemoteBgpId())
58 + .andReturn(BGP_SESSION_BGP_ID3).anyTimes();
59 + expect(bgpSession3.getRemoteIp4Address())
60 + .andReturn(BGP_SESSION_IP_ADDRESS3).anyTimes();
61 +
62 + replay(bgpSession);
63 + replay(bgpSession2);
64 + replay(bgpSession3);
65 + }
66 +
67 + /**
68 + * Generates a BGP Route Entry.
69 + *
70 + * @return a generated BGP Route Entry
71 + */
72 + private BgpRouteEntry generateBgpRouteEntry() {
73 + IpPrefix prefix = IpPrefix.valueOf("1.2.3.0/24");
74 + IpAddress nextHop = IpAddress.valueOf("5.6.7.8");
75 + byte origin = BgpConstants.Update.Origin.IGP;
76 + // Setup the AS Path
77 + ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
78 + byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
79 + ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
80 + segmentAsNumbers1.add((long) 1);
81 + segmentAsNumbers1.add((long) 2);
82 + segmentAsNumbers1.add((long) 3);
83 + BgpRouteEntry.PathSegment pathSegment1 =
84 + new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
85 + pathSegments.add(pathSegment1);
86 + //
87 + byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
88 + ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
89 + segmentAsNumbers2.add((long) 4);
90 + segmentAsNumbers2.add((long) 5);
91 + segmentAsNumbers2.add((long) 6);
92 + BgpRouteEntry.PathSegment pathSegment2 =
93 + new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
94 + pathSegments.add(pathSegment2);
95 + //
96 + BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
97 + //
98 + long localPref = 100;
99 + long multiExitDisc = 20;
100 +
101 + BgpRouteEntry bgpRouteEntry =
102 + new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
103 + localPref);
104 + bgpRouteEntry.setMultiExitDisc(multiExitDisc);
105 +
106 + return bgpRouteEntry;
107 + }
108 +
109 + /**
110 + * Tests valid class constructor.
111 + */
112 + @Test
113 + public void testConstructor() {
114 + BgpRouteEntry bgpRouteEntry = generateBgpRouteEntry();
115 +
116 + String expectedString =
117 + "BgpRouteEntry{prefix=1.2.3.0/24, nextHop=5.6.7.8, " +
118 + "bgpId=10.0.0.1, origin=0, asPath=AsPath{pathSegments=" +
119 + "[PathSegment{type=2, segmentAsNumbers=[1, 2, 3]}, " +
120 + "PathSegment{type=1, segmentAsNumbers=[4, 5, 6]}]}, " +
121 + "localPref=100, multiExitDisc=20}";
122 + assertThat(bgpRouteEntry.toString(), is(expectedString));
123 + }
124 +
125 + /**
126 + * Tests invalid class constructor for null BGP Session.
127 + */
128 + @Test(expected = NullPointerException.class)
129 + public void testInvalidConstructorNullBgpSession() {
130 + BgpSession bgpSessionNull = null;
131 + IpPrefix prefix = IpPrefix.valueOf("1.2.3.0/24");
132 + IpAddress nextHop = IpAddress.valueOf("5.6.7.8");
133 + byte origin = BgpConstants.Update.Origin.IGP;
134 + // Setup the AS Path
135 + ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
136 + BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
137 + //
138 + long localPref = 100;
139 +
140 + new BgpRouteEntry(bgpSessionNull, prefix, nextHop, origin, asPath,
141 + localPref);
142 + }
143 +
144 + /**
145 + * Tests invalid class constructor for null AS Path.
146 + */
147 + @Test(expected = NullPointerException.class)
148 + public void testInvalidConstructorNullAsPath() {
149 + IpPrefix prefix = IpPrefix.valueOf("1.2.3.0/24");
150 + IpAddress nextHop = IpAddress.valueOf("5.6.7.8");
151 + byte origin = BgpConstants.Update.Origin.IGP;
152 + BgpRouteEntry.AsPath asPath = null;
153 + long localPref = 100;
154 +
155 + new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
156 + localPref);
157 + }
158 +
159 + /**
160 + * Tests getting the fields of a BGP route entry.
161 + */
162 + @Test
163 + public void testGetFields() {
164 + // Create the fields to compare against
165 + IpPrefix prefix = IpPrefix.valueOf("1.2.3.0/24");
166 + IpAddress nextHop = IpAddress.valueOf("5.6.7.8");
167 + byte origin = BgpConstants.Update.Origin.IGP;
168 + // Setup the AS Path
169 + ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
170 + byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
171 + ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
172 + segmentAsNumbers1.add((long) 1);
173 + segmentAsNumbers1.add((long) 2);
174 + segmentAsNumbers1.add((long) 3);
175 + BgpRouteEntry.PathSegment pathSegment1 =
176 + new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
177 + pathSegments.add(pathSegment1);
178 + //
179 + byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
180 + ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
181 + segmentAsNumbers2.add((long) 4);
182 + segmentAsNumbers2.add((long) 5);
183 + segmentAsNumbers2.add((long) 6);
184 + BgpRouteEntry.PathSegment pathSegment2 =
185 + new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
186 + pathSegments.add(pathSegment2);
187 + //
188 + BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
189 + //
190 + long localPref = 100;
191 + long multiExitDisc = 20;
192 +
193 + // Generate the entry to test
194 + BgpRouteEntry bgpRouteEntry = generateBgpRouteEntry();
195 +
196 + assertThat(bgpRouteEntry.prefix(), is(prefix));
197 + assertThat(bgpRouteEntry.nextHop(), is(nextHop));
198 + assertThat(bgpRouteEntry.getBgpSession(), is(bgpSession));
199 + assertThat(bgpRouteEntry.getOrigin(), is(origin));
200 + assertThat(bgpRouteEntry.getAsPath(), is(asPath));
201 + assertThat(bgpRouteEntry.getLocalPref(), is(localPref));
202 + assertThat(bgpRouteEntry.getMultiExitDisc(), is(multiExitDisc));
203 + }
204 +
205 + /**
206 + * Tests whether a BGP route entry is a local route.
207 + */
208 + @Test
209 + public void testIsLocalRoute() {
210 + //
211 + // Test non-local route
212 + //
213 + BgpRouteEntry bgpRouteEntry = generateBgpRouteEntry();
214 + assertThat(bgpRouteEntry.isLocalRoute(), is(false));
215 +
216 + //
217 + // Test local route with AS Path that begins with AS_SET
218 + //
219 + IpPrefix prefix = IpPrefix.valueOf("1.2.3.0/24");
220 + IpAddress nextHop = IpAddress.valueOf("5.6.7.8");
221 + byte origin = BgpConstants.Update.Origin.IGP;
222 + // Setup the AS Path
223 + ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
224 + byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SET;
225 + ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
226 + segmentAsNumbers1.add((long) 1);
227 + segmentAsNumbers1.add((long) 2);
228 + segmentAsNumbers1.add((long) 3);
229 + BgpRouteEntry.PathSegment pathSegment1 =
230 + new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
231 + pathSegments.add(pathSegment1);
232 + //
233 + byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
234 + ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
235 + segmentAsNumbers2.add((long) 4);
236 + segmentAsNumbers2.add((long) 5);
237 + segmentAsNumbers2.add((long) 6);
238 + BgpRouteEntry.PathSegment pathSegment2 =
239 + new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
240 + pathSegments.add(pathSegment2);
241 + //
242 + BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
243 + //
244 + long localPref = 100;
245 + long multiExitDisc = 20;
246 + //
247 + bgpRouteEntry =
248 + new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
249 + localPref);
250 + bgpRouteEntry.setMultiExitDisc(multiExitDisc);
251 + assertThat(bgpRouteEntry.isLocalRoute(), is(true));
252 +
253 + //
254 + // Test local route with empty AS Path
255 + //
256 + pathSegments = new ArrayList<>();
257 + asPath = new BgpRouteEntry.AsPath(pathSegments);
258 + bgpRouteEntry =
259 + new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
260 + localPref);
261 + bgpRouteEntry.setMultiExitDisc(multiExitDisc);
262 + assertThat(bgpRouteEntry.isLocalRoute(), is(true));
263 + }
264 +
265 + /**
266 + * Tests getting the BGP Neighbor AS number for a route.
267 + */
268 + @Test
269 + public void testGetNeighborAs() {
270 + //
271 + // Get neighbor AS for non-local route
272 + //
273 + BgpRouteEntry bgpRouteEntry = generateBgpRouteEntry();
274 + assertThat(bgpRouteEntry.getNeighborAs(), is((long) 1));
275 +
276 + //
277 + // Get neighbor AS for a local route
278 + //
279 + IpPrefix prefix = IpPrefix.valueOf("1.2.3.0/24");
280 + IpAddress nextHop = IpAddress.valueOf("5.6.7.8");
281 + byte origin = BgpConstants.Update.Origin.IGP;
282 + // Setup the AS Path
283 + ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
284 + BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
285 + //
286 + long localPref = 100;
287 + long multiExitDisc = 20;
288 + //
289 + bgpRouteEntry =
290 + new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
291 + localPref);
292 + bgpRouteEntry.setMultiExitDisc(multiExitDisc);
293 + assertThat(bgpRouteEntry.getNeighborAs(), is(BgpConstants.BGP_AS_0));
294 + }
295 +
296 + /**
297 + * Tests whether a BGP route entry has AS Path loop.
298 + */
299 + @Test
300 + public void testHasAsPathLoop() {
301 + BgpRouteEntry bgpRouteEntry = generateBgpRouteEntry();
302 +
303 + // Test for loops: test each AS number in the interval [1, 6]
304 + for (int i = 1; i <= 6; i++) {
305 + assertThat(bgpRouteEntry.hasAsPathLoop(i), is(true));
306 + }
307 +
308 + // Test for non-loops
309 + assertThat(bgpRouteEntry.hasAsPathLoop(500), is(false));
310 + }
311 +
312 + /**
313 + * Tests the BGP Decision Process comparison of BGP routes.
314 + */
315 + @Test
316 + public void testBgpDecisionProcessComparison() {
317 + BgpRouteEntry bgpRouteEntry1 = generateBgpRouteEntry();
318 + BgpRouteEntry bgpRouteEntry2 = generateBgpRouteEntry();
319 +
320 + //
321 + // Compare two routes that are same
322 + //
323 + assertThat(bgpRouteEntry1.isBetterThan(bgpRouteEntry2), is(true));
324 + assertThat(bgpRouteEntry2.isBetterThan(bgpRouteEntry1), is(true));
325 +
326 + //
327 + // Compare two routes with different LOCAL_PREF
328 + //
329 + IpPrefix prefix = IpPrefix.valueOf("1.2.3.0/24");
330 + IpAddress nextHop = IpAddress.valueOf("5.6.7.8");
331 + byte origin = BgpConstants.Update.Origin.IGP;
332 + // Setup the AS Path
333 + ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
334 + byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
335 + ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
336 + segmentAsNumbers1.add((long) 1);
337 + segmentAsNumbers1.add((long) 2);
338 + segmentAsNumbers1.add((long) 3);
339 + BgpRouteEntry.PathSegment pathSegment1 =
340 + new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
341 + pathSegments.add(pathSegment1);
342 + //
343 + byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
344 + ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
345 + segmentAsNumbers2.add((long) 4);
346 + segmentAsNumbers2.add((long) 5);
347 + segmentAsNumbers2.add((long) 6);
348 + BgpRouteEntry.PathSegment pathSegment2 =
349 + new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
350 + pathSegments.add(pathSegment2);
351 + //
352 + BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
353 + //
354 + long localPref = 50; // Different
355 + long multiExitDisc = 20;
356 + bgpRouteEntry2 =
357 + new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
358 + localPref);
359 + bgpRouteEntry2.setMultiExitDisc(multiExitDisc);
360 + //
361 + assertThat(bgpRouteEntry1.isBetterThan(bgpRouteEntry2), is(true));
362 + assertThat(bgpRouteEntry2.isBetterThan(bgpRouteEntry1), is(false));
363 + localPref = bgpRouteEntry1.getLocalPref(); // Restore
364 +
365 + //
366 + // Compare two routes with different AS_PATH length
367 + //
368 + ArrayList<BgpRouteEntry.PathSegment> pathSegments2 = new ArrayList<>();
369 + pathSegments2.add(pathSegment1);
370 + // Different AS Path
371 + BgpRouteEntry.AsPath asPath2 = new BgpRouteEntry.AsPath(pathSegments2);
372 + bgpRouteEntry2 =
373 + new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath2,
374 + localPref);
375 + bgpRouteEntry2.setMultiExitDisc(multiExitDisc);
376 + //
377 + assertThat(bgpRouteEntry1.isBetterThan(bgpRouteEntry2), is(false));
378 + assertThat(bgpRouteEntry2.isBetterThan(bgpRouteEntry1), is(true));
379 +
380 + //
381 + // Compare two routes with different ORIGIN
382 + //
383 + origin = BgpConstants.Update.Origin.EGP; // Different
384 + bgpRouteEntry2 =
385 + new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
386 + localPref);
387 + bgpRouteEntry2.setMultiExitDisc(multiExitDisc);
388 + //
389 + assertThat(bgpRouteEntry1.isBetterThan(bgpRouteEntry2), is(true));
390 + assertThat(bgpRouteEntry2.isBetterThan(bgpRouteEntry1), is(false));
391 + origin = bgpRouteEntry1.getOrigin(); // Restore
392 +
393 + //
394 + // Compare two routes with different MULTI_EXIT_DISC
395 + //
396 + multiExitDisc = 10; // Different
397 + bgpRouteEntry2 =
398 + new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
399 + localPref);
400 + bgpRouteEntry2.setMultiExitDisc(multiExitDisc);
401 + //
402 + assertThat(bgpRouteEntry1.isBetterThan(bgpRouteEntry2), is(true));
403 + assertThat(bgpRouteEntry2.isBetterThan(bgpRouteEntry1), is(false));
404 + multiExitDisc = bgpRouteEntry1.getMultiExitDisc(); // Restore
405 +
406 + //
407 + // Compare two routes with different BGP ID
408 + //
409 + bgpRouteEntry2 =
410 + new BgpRouteEntry(bgpSession2, prefix, nextHop, origin, asPath,
411 + localPref);
412 + bgpRouteEntry2.setMultiExitDisc(multiExitDisc);
413 + //
414 + assertThat(bgpRouteEntry1.isBetterThan(bgpRouteEntry2), is(true));
415 + assertThat(bgpRouteEntry2.isBetterThan(bgpRouteEntry1), is(false));
416 +
417 + //
418 + // Compare two routes with different BGP address
419 + //
420 + bgpRouteEntry2 =
421 + new BgpRouteEntry(bgpSession3, prefix, nextHop, origin, asPath,
422 + localPref);
423 + bgpRouteEntry2.setMultiExitDisc(multiExitDisc);
424 + //
425 + assertThat(bgpRouteEntry1.isBetterThan(bgpRouteEntry2), is(true));
426 + assertThat(bgpRouteEntry2.isBetterThan(bgpRouteEntry1), is(false));
427 + }
428 +
429 + /**
430 + * Tests equality of {@link BgpRouteEntry}.
431 + */
432 + @Test
433 + public void testEquality() {
434 + BgpRouteEntry bgpRouteEntry1 = generateBgpRouteEntry();
435 + BgpRouteEntry bgpRouteEntry2 = generateBgpRouteEntry();
436 +
437 + assertThat(bgpRouteEntry1, is(bgpRouteEntry2));
438 + }
439 +
440 + /**
441 + * Tests non-equality of {@link BgpRouteEntry}.
442 + */
443 + @Test
444 + public void testNonEquality() {
445 + BgpRouteEntry bgpRouteEntry1 = generateBgpRouteEntry();
446 +
447 + // Setup BGP Route 2
448 + IpPrefix prefix = IpPrefix.valueOf("1.2.3.0/24");
449 + IpAddress nextHop = IpAddress.valueOf("5.6.7.8");
450 + byte origin = BgpConstants.Update.Origin.IGP;
451 + // Setup the AS Path
452 + ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
453 + byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
454 + ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
455 + segmentAsNumbers1.add((long) 1);
456 + segmentAsNumbers1.add((long) 2);
457 + segmentAsNumbers1.add((long) 3);
458 + BgpRouteEntry.PathSegment pathSegment1 =
459 + new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
460 + pathSegments.add(pathSegment1);
461 + //
462 + byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
463 + ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
464 + segmentAsNumbers2.add((long) 4);
465 + segmentAsNumbers2.add((long) 5);
466 + segmentAsNumbers2.add((long) 6);
467 + BgpRouteEntry.PathSegment pathSegment2 =
468 + new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
469 + pathSegments.add(pathSegment2);
470 + //
471 + BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
472 + //
473 + long localPref = 500; // Different
474 + long multiExitDisc = 20;
475 + BgpRouteEntry bgpRouteEntry2 =
476 + new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
477 + localPref);
478 + bgpRouteEntry2.setMultiExitDisc(multiExitDisc);
479 +
480 + assertThat(bgpRouteEntry1, is(not(bgpRouteEntry2)));
481 + }
482 +
483 + /**
484 + * Tests object string representation.
485 + */
486 + @Test
487 + public void testToString() {
488 + BgpRouteEntry bgpRouteEntry = generateBgpRouteEntry();
489 +
490 + String expectedString =
491 + "BgpRouteEntry{prefix=1.2.3.0/24, nextHop=5.6.7.8, " +
492 + "bgpId=10.0.0.1, origin=0, asPath=AsPath{pathSegments=" +
493 + "[PathSegment{type=2, segmentAsNumbers=[1, 2, 3]}, " +
494 + "PathSegment{type=1, segmentAsNumbers=[4, 5, 6]}]}, " +
495 + "localPref=100, multiExitDisc=20}";
496 + assertThat(bgpRouteEntry.toString(), is(expectedString));
497 + }
498 +}
1 +package org.onlab.onos.sdnip.bgp;
2 +
3 +import static org.hamcrest.Matchers.hasItem;
4 +import static org.hamcrest.Matchers.hasSize;
5 +import static org.hamcrest.Matchers.is;
6 +import static org.hamcrest.Matchers.notNullValue;
7 +import static org.junit.Assert.assertThat;
8 +
9 +import java.net.InetAddress;
10 +import java.net.InetSocketAddress;
11 +import java.net.SocketAddress;
12 +import java.util.ArrayList;
13 +import java.util.Collection;
14 +import java.util.LinkedList;
15 +import java.util.concurrent.Executors;
16 +import java.util.concurrent.TimeUnit;
17 +
18 +import org.jboss.netty.bootstrap.ClientBootstrap;
19 +import org.jboss.netty.buffer.ChannelBuffer;
20 +import org.jboss.netty.channel.Channel;
21 +import org.jboss.netty.channel.ChannelFactory;
22 +import org.jboss.netty.channel.ChannelPipeline;
23 +import org.jboss.netty.channel.ChannelPipelineFactory;
24 +import org.jboss.netty.channel.Channels;
25 +import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
26 +import org.junit.After;
27 +import org.junit.Before;
28 +import org.junit.Test;
29 +import org.onlab.onos.sdnip.RouteListener;
30 +import org.onlab.onos.sdnip.RouteUpdate;
31 +import org.onlab.packet.IpAddress;
32 +import org.onlab.packet.IpPrefix;
33 +import org.onlab.util.TestUtils;
34 +import org.onlab.util.TestUtils.TestUtilsException;
35 +
36 +import com.google.common.net.InetAddresses;
37 +
38 +/**
39 + * Unit tests for the BgpSessionManager class.
40 + */
41 +public class BgpSessionManagerTest {
42 + private static final IpAddress IP_LOOPBACK_ID =
43 + IpAddress.valueOf("127.0.0.1");
44 + private static final IpAddress BGP_PEER1_ID = IpAddress.valueOf("10.0.0.1");
45 + private static final long DEFAULT_LOCAL_PREF = 10;
46 + private static final long DEFAULT_MULTI_EXIT_DISC = 20;
47 +
48 + // The BGP Session Manager to test
49 + private BgpSessionManager bgpSessionManager;
50 +
51 + // Remote Peer state
52 + private ClientBootstrap peerBootstrap;
53 + private TestBgpPeerChannelHandler peerChannelHandler =
54 + new TestBgpPeerChannelHandler(BGP_PEER1_ID, DEFAULT_LOCAL_PREF);
55 + private TestBgpPeerFrameDecoder peerFrameDecoder =
56 + new TestBgpPeerFrameDecoder();
57 +
58 + // The socket that the Remote Peer should connect to
59 + private InetSocketAddress connectToSocket;
60 +
61 + private final DummyRouteListener dummyRouteListener =
62 + new DummyRouteListener();
63 +
64 + /**
65 + * Dummy implementation for the RouteListener interface.
66 + */
67 + private class DummyRouteListener implements RouteListener {
68 + @Override
69 + public void update(RouteUpdate routeUpdate) {
70 + // Nothing to do
71 + }
72 + }
73 +
74 + @Before
75 + public void setUp() throws Exception {
76 + //
77 + // Setup the BGP Session Manager to test, and start listening for BGP
78 + // connections.
79 + //
80 + bgpSessionManager = new BgpSessionManager(dummyRouteListener);
81 + // NOTE: We use port 0 to bind on any available port
82 + bgpSessionManager.startUp(0);
83 +
84 + // Get the port number the BGP Session Manager is listening on
85 + Channel serverChannel = TestUtils.getField(bgpSessionManager,
86 + "serverChannel");
87 + SocketAddress socketAddress = serverChannel.getLocalAddress();
88 + InetSocketAddress inetSocketAddress =
89 + (InetSocketAddress) socketAddress;
90 +
91 + //
92 + // Setup the BGP Peer, i.e., the "remote" BGP router that will
93 + // initiate the BGP connection, send BGP UPDATE messages, etc.
94 + //
95 + ChannelFactory channelFactory =
96 + new NioClientSocketChannelFactory(Executors.newCachedThreadPool(),
97 + Executors.newCachedThreadPool());
98 + ChannelPipelineFactory pipelineFactory = new ChannelPipelineFactory() {
99 + @Override
100 + public ChannelPipeline getPipeline() throws Exception {
101 + // Setup the transmitting pipeline
102 + ChannelPipeline pipeline = Channels.pipeline();
103 + pipeline.addLast("TestBgpPeerFrameDecoder",
104 + peerFrameDecoder);
105 + pipeline.addLast("TestBgpPeerChannelHandler",
106 + peerChannelHandler);
107 + return pipeline;
108 + }
109 + };
110 +
111 + peerBootstrap = new ClientBootstrap(channelFactory);
112 + peerBootstrap.setOption("child.keepAlive", true);
113 + peerBootstrap.setOption("child.tcpNoDelay", true);
114 + peerBootstrap.setPipelineFactory(pipelineFactory);
115 +
116 + InetAddress connectToAddress = InetAddresses.forString("127.0.0.1");
117 + connectToSocket = new InetSocketAddress(connectToAddress,
118 + inetSocketAddress.getPort());
119 + }
120 +
121 + @After
122 + public void tearDown() throws Exception {
123 + bgpSessionManager.shutDown();
124 + bgpSessionManager = null;
125 + }
126 +
127 + /**
128 + * Gets BGP RIB-IN routes by waiting until they are received.
129 + * <p/>
130 + * NOTE: We keep checking once a second the number of received routes,
131 + * up to 5 seconds.
132 + *
133 + * @param bgpSession the BGP session that is expected to receive the
134 + * routes
135 + * @param expectedRoutes the expected number of routes
136 + * @return the BGP RIB-IN routes as received within the expected
137 + * time interval
138 + */
139 + private Collection<BgpRouteEntry> waitForBgpRibIn(BgpSession bgpSession,
140 + long expectedRoutes)
141 + throws InterruptedException {
142 + Collection<BgpRouteEntry> bgpRibIn = bgpSession.getBgpRibIn();
143 +
144 + final int maxChecks = 5; // Max wait of 5 seconds
145 + for (int i = 0; i < maxChecks; i++) {
146 + if (bgpRibIn.size() == expectedRoutes) {
147 + break;
148 + }
149 + Thread.sleep(1000);
150 + bgpRibIn = bgpSession.getBgpRibIn();
151 + }
152 +
153 + return bgpRibIn;
154 + }
155 +
156 + /**
157 + * Gets BGP merged routes by waiting until they are received.
158 + * <p/>
159 + * NOTE: We keep checking once a second the number of received routes,
160 + * up to 5 seconds.
161 + *
162 + * @param expectedRoutes the expected number of routes
163 + * @return the BGP Session Manager routes as received within the expected
164 + * time interval
165 + */
166 + private Collection<BgpRouteEntry> waitForBgpRoutes(long expectedRoutes)
167 + throws InterruptedException {
168 + Collection<BgpRouteEntry> bgpRoutes = bgpSessionManager.getBgpRoutes();
169 +
170 + final int maxChecks = 5; // Max wait of 5 seconds
171 + for (int i = 0; i < maxChecks; i++) {
172 + if (bgpRoutes.size() == expectedRoutes) {
173 + break;
174 + }
175 + Thread.sleep(1000);
176 + bgpRoutes = bgpSessionManager.getBgpRoutes();
177 + }
178 +
179 + return bgpRoutes;
180 + }
181 +
182 + /**
183 + * Tests that the BGP OPEN messages have been exchanged, followed by
184 + * KEEPALIVE.
185 + * <p>
186 + * The BGP Peer opens the sessions and transmits OPEN Message, eventually
187 + * followed by KEEPALIVE. The tested BGP listener should respond by
188 + * OPEN Message, followed by KEEPALIVE.
189 + *
190 + * @throws TestUtilsException TestUtils error
191 + */
192 + @Test
193 + public void testExchangedBgpOpenMessages()
194 + throws InterruptedException, TestUtilsException {
195 + // Initiate the connection
196 + peerBootstrap.connect(connectToSocket);
197 +
198 + // Wait until the OPEN message is received
199 + peerFrameDecoder.receivedOpenMessageLatch.await(2000,
200 + TimeUnit.MILLISECONDS);
201 + // Wait until the KEEPALIVE message is received
202 + peerFrameDecoder.receivedKeepaliveMessageLatch.await(2000,
203 + TimeUnit.MILLISECONDS);
204 +
205 + //
206 + // Test the fields from the BGP OPEN message:
207 + // BGP version, AS number, BGP ID
208 + //
209 + assertThat(peerFrameDecoder.remoteBgpVersion,
210 + is(BgpConstants.BGP_VERSION));
211 + assertThat(peerFrameDecoder.remoteAs,
212 + is(TestBgpPeerChannelHandler.PEER_AS));
213 + assertThat(peerFrameDecoder.remoteBgpIdentifier, is(IP_LOOPBACK_ID));
214 +
215 + //
216 + // Test that a BgpSession instance has been created
217 + //
218 + assertThat(bgpSessionManager.getMyBgpId(), is(IP_LOOPBACK_ID));
219 + assertThat(bgpSessionManager.getBgpSessions(), hasSize(1));
220 + BgpSession bgpSession =
221 + bgpSessionManager.getBgpSessions().iterator().next();
222 + assertThat(bgpSession, notNullValue());
223 + long sessionAs = TestUtils.getField(bgpSession, "localAs");
224 + assertThat(sessionAs, is(TestBgpPeerChannelHandler.PEER_AS));
225 + }
226 +
227 + /**
228 + * Tests that the BGP UPDATE messages have been received and processed.
229 + */
230 + @Test
231 + public void testProcessedBgpUpdateMessages() throws InterruptedException {
232 + BgpSession bgpSession;
233 + IpAddress nextHopRouter;
234 + BgpRouteEntry bgpRouteEntry;
235 + ChannelBuffer message;
236 + Collection<BgpRouteEntry> bgpRibIn;
237 + Collection<BgpRouteEntry> bgpRoutes;
238 +
239 + // Initiate the connection
240 + peerBootstrap.connect(connectToSocket);
241 +
242 + // Wait until the OPEN message is received
243 + peerFrameDecoder.receivedOpenMessageLatch.await(2000,
244 + TimeUnit.MILLISECONDS);
245 + // Wait until the KEEPALIVE message is received
246 + peerFrameDecoder.receivedKeepaliveMessageLatch.await(2000,
247 + TimeUnit.MILLISECONDS);
248 +
249 + // Get the BGP Session handler
250 + bgpSession = bgpSessionManager.getBgpSessions().iterator().next();
251 +
252 + // Prepare routes to add/delete
253 + nextHopRouter = IpAddress.valueOf("10.20.30.40");
254 + Collection<IpPrefix> addedRoutes = new LinkedList<>();
255 + Collection<IpPrefix> withdrawnRoutes = new LinkedList<>();
256 + addedRoutes.add(IpPrefix.valueOf("0.0.0.0/0"));
257 + addedRoutes.add(IpPrefix.valueOf("20.0.0.0/8"));
258 + addedRoutes.add(IpPrefix.valueOf("30.0.0.0/16"));
259 + addedRoutes.add(IpPrefix.valueOf("40.0.0.0/24"));
260 + addedRoutes.add(IpPrefix.valueOf("50.0.0.0/32"));
261 + withdrawnRoutes.add(IpPrefix.valueOf("60.0.0.0/8"));
262 + withdrawnRoutes.add(IpPrefix.valueOf("70.0.0.0/16"));
263 + withdrawnRoutes.add(IpPrefix.valueOf("80.0.0.0/24"));
264 + withdrawnRoutes.add(IpPrefix.valueOf("90.0.0.0/32"));
265 + // Write the routes
266 + message = peerChannelHandler.prepareBgpUpdate(nextHopRouter,
267 + addedRoutes,
268 + withdrawnRoutes);
269 + peerChannelHandler.savedCtx.getChannel().write(message);
270 +
271 + // Check that the routes have been received, processed and stored
272 + bgpRibIn = waitForBgpRibIn(bgpSession, 5);
273 + assertThat(bgpRibIn, hasSize(5));
274 + bgpRoutes = waitForBgpRoutes(5);
275 + assertThat(bgpRoutes, hasSize(5));
276 +
277 + // Setup the AS Path
278 + ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
279 + byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
280 + ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
281 + segmentAsNumbers1.add((long) 65010);
282 + segmentAsNumbers1.add((long) 65020);
283 + segmentAsNumbers1.add((long) 65030);
284 + BgpRouteEntry.PathSegment pathSegment1 =
285 + new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
286 + pathSegments.add(pathSegment1);
287 + //
288 + byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
289 + ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
290 + segmentAsNumbers2.add((long) 65041);
291 + segmentAsNumbers2.add((long) 65042);
292 + segmentAsNumbers2.add((long) 65043);
293 + BgpRouteEntry.PathSegment pathSegment2 =
294 + new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
295 + pathSegments.add(pathSegment2);
296 + //
297 + BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
298 +
299 + //
300 + bgpRouteEntry =
301 + new BgpRouteEntry(bgpSession,
302 + IpPrefix.valueOf("0.0.0.0/0"),
303 + nextHopRouter,
304 + (byte) BgpConstants.Update.Origin.IGP,
305 + asPath,
306 + DEFAULT_LOCAL_PREF);
307 + bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
308 + assertThat(bgpRibIn, hasItem(bgpRouteEntry));
309 + //
310 + bgpRouteEntry =
311 + new BgpRouteEntry(bgpSession,
312 + IpPrefix.valueOf("20.0.0.0/8"),
313 + nextHopRouter,
314 + (byte) BgpConstants.Update.Origin.IGP,
315 + asPath,
316 + DEFAULT_LOCAL_PREF);
317 + bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
318 + assertThat(bgpRibIn, hasItem(bgpRouteEntry));
319 + //
320 + bgpRouteEntry =
321 + new BgpRouteEntry(bgpSession,
322 + IpPrefix.valueOf("30.0.0.0/16"),
323 + nextHopRouter,
324 + (byte) BgpConstants.Update.Origin.IGP,
325 + asPath,
326 + DEFAULT_LOCAL_PREF);
327 + bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
328 + assertThat(bgpRibIn, hasItem(bgpRouteEntry));
329 + //
330 + bgpRouteEntry =
331 + new BgpRouteEntry(bgpSession,
332 + IpPrefix.valueOf("40.0.0.0/24"),
333 + nextHopRouter,
334 + (byte) BgpConstants.Update.Origin.IGP,
335 + asPath,
336 + DEFAULT_LOCAL_PREF);
337 + bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
338 + assertThat(bgpRibIn, hasItem(bgpRouteEntry));
339 + //
340 + bgpRouteEntry =
341 + new BgpRouteEntry(bgpSession,
342 + IpPrefix.valueOf("50.0.0.0/32"),
343 + nextHopRouter,
344 + (byte) BgpConstants.Update.Origin.IGP,
345 + asPath,
346 + DEFAULT_LOCAL_PREF);
347 + bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
348 + assertThat(bgpRibIn, hasItem(bgpRouteEntry));
349 +
350 + // Delete some routes
351 + addedRoutes = new LinkedList<>();
352 + withdrawnRoutes = new LinkedList<>();
353 + withdrawnRoutes.add(IpPrefix.valueOf("0.0.0.0/0"));
354 + withdrawnRoutes.add(IpPrefix.valueOf("50.0.0.0/32"));
355 +
356 + // Write the routes
357 + message = peerChannelHandler.prepareBgpUpdate(nextHopRouter,
358 + addedRoutes,
359 + withdrawnRoutes);
360 + peerChannelHandler.savedCtx.getChannel().write(message);
361 +
362 + // Check that the routes have been received, processed and stored
363 + bgpRibIn = waitForBgpRibIn(bgpSession, 3);
364 + assertThat(bgpRibIn, hasSize(3));
365 + bgpRoutes = waitForBgpRoutes(3);
366 + assertThat(bgpRoutes, hasSize(3));
367 + //
368 + bgpRouteEntry =
369 + new BgpRouteEntry(bgpSession,
370 + IpPrefix.valueOf("20.0.0.0/8"),
371 + nextHopRouter,
372 + (byte) BgpConstants.Update.Origin.IGP,
373 + asPath,
374 + DEFAULT_LOCAL_PREF);
375 + bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
376 + assertThat(bgpRibIn, hasItem(bgpRouteEntry));
377 + //
378 + bgpRouteEntry =
379 + new BgpRouteEntry(bgpSession,
380 + IpPrefix.valueOf("30.0.0.0/16"),
381 + nextHopRouter,
382 + (byte) BgpConstants.Update.Origin.IGP,
383 + asPath,
384 + DEFAULT_LOCAL_PREF);
385 + bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
386 + assertThat(bgpRibIn, hasItem(bgpRouteEntry));
387 + //
388 + bgpRouteEntry =
389 + new BgpRouteEntry(bgpSession,
390 + IpPrefix.valueOf("40.0.0.0/24"),
391 + nextHopRouter,
392 + (byte) BgpConstants.Update.Origin.IGP,
393 + asPath,
394 + DEFAULT_LOCAL_PREF);
395 + bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
396 + assertThat(bgpRibIn, hasItem(bgpRouteEntry));
397 +
398 + // Close the channel and test there are no routes
399 + peerChannelHandler.closeChannel();
400 + bgpRoutes = waitForBgpRoutes(0);
401 + assertThat(bgpRoutes, hasSize(0));
402 + }
403 +}
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 +}
...@@ -94,7 +94,7 @@ public class FlowsListCommand extends AbstractShellCommand { ...@@ -94,7 +94,7 @@ public class FlowsListCommand extends AbstractShellCommand {
94 94
95 result.put("device", device.id().toString()) 95 result.put("device", device.id().toString())
96 .put("flowCount", flows.size()) 96 .put("flowCount", flows.size())
97 - .put("flows", array); 97 + .set("flows", array);
98 return result; 98 return result;
99 } 99 }
100 100
......
...@@ -90,11 +90,15 @@ public class IntentPushTestCommand extends AbstractShellCommand ...@@ -90,11 +90,15 @@ public class IntentPushTestCommand extends AbstractShellCommand
90 service.submit(intent); 90 service.submit(intent);
91 } 91 }
92 try { 92 try {
93 - latch.await(5, TimeUnit.SECONDS); 93 + if (latch.await(10, TimeUnit.SECONDS)) {
94 printResults(count); 94 printResults(count);
95 + } else {
96 + print("I FAIL MISERABLY -> %d", latch.getCount());
97 + }
95 } catch (InterruptedException e) { 98 } catch (InterruptedException e) {
96 print(e.toString()); 99 print(e.toString());
97 } 100 }
101 +
98 service.removeListener(this); 102 service.removeListener(this);
99 } 103 }
100 104
...@@ -140,6 +144,8 @@ public class IntentPushTestCommand extends AbstractShellCommand ...@@ -140,6 +144,8 @@ public class IntentPushTestCommand extends AbstractShellCommand
140 } else { 144 } else {
141 log.warn("install event latch is null"); 145 log.warn("install event latch is null");
142 } 146 }
147 + } else {
148 + log.info("I FAIL -> {}", event);
143 } 149 }
144 } 150 }
145 } 151 }
......
1 package org.onlab.onos.net; 1 package org.onlab.onos.net;
2 2
3 import org.onlab.onos.net.provider.ProviderId; 3 import org.onlab.onos.net.provider.ProviderId;
4 +import org.onlab.packet.ChassisId;
4 5
5 import java.util.Objects; 6 import java.util.Objects;
6 7
...@@ -16,6 +17,7 @@ public class DefaultDevice extends AbstractElement implements Device { ...@@ -16,6 +17,7 @@ public class DefaultDevice extends AbstractElement implements Device {
16 private final String serialNumber; 17 private final String serialNumber;
17 private final String hwVersion; 18 private final String hwVersion;
18 private final String swVersion; 19 private final String swVersion;
20 + private final ChassisId chassisId;
19 21
20 // For serialization 22 // For serialization
21 private DefaultDevice() { 23 private DefaultDevice() {
...@@ -24,6 +26,7 @@ public class DefaultDevice extends AbstractElement implements Device { ...@@ -24,6 +26,7 @@ public class DefaultDevice extends AbstractElement implements Device {
24 this.hwVersion = null; 26 this.hwVersion = null;
25 this.swVersion = null; 27 this.swVersion = null;
26 this.serialNumber = null; 28 this.serialNumber = null;
29 + this.chassisId = null;
27 } 30 }
28 31
29 /** 32 /**
...@@ -40,13 +43,15 @@ public class DefaultDevice extends AbstractElement implements Device { ...@@ -40,13 +43,15 @@ public class DefaultDevice extends AbstractElement implements Device {
40 */ 43 */
41 public DefaultDevice(ProviderId providerId, DeviceId id, Type type, 44 public DefaultDevice(ProviderId providerId, DeviceId id, Type type,
42 String manufacturer, String hwVersion, String swVersion, 45 String manufacturer, String hwVersion, String swVersion,
43 - String serialNumber, Annotations... annotations) { 46 + String serialNumber, ChassisId chassisId,
47 + Annotations... annotations) {
44 super(providerId, id, annotations); 48 super(providerId, id, annotations);
45 this.type = type; 49 this.type = type;
46 this.manufacturer = manufacturer; 50 this.manufacturer = manufacturer;
47 this.hwVersion = hwVersion; 51 this.hwVersion = hwVersion;
48 this.swVersion = swVersion; 52 this.swVersion = swVersion;
49 this.serialNumber = serialNumber; 53 this.serialNumber = serialNumber;
54 + this.chassisId = chassisId;
50 } 55 }
51 56
52 @Override 57 @Override
...@@ -80,6 +85,11 @@ public class DefaultDevice extends AbstractElement implements Device { ...@@ -80,6 +85,11 @@ public class DefaultDevice extends AbstractElement implements Device {
80 } 85 }
81 86
82 @Override 87 @Override
88 + public ChassisId chassisId() {
89 + return chassisId;
90 + }
91 +
92 + @Override
83 public int hashCode() { 93 public int hashCode() {
84 return Objects.hash(id, type, manufacturer, hwVersion, swVersion, serialNumber); 94 return Objects.hash(id, type, manufacturer, hwVersion, swVersion, serialNumber);
85 } 95 }
......
1 package org.onlab.onos.net; 1 package org.onlab.onos.net;
2 2
3 +import org.onlab.packet.ChassisId;
4 +
3 /** 5 /**
4 * Representation of a network infrastructure device. 6 * Representation of a network infrastructure device.
5 */ 7 */
...@@ -54,6 +56,13 @@ public interface Device extends Element { ...@@ -54,6 +56,13 @@ public interface Device extends Element {
54 */ 56 */
55 String serialNumber(); 57 String serialNumber();
56 58
59 + /**
60 + * Returns the device chassis id.
61 + *
62 + * @return chassis id
63 + */
64 + ChassisId chassisId();
65 +
57 // Device realizedBy(); ? 66 // Device realizedBy(); ?
58 67
59 // ports are not provided directly, but rather via DeviceService.getPorts(Device device); 68 // ports are not provided directly, but rather via DeviceService.getPorts(Device device);
......
...@@ -2,6 +2,7 @@ package org.onlab.onos.net.device; ...@@ -2,6 +2,7 @@ package org.onlab.onos.net.device;
2 2
3 import org.onlab.onos.net.AbstractDescription; 3 import org.onlab.onos.net.AbstractDescription;
4 import org.onlab.onos.net.SparseAnnotations; 4 import org.onlab.onos.net.SparseAnnotations;
5 +import org.onlab.packet.ChassisId;
5 6
6 import java.net.URI; 7 import java.net.URI;
7 8
...@@ -20,6 +21,7 @@ public class DefaultDeviceDescription extends AbstractDescription ...@@ -20,6 +21,7 @@ public class DefaultDeviceDescription extends AbstractDescription
20 private final String hwVersion; 21 private final String hwVersion;
21 private final String swVersion; 22 private final String swVersion;
22 private final String serialNumber; 23 private final String serialNumber;
24 + private final ChassisId chassisId;
23 25
24 /** 26 /**
25 * Creates a device description using the supplied information. 27 * Creates a device description using the supplied information.
...@@ -34,7 +36,7 @@ public class DefaultDeviceDescription extends AbstractDescription ...@@ -34,7 +36,7 @@ public class DefaultDeviceDescription extends AbstractDescription
34 */ 36 */
35 public DefaultDeviceDescription(URI uri, Type type, String manufacturer, 37 public DefaultDeviceDescription(URI uri, Type type, String manufacturer,
36 String hwVersion, String swVersion, 38 String hwVersion, String swVersion,
37 - String serialNumber, 39 + String serialNumber, ChassisId chassis,
38 SparseAnnotations... annotations) { 40 SparseAnnotations... annotations) {
39 super(annotations); 41 super(annotations);
40 this.uri = checkNotNull(uri, "Device URI cannot be null"); 42 this.uri = checkNotNull(uri, "Device URI cannot be null");
...@@ -43,6 +45,7 @@ public class DefaultDeviceDescription extends AbstractDescription ...@@ -43,6 +45,7 @@ public class DefaultDeviceDescription extends AbstractDescription
43 this.hwVersion = hwVersion; 45 this.hwVersion = hwVersion;
44 this.swVersion = swVersion; 46 this.swVersion = swVersion;
45 this.serialNumber = serialNumber; 47 this.serialNumber = serialNumber;
48 + this.chassisId = chassis;
46 } 49 }
47 50
48 /** 51 /**
...@@ -54,7 +57,7 @@ public class DefaultDeviceDescription extends AbstractDescription ...@@ -54,7 +57,7 @@ public class DefaultDeviceDescription extends AbstractDescription
54 SparseAnnotations... annotations) { 57 SparseAnnotations... annotations) {
55 this(base.deviceURI(), base.type(), base.manufacturer(), 58 this(base.deviceURI(), base.type(), base.manufacturer(),
56 base.hwVersion(), base.swVersion(), base.serialNumber(), 59 base.hwVersion(), base.swVersion(), base.serialNumber(),
57 - annotations); 60 + base.chassisId(), annotations);
58 } 61 }
59 62
60 @Override 63 @Override
...@@ -88,6 +91,11 @@ public class DefaultDeviceDescription extends AbstractDescription ...@@ -88,6 +91,11 @@ public class DefaultDeviceDescription extends AbstractDescription
88 } 91 }
89 92
90 @Override 93 @Override
94 + public ChassisId chassisId() {
95 + return chassisId;
96 + }
97 +
98 + @Override
91 public String toString() { 99 public String toString() {
92 return toStringHelper(this) 100 return toStringHelper(this)
93 .add("uri", uri).add("type", type).add("mfr", manufacturer) 101 .add("uri", uri).add("type", type).add("mfr", manufacturer)
...@@ -104,5 +112,6 @@ public class DefaultDeviceDescription extends AbstractDescription ...@@ -104,5 +112,6 @@ public class DefaultDeviceDescription extends AbstractDescription
104 this.hwVersion = null; 112 this.hwVersion = null;
105 this.swVersion = null; 113 this.swVersion = null;
106 this.serialNumber = null; 114 this.serialNumber = null;
115 + this.chassisId = null;
107 } 116 }
108 } 117 }
......
...@@ -2,6 +2,7 @@ package org.onlab.onos.net.device; ...@@ -2,6 +2,7 @@ package org.onlab.onos.net.device;
2 2
3 import org.onlab.onos.net.Description; 3 import org.onlab.onos.net.Description;
4 import org.onlab.onos.net.Device; 4 import org.onlab.onos.net.Device;
5 +import org.onlab.packet.ChassisId;
5 6
6 import java.net.URI; 7 import java.net.URI;
7 8
...@@ -54,4 +55,11 @@ public interface DeviceDescription extends Description { ...@@ -54,4 +55,11 @@ public interface DeviceDescription extends Description {
54 */ 55 */
55 String serialNumber(); 56 String serialNumber();
56 57
58 + /**
59 + * Returns a device chassis id.
60 + *
61 + * @return chassis id
62 + */
63 + ChassisId chassisId();
64 +
57 } 65 }
......
...@@ -8,7 +8,7 @@ import org.slf4j.Logger; ...@@ -8,7 +8,7 @@ import org.slf4j.Logger;
8 8
9 public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry { 9 public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry {
10 10
11 - private final Logger log = getLogger(getClass()); 11 + private static final Logger log = getLogger(DefaultFlowEntry.class);
12 12
13 private long life; 13 private long life;
14 private long packets; 14 private long packets;
......
...@@ -11,7 +11,7 @@ import org.slf4j.Logger; ...@@ -11,7 +11,7 @@ import org.slf4j.Logger;
11 11
12 public class DefaultFlowRule implements FlowRule { 12 public class DefaultFlowRule implements FlowRule {
13 13
14 - private final Logger log = getLogger(getClass()); 14 + private static final Logger log = getLogger(DefaultFlowRule.class);
15 15
16 private final DeviceId deviceId; 16 private final DeviceId deviceId;
17 private final int priority; 17 private final int priority;
......
...@@ -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;
......
...@@ -62,6 +62,9 @@ public abstract class AbstractProviderRegistry<P extends Provider, S extends Pro ...@@ -62,6 +62,9 @@ public abstract class AbstractProviderRegistry<P extends Provider, S extends Pro
62 ((AbstractProviderService) service).invalidate(); 62 ((AbstractProviderService) service).invalidate();
63 services.remove(provider.id()); 63 services.remove(provider.id());
64 providers.remove(provider.id()); 64 providers.remove(provider.id());
65 + if (!provider.id().isAncillary()) {
66 + providersByScheme.remove(provider.id().scheme());
67 + }
65 } 68 }
66 } 69 }
67 70
......
...@@ -7,6 +7,8 @@ import org.onlab.onos.net.Provided; ...@@ -7,6 +7,8 @@ import org.onlab.onos.net.Provided;
7 */ 7 */
8 public interface Topology extends Provided { 8 public interface Topology extends Provided {
9 9
10 + // FIXME: Following is not true right now. It is actually System.nanoTime(),
11 + // which has no relation to epoch time, wall clock, etc.
10 /** 12 /**
11 * Returns the time, specified in milliseconds since start of epoch, 13 * Returns the time, specified in milliseconds since start of epoch,
12 * when the topology became active and made available. 14 * when the topology became active and made available.
......
...@@ -37,6 +37,15 @@ public interface ClusterCommunicationService { ...@@ -37,6 +37,15 @@ public interface ClusterCommunicationService {
37 boolean multicast(ClusterMessage message, Set<NodeId> nodeIds) throws IOException; 37 boolean multicast(ClusterMessage message, Set<NodeId> nodeIds) throws IOException;
38 38
39 /** 39 /**
40 + * Sends a message synchronously.
41 + * @param message message to send
42 + * @param toNodeId recipient node identifier
43 + * @return ClusterMessageResponse which is reply future.
44 + * @throws IOException
45 + */
46 + ClusterMessageResponse sendAndReceive(ClusterMessage message, NodeId toNodeId) throws IOException;
47 +
48 + /**
40 * Adds a new subscriber for the specified message subject. 49 * Adds a new subscriber for the specified message subject.
41 * 50 *
42 * @param subject message subject 51 * @param subject message subject
......
1 package org.onlab.onos.store.cluster.messaging; 1 package org.onlab.onos.store.cluster.messaging;
2 2
3 +import java.io.IOException;
4 +
3 import org.onlab.onos.cluster.NodeId; 5 import org.onlab.onos.cluster.NodeId;
4 6
5 // TODO: Should payload type be ByteBuffer? 7 // TODO: Should payload type be ByteBuffer?
...@@ -49,4 +51,14 @@ public class ClusterMessage { ...@@ -49,4 +51,14 @@ public class ClusterMessage {
49 public byte[] payload() { 51 public byte[] payload() {
50 return payload; 52 return payload;
51 } 53 }
54 +
55 + /**
56 + * Sends a response to the sender.
57 + *
58 + * @param data payload response.
59 + * @throws IOException
60 + */
61 + public void respond(byte[] data) throws IOException {
62 + throw new IllegalStateException("One can only repond to message recived from others.");
63 + }
52 } 64 }
......
1 +package org.onlab.onos.store.cluster.messaging;
2 +
3 +import java.util.concurrent.TimeUnit;
4 +import java.util.concurrent.TimeoutException;
5 +
6 +import org.onlab.onos.cluster.NodeId;
7 +
8 +public interface ClusterMessageResponse {
9 + public NodeId sender();
10 + public byte[] get(long timeout, TimeUnit timeunit) throws TimeoutException;
11 + public byte[] get(long timeout) throws InterruptedException;
12 +}
...@@ -3,6 +3,7 @@ package org.onlab.onos.net; ...@@ -3,6 +3,7 @@ package org.onlab.onos.net;
3 import com.google.common.testing.EqualsTester; 3 import com.google.common.testing.EqualsTester;
4 import org.junit.Test; 4 import org.junit.Test;
5 import org.onlab.onos.net.provider.ProviderId; 5 import org.onlab.onos.net.provider.ProviderId;
6 +import org.onlab.packet.ChassisId;
6 7
7 import static org.junit.Assert.assertEquals; 8 import static org.junit.Assert.assertEquals;
8 import static org.onlab.onos.net.Device.Type.SWITCH; 9 import static org.onlab.onos.net.Device.Type.SWITCH;
...@@ -21,14 +22,15 @@ public class DefaultDeviceTest { ...@@ -21,14 +22,15 @@ public class DefaultDeviceTest {
21 static final String SW = "3.9.1"; 22 static final String SW = "3.9.1";
22 static final String SN1 = "43311-12345"; 23 static final String SN1 = "43311-12345";
23 static final String SN2 = "42346-43512"; 24 static final String SN2 = "42346-43512";
25 + static final ChassisId CID = new ChassisId();
24 26
25 @Test 27 @Test
26 public void testEquality() { 28 public void testEquality() {
27 - Device d1 = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1); 29 + Device d1 = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1, CID);
28 - Device d2 = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1); 30 + Device d2 = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1, CID);
29 - Device d3 = new DefaultDevice(PID, DID2, SWITCH, MFR, HW, SW, SN2); 31 + Device d3 = new DefaultDevice(PID, DID2, SWITCH, MFR, HW, SW, SN2, CID);
30 - Device d4 = new DefaultDevice(PID, DID2, SWITCH, MFR, HW, SW, SN2); 32 + Device d4 = new DefaultDevice(PID, DID2, SWITCH, MFR, HW, SW, SN2, CID);
31 - Device d5 = new DefaultDevice(PID, DID2, SWITCH, MFR, HW, SW, SN1); 33 + Device d5 = new DefaultDevice(PID, DID2, SWITCH, MFR, HW, SW, SN1, CID);
32 34
33 new EqualsTester().addEqualityGroup(d1, d2) 35 new EqualsTester().addEqualityGroup(d1, d2)
34 .addEqualityGroup(d3, d4) 36 .addEqualityGroup(d3, d4)
...@@ -38,13 +40,13 @@ public class DefaultDeviceTest { ...@@ -38,13 +40,13 @@ public class DefaultDeviceTest {
38 40
39 @Test 41 @Test
40 public void basics() { 42 public void basics() {
41 - Device device = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1); 43 + Device device = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1, CID);
42 validate(device); 44 validate(device);
43 } 45 }
44 46
45 @Test 47 @Test
46 public void annotations() { 48 public void annotations() {
47 - Device device = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1, 49 + Device device = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1, CID,
48 DefaultAnnotations.builder().set("foo", "bar").build()); 50 DefaultAnnotations.builder().set("foo", "bar").build());
49 validate(device); 51 validate(device);
50 assertEquals("incorrect provider", "bar", device.annotations().value("foo")); 52 assertEquals("incorrect provider", "bar", device.annotations().value("foo"));
......
...@@ -3,6 +3,7 @@ package org.onlab.onos.net; ...@@ -3,6 +3,7 @@ package org.onlab.onos.net;
3 import com.google.common.testing.EqualsTester; 3 import com.google.common.testing.EqualsTester;
4 import org.junit.Test; 4 import org.junit.Test;
5 import org.onlab.onos.net.provider.ProviderId; 5 import org.onlab.onos.net.provider.ProviderId;
6 +import org.onlab.packet.ChassisId;
6 7
7 import static org.junit.Assert.assertEquals; 8 import static org.junit.Assert.assertEquals;
8 import static org.onlab.onos.net.Device.Type.SWITCH; 9 import static org.onlab.onos.net.Device.Type.SWITCH;
...@@ -22,7 +23,8 @@ public class DefaultPortTest { ...@@ -22,7 +23,8 @@ public class DefaultPortTest {
22 23
23 @Test 24 @Test
24 public void testEquality() { 25 public void testEquality() {
25 - Device device = new DefaultDevice(PID, DID1, SWITCH, "m", "h", "s", "n"); 26 + Device device = new DefaultDevice(PID, DID1, SWITCH, "m", "h", "s", "n",
27 + new ChassisId());
26 Port p1 = new DefaultPort(device, portNumber(1), true); 28 Port p1 = new DefaultPort(device, portNumber(1), true);
27 Port p2 = new DefaultPort(device, portNumber(1), true); 29 Port p2 = new DefaultPort(device, portNumber(1), true);
28 Port p3 = new DefaultPort(device, portNumber(2), true); 30 Port p3 = new DefaultPort(device, portNumber(2), true);
...@@ -37,7 +39,8 @@ public class DefaultPortTest { ...@@ -37,7 +39,8 @@ public class DefaultPortTest {
37 39
38 @Test 40 @Test
39 public void basics() { 41 public void basics() {
40 - Device device = new DefaultDevice(PID, DID1, SWITCH, "m", "h", "s", "n"); 42 + Device device = new DefaultDevice(PID, DID1, SWITCH, "m", "h", "s", "n",
43 + new ChassisId());
41 Port port = new DefaultPort(device, portNumber(1), true); 44 Port port = new DefaultPort(device, portNumber(1), true);
42 assertEquals("incorrect element", device, port.element()); 45 assertEquals("incorrect element", device, port.element());
43 assertEquals("incorrect number", portNumber(1), port.number()); 46 assertEquals("incorrect number", portNumber(1), port.number());
......
1 package org.onlab.onos.net; 1 package org.onlab.onos.net;
2 2
3 import org.onlab.onos.net.provider.ProviderId; 3 import org.onlab.onos.net.provider.ProviderId;
4 +import org.onlab.packet.ChassisId;
4 import org.onlab.packet.IpPrefix; 5 import org.onlab.packet.IpPrefix;
5 6
6 import java.util.ArrayList; 7 import java.util.ArrayList;
...@@ -37,7 +38,7 @@ public final class NetTestTools { ...@@ -37,7 +38,7 @@ public final class NetTestTools {
37 // Crates a new device with the specified id 38 // Crates a new device with the specified id
38 public static Device device(String id) { 39 public static Device device(String id) {
39 return new DefaultDevice(PID, did(id), Device.Type.SWITCH, 40 return new DefaultDevice(PID, did(id), Device.Type.SWITCH,
40 - "mfg", "1.0", "1.1", "1234"); 41 + "mfg", "1.0", "1.1", "1234", new ChassisId());
41 } 42 }
42 43
43 // Crates a new host with the specified id 44 // Crates a new host with the specified id
...@@ -47,10 +48,16 @@ public final class NetTestTools { ...@@ -47,10 +48,16 @@ public final class NetTestTools {
47 new HashSet<IpPrefix>()); 48 new HashSet<IpPrefix>());
48 } 49 }
49 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 +
50 // Short-hand for creating a link. 56 // Short-hand for creating a link.
51 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) {
52 - return new DefaultLink(PID, new ConnectPoint(did(src), portNumber(sp)), 58 + return new DefaultLink(PID,
53 - new ConnectPoint(did(dst), portNumber(dp)), 59 + connectPoint(src, sp),
60 + connectPoint(dst, dp),
54 Link.Type.DIRECT); 61 Link.Type.DIRECT);
55 } 62 }
56 63
......
1 package org.onlab.onos.net.device; 1 package org.onlab.onos.net.device;
2 2
3 import org.junit.Test; 3 import org.junit.Test;
4 +import org.onlab.packet.ChassisId;
4 5
5 import java.net.URI; 6 import java.net.URI;
6 7
...@@ -18,12 +19,13 @@ public class DefaultDeviceDescriptionTest { ...@@ -18,12 +19,13 @@ public class DefaultDeviceDescriptionTest {
18 private static final String HW = "1.1.x"; 19 private static final String HW = "1.1.x";
19 private static final String SW = "3.9.1"; 20 private static final String SW = "3.9.1";
20 private static final String SN = "43311-12345"; 21 private static final String SN = "43311-12345";
22 + private static final ChassisId CID = new ChassisId();
21 23
22 24
23 @Test 25 @Test
24 public void basics() { 26 public void basics() {
25 DeviceDescription device = 27 DeviceDescription device =
26 - new DefaultDeviceDescription(DURI, SWITCH, MFR, HW, SW, SN); 28 + new DefaultDeviceDescription(DURI, SWITCH, MFR, HW, SW, SN, CID);
27 assertEquals("incorrect uri", DURI, device.deviceURI()); 29 assertEquals("incorrect uri", DURI, device.deviceURI());
28 assertEquals("incorrect type", SWITCH, device.type()); 30 assertEquals("incorrect type", SWITCH, device.type());
29 assertEquals("incorrect manufacturer", MFR, device.manufacturer()); 31 assertEquals("incorrect manufacturer", MFR, device.manufacturer());
...@@ -31,6 +33,7 @@ public class DefaultDeviceDescriptionTest { ...@@ -31,6 +33,7 @@ public class DefaultDeviceDescriptionTest {
31 assertEquals("incorrect sw", SW, device.swVersion()); 33 assertEquals("incorrect sw", SW, device.swVersion());
32 assertEquals("incorrect serial", SN, device.serialNumber()); 34 assertEquals("incorrect serial", SN, device.serialNumber());
33 assertTrue("incorrect toString", device.toString().contains("uri=of:foo")); 35 assertTrue("incorrect toString", device.toString().contains("uri=of:foo"));
36 + assertTrue("Incorrect chassis", device.chassisId().value() == 0);
34 } 37 }
35 38
36 } 39 }
......
...@@ -11,6 +11,7 @@ import org.onlab.onos.net.Device; ...@@ -11,6 +11,7 @@ import org.onlab.onos.net.Device;
11 import org.onlab.onos.net.Port; 11 import org.onlab.onos.net.Port;
12 import org.onlab.onos.net.PortNumber; 12 import org.onlab.onos.net.PortNumber;
13 import org.onlab.onos.net.provider.ProviderId; 13 import org.onlab.onos.net.provider.ProviderId;
14 +import org.onlab.packet.ChassisId;
14 15
15 /** 16 /**
16 * Tests of the device event. 17 * Tests of the device event.
...@@ -19,7 +20,7 @@ public class DeviceEventTest extends AbstractEventTest { ...@@ -19,7 +20,7 @@ public class DeviceEventTest extends AbstractEventTest {
19 20
20 private Device createDevice() { 21 private Device createDevice() {
21 return new DefaultDevice(new ProviderId("of", "foo"), deviceId("of:foo"), 22 return new DefaultDevice(new ProviderId("of", "foo"), deviceId("of:foo"),
22 - Device.Type.SWITCH, "box", "hw", "sw", "sn"); 23 + Device.Type.SWITCH, "box", "hw", "sw", "sn", new ChassisId());
23 } 24 }
24 25
25 @Override 26 @Override
......
...@@ -18,9 +18,9 @@ public class DefaultGraphDescriptionTest { ...@@ -18,9 +18,9 @@ public class DefaultGraphDescriptionTest {
18 18
19 private static final DeviceId D3 = deviceId("3"); 19 private static final DeviceId D3 = deviceId("3");
20 20
21 - static final Device DEV1 = new DefaultDevice(PID, D1, SWITCH, "", "", "", ""); 21 + static final Device DEV1 = new DefaultDevice(PID, D1, SWITCH, "", "", "", "", null);
22 - static final Device DEV2 = new DefaultDevice(PID, D2, SWITCH, "", "", "", ""); 22 + static final Device DEV2 = new DefaultDevice(PID, D2, SWITCH, "", "", "", "", null);
23 - static final Device DEV3 = new DefaultDevice(PID, D3, SWITCH, "", "", "", ""); 23 + static final Device DEV3 = new DefaultDevice(PID, D3, SWITCH, "", "", "", "", null);
24 24
25 @Test 25 @Test
26 public void basics() { 26 public void basics() {
......
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-core</artifactId>
10 + <version>1.0.0-SNAPSHOT</version>
11 + <relativePath>../pom.xml</relativePath>
12 + </parent>
13 +
14 + <artifactId>onos-json</artifactId>
15 + <packaging>bundle</packaging>
16 +
17 + <description>ONOS JSON encode/decode facilities</description>
18 +
19 + <dependencies>
20 + <dependency>
21 + <groupId>org.onlab.onos</groupId>
22 + <artifactId>onos-api</artifactId>
23 + </dependency>
24 + <dependency>
25 + <groupId>org.onlab.onos</groupId>
26 + <artifactId>onos-api</artifactId>
27 + <classifier>tests</classifier>
28 + <scope>test</scope>
29 + </dependency>
30 +
31 + <dependency>
32 + <groupId>org.onlab.onos</groupId>
33 + <artifactId>onos-core-trivial</artifactId>
34 + <version>${project.version}</version>
35 + <scope>test</scope>
36 + </dependency>
37 +
38 + <dependency>
39 + <groupId>org.apache.felix</groupId>
40 + <artifactId>org.apache.felix.scr.annotations</artifactId>
41 + </dependency>
42 + </dependencies>
43 +
44 + <build>
45 + <plugins>
46 + <plugin>
47 + <groupId>org.apache.felix</groupId>
48 + <artifactId>maven-scr-plugin</artifactId>
49 + </plugin>
50 + </plugins>
51 + </build>
52 +
53 +</project>
1 +package org.onlab.onos.json.impl;
2 +
3 +/**
4 + * Created by tom on 10/16/14.
5 + */
6 +public class DeleteMe {
7 +}
1 +/**
2 + * Implementation of JSON codec factory and of the builtin codecs.
3 + */
4 +package org.onlab.onos.json.impl;
...\ No newline at end of file ...\ No newline at end of file
...@@ -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>
......
...@@ -388,7 +388,7 @@ public class DeviceManager ...@@ -388,7 +388,7 @@ public class DeviceManager
388 new DefaultDeviceDescription( 388 new DefaultDeviceDescription(
389 did.uri(), device.type(), device.manufacturer(), 389 did.uri(), device.type(), device.manufacturer(),
390 device.hwVersion(), device.swVersion(), 390 device.hwVersion(), device.swVersion(),
391 - device.serialNumber())); 391 + device.serialNumber(), device.chassisId()));
392 } 392 }
393 //TODO re-collect device information to fix potential staleness 393 //TODO re-collect device information to fix potential staleness
394 applyRole(did, MastershipRole.MASTER); 394 applyRole(did, MastershipRole.MASTER);
......
...@@ -401,7 +401,7 @@ public class FlowRuleManager ...@@ -401,7 +401,7 @@ public class FlowRuleManager
401 CompletedBatchOperation completed; 401 CompletedBatchOperation completed;
402 for (Future<CompletedBatchOperation> future : futures) { 402 for (Future<CompletedBatchOperation> future : futures) {
403 completed = future.get(); 403 completed = future.get();
404 - success = validateBatchOperation(failed, completed, future); 404 + success = validateBatchOperation(failed, completed);
405 } 405 }
406 406
407 return finalizeBatchOperation(success, failed); 407 return finalizeBatchOperation(success, failed);
...@@ -426,14 +426,13 @@ public class FlowRuleManager ...@@ -426,14 +426,13 @@ public class FlowRuleManager
426 long now = System.nanoTime(); 426 long now = System.nanoTime();
427 long thisTimeout = end - now; 427 long thisTimeout = end - now;
428 completed = future.get(thisTimeout, TimeUnit.NANOSECONDS); 428 completed = future.get(thisTimeout, TimeUnit.NANOSECONDS);
429 - success = validateBatchOperation(failed, completed, future); 429 + success = validateBatchOperation(failed, completed);
430 } 430 }
431 return finalizeBatchOperation(success, failed); 431 return finalizeBatchOperation(success, failed);
432 } 432 }
433 433
434 private boolean validateBatchOperation(List<FlowEntry> failed, 434 private boolean validateBatchOperation(List<FlowEntry> failed,
435 - CompletedBatchOperation completed, 435 + CompletedBatchOperation completed) {
436 - Future<CompletedBatchOperation> future) {
437 436
438 if (isCancelled()) { 437 if (isCancelled()) {
439 throw new CancellationException(); 438 throw new CancellationException();
......
...@@ -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() {
......
...@@ -96,7 +96,7 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { ...@@ -96,7 +96,7 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
96 96
97 FlowRule rule = new DefaultFlowRule(link.src().deviceId(), 97 FlowRule rule = new DefaultFlowRule(link.src().deviceId(),
98 builder.build(), treatment, 98 builder.build(), treatment,
99 - 123, appId, 600); 99 + 123, appId, 15);
100 rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule)); 100 rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule));
101 prev = link.dst(); 101 prev = link.dst();
102 } 102 }
......
...@@ -43,7 +43,7 @@ public class PointToPointIntentCompiler ...@@ -43,7 +43,7 @@ public class PointToPointIntentCompiler
43 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 43 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
44 protected HostService hostService; 44 protected HostService hostService;
45 45
46 - private IdGenerator<IntentId> intentIdGenerator; 46 + protected IdGenerator<IntentId> intentIdGenerator;
47 47
48 @Activate 48 @Activate
49 public void activate() { 49 public void activate() {
......
...@@ -244,6 +244,7 @@ public class LinkManager ...@@ -244,6 +244,7 @@ public class LinkManager
244 return; 244 return;
245 } 245 }
246 log.info("Links for connection point {} vanished", connectPoint); 246 log.info("Links for connection point {} vanished", connectPoint);
247 + // FIXME: This will remove links registered by other providers
247 removeLinks(getLinks(connectPoint)); 248 removeLinks(getLinks(connectPoint));
248 } 249 }
249 250
......
...@@ -167,6 +167,7 @@ public class ProxyArpManager implements ProxyArpService { ...@@ -167,6 +167,7 @@ public class ProxyArpManager implements ProxyArpService {
167 return; 167 return;
168 } 168 }
169 169
170 + // TODO find the correct IP address
170 Ethernet arpReply = buildArpReply(dst.ipAddresses().iterator().next(), 171 Ethernet arpReply = buildArpReply(dst.ipAddresses().iterator().next(),
171 dst.mac(), eth); 172 dst.mac(), eth);
172 // TODO: check send status with host service. 173 // TODO: check send status with host service.
......
...@@ -23,6 +23,7 @@ import org.onlab.onos.net.topology.TopologyProviderRegistry; ...@@ -23,6 +23,7 @@ import org.onlab.onos.net.topology.TopologyProviderRegistry;
23 import org.onlab.onos.net.topology.TopologyProviderService; 23 import org.onlab.onos.net.topology.TopologyProviderService;
24 import org.slf4j.Logger; 24 import org.slf4j.Logger;
25 25
26 +import java.util.Collections;
26 import java.util.List; 27 import java.util.List;
27 import java.util.Timer; 28 import java.util.Timer;
28 import java.util.concurrent.ExecutorService; 29 import java.util.concurrent.ExecutorService;
...@@ -88,7 +89,7 @@ public class DefaultTopologyProvider extends AbstractProvider ...@@ -88,7 +89,7 @@ public class DefaultTopologyProvider extends AbstractProvider
88 linkService.addListener(linkListener); 89 linkService.addListener(linkListener);
89 90
90 isStarted = true; 91 isStarted = true;
91 - triggerTopologyBuild(null); 92 + triggerTopologyBuild(Collections.<Event>emptyList());
92 log.info("Started"); 93 log.info("Started");
93 } 94 }
94 95
......
...@@ -37,6 +37,7 @@ import org.onlab.onos.net.device.PortDescription; ...@@ -37,6 +37,7 @@ import org.onlab.onos.net.device.PortDescription;
37 import org.onlab.onos.net.provider.AbstractProvider; 37 import org.onlab.onos.net.provider.AbstractProvider;
38 import org.onlab.onos.net.provider.ProviderId; 38 import org.onlab.onos.net.provider.ProviderId;
39 import org.onlab.onos.store.trivial.impl.SimpleDeviceStore; 39 import org.onlab.onos.store.trivial.impl.SimpleDeviceStore;
40 +import org.onlab.packet.ChassisId;
40 import org.onlab.packet.IpPrefix; 41 import org.onlab.packet.IpPrefix;
41 42
42 import java.util.ArrayList; 43 import java.util.ArrayList;
...@@ -62,6 +63,7 @@ public class DeviceManagerTest { ...@@ -62,6 +63,7 @@ public class DeviceManagerTest {
62 private static final String SW1 = "3.8.1"; 63 private static final String SW1 = "3.8.1";
63 private static final String SW2 = "3.9.5"; 64 private static final String SW2 = "3.9.5";
64 private static final String SN = "43311-12345"; 65 private static final String SN = "43311-12345";
66 + private static final ChassisId CID = new ChassisId();
65 67
66 private static final PortNumber P1 = PortNumber.portNumber(1); 68 private static final PortNumber P1 = PortNumber.portNumber(1);
67 private static final PortNumber P2 = PortNumber.portNumber(2); 69 private static final PortNumber P2 = PortNumber.portNumber(2);
...@@ -111,7 +113,7 @@ public class DeviceManagerTest { ...@@ -111,7 +113,7 @@ public class DeviceManagerTest {
111 private void connectDevice(DeviceId deviceId, String swVersion) { 113 private void connectDevice(DeviceId deviceId, String swVersion) {
112 DeviceDescription description = 114 DeviceDescription description =
113 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR, 115 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
114 - HW, swVersion, SN); 116 + HW, swVersion, SN, CID);
115 providerService.deviceConnected(deviceId, description); 117 providerService.deviceConnected(deviceId, description);
116 assertNotNull("device should be found", service.getDevice(DID1)); 118 assertNotNull("device should be found", service.getDevice(DID1));
117 } 119 }
......
...@@ -8,7 +8,9 @@ import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_UPDATED; ...@@ -8,7 +8,9 @@ import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_UPDATED;
8 8
9 import java.util.ArrayList; 9 import java.util.ArrayList;
10 import java.util.Collections; 10 import java.util.Collections;
11 +import java.util.HashMap;
11 import java.util.List; 12 import java.util.List;
13 +import java.util.Map;
12 import java.util.Set; 14 import java.util.Set;
13 import java.util.concurrent.ExecutionException; 15 import java.util.concurrent.ExecutionException;
14 import java.util.concurrent.Future; 16 import java.util.concurrent.Future;
...@@ -54,6 +56,7 @@ import org.onlab.onos.net.provider.ProviderId; ...@@ -54,6 +56,7 @@ import org.onlab.onos.net.provider.ProviderId;
54 import org.onlab.onos.store.trivial.impl.SimpleFlowRuleStore; 56 import org.onlab.onos.store.trivial.impl.SimpleFlowRuleStore;
55 57
56 import com.google.common.collect.ImmutableList; 58 import com.google.common.collect.ImmutableList;
59 +import com.google.common.collect.ImmutableMap;
57 import com.google.common.collect.Lists; 60 import com.google.common.collect.Lists;
58 import com.google.common.collect.Sets; 61 import com.google.common.collect.Sets;
59 62
...@@ -68,7 +71,7 @@ public class FlowRuleManagerTest { ...@@ -68,7 +71,7 @@ public class FlowRuleManagerTest {
68 private static final DeviceId DID = DeviceId.deviceId("of:001"); 71 private static final DeviceId DID = DeviceId.deviceId("of:001");
69 private static final int TIMEOUT = 10; 72 private static final int TIMEOUT = 10;
70 private static final Device DEV = new DefaultDevice( 73 private static final Device DEV = new DefaultDevice(
71 - PID, DID, Type.SWITCH, "", "", "", ""); 74 + PID, DID, Type.SWITCH, "", "", "", "", null);
72 75
73 private FlowRuleManager mgr; 76 private FlowRuleManager mgr;
74 77
...@@ -166,16 +169,17 @@ public class FlowRuleManagerTest { ...@@ -166,16 +169,17 @@ public class FlowRuleManagerTest {
166 } 169 }
167 170
168 171
172 + // TODO: If preserving iteration order is a requirement, redo FlowRuleStore.
169 //backing store is sensitive to the order of additions/removals 173 //backing store is sensitive to the order of additions/removals
170 - private boolean validateState(FlowEntryState... state) { 174 + private boolean validateState(Map<FlowRule, FlowEntryState> expected) {
175 + Map<FlowRule, FlowEntryState> expectedToCheck = new HashMap<>(expected);
171 Iterable<FlowEntry> rules = service.getFlowEntries(DID); 176 Iterable<FlowEntry> rules = service.getFlowEntries(DID);
172 - int i = 0;
173 for (FlowEntry f : rules) { 177 for (FlowEntry f : rules) {
174 - if (f.state() != state[i]) { 178 + assertTrue("Unexpected FlowRule " + f, expectedToCheck.containsKey(f));
175 - return false; 179 + assertEquals("FlowEntry" + f, expectedToCheck.get(f), f.state());
176 - } 180 + expectedToCheck.remove(f);
177 - i++;
178 } 181 }
182 + assertEquals(Collections.emptySet(), expectedToCheck.entrySet());
179 return true; 183 return true;
180 } 184 }
181 185
...@@ -191,8 +195,10 @@ public class FlowRuleManagerTest { ...@@ -191,8 +195,10 @@ public class FlowRuleManagerTest {
191 mgr.applyFlowRules(r1, r2, r3); 195 mgr.applyFlowRules(r1, r2, r3);
192 assertEquals("3 rules should exist", 3, flowCount()); 196 assertEquals("3 rules should exist", 3, flowCount());
193 assertTrue("Entries should be pending add.", 197 assertTrue("Entries should be pending add.",
194 - validateState(FlowEntryState.PENDING_ADD, FlowEntryState.PENDING_ADD, 198 + validateState(ImmutableMap.of(
195 - FlowEntryState.PENDING_ADD)); 199 + r1, FlowEntryState.PENDING_ADD,
200 + r2, FlowEntryState.PENDING_ADD,
201 + r3, FlowEntryState.PENDING_ADD)));
196 } 202 }
197 203
198 @Test 204 @Test
...@@ -213,8 +219,10 @@ public class FlowRuleManagerTest { ...@@ -213,8 +219,10 @@ public class FlowRuleManagerTest {
213 validateEvents(); 219 validateEvents();
214 assertEquals("3 rule should exist", 3, flowCount()); 220 assertEquals("3 rule should exist", 3, flowCount());
215 assertTrue("Entries should be pending remove.", 221 assertTrue("Entries should be pending remove.",
216 - validateState(FlowEntryState.PENDING_REMOVE, FlowEntryState.PENDING_REMOVE, 222 + validateState(ImmutableMap.of(
217 - FlowEntryState.ADDED)); 223 + f1, FlowEntryState.PENDING_REMOVE,
224 + f2, FlowEntryState.PENDING_REMOVE,
225 + f3, FlowEntryState.ADDED)));
218 226
219 mgr.removeFlowRules(f1); 227 mgr.removeFlowRules(f1);
220 assertEquals("3 rule should still exist", 3, flowCount()); 228 assertEquals("3 rule should still exist", 3, flowCount());
...@@ -263,8 +271,10 @@ public class FlowRuleManagerTest { ...@@ -263,8 +271,10 @@ public class FlowRuleManagerTest {
263 providerService.pushFlowMetrics(DID, Lists.newArrayList(fe1, fe2)); 271 providerService.pushFlowMetrics(DID, Lists.newArrayList(fe1, fe2));
264 272
265 assertTrue("Entries should be added.", 273 assertTrue("Entries should be added.",
266 - validateState(FlowEntryState.ADDED, FlowEntryState.ADDED, 274 + validateState(ImmutableMap.of(
267 - FlowEntryState.PENDING_ADD)); 275 + f1, FlowEntryState.ADDED,
276 + f2, FlowEntryState.ADDED,
277 + f3, FlowEntryState.PENDING_ADD)));
268 278
269 validateEvents(RULE_ADDED, RULE_ADDED); 279 validateEvents(RULE_ADDED, RULE_ADDED);
270 } 280 }
...@@ -336,7 +346,9 @@ public class FlowRuleManagerTest { ...@@ -336,7 +346,9 @@ public class FlowRuleManagerTest {
336 346
337 //only check that we are in pending remove. Events and actual remove state will 347 //only check that we are in pending remove. Events and actual remove state will
338 // be set by flowRemoved call. 348 // be set by flowRemoved call.
339 - validateState(FlowEntryState.PENDING_REMOVE, FlowEntryState.PENDING_REMOVE); 349 + validateState(ImmutableMap.of(
350 + f1, FlowEntryState.PENDING_REMOVE,
351 + f2, FlowEntryState.PENDING_REMOVE));
340 } 352 }
341 353
342 @Test 354 @Test
...@@ -360,7 +372,9 @@ public class FlowRuleManagerTest { ...@@ -360,7 +372,9 @@ public class FlowRuleManagerTest {
360 Lists.newArrayList(fbe1, fbe2)); 372 Lists.newArrayList(fbe1, fbe2));
361 Future<CompletedBatchOperation> future = mgr.applyBatch(fbo); 373 Future<CompletedBatchOperation> future = mgr.applyBatch(fbo);
362 assertTrue("Entries in wrong state", 374 assertTrue("Entries in wrong state",
363 - validateState(FlowEntryState.PENDING_REMOVE, FlowEntryState.PENDING_ADD)); 375 + validateState(ImmutableMap.of(
376 + f1, FlowEntryState.PENDING_REMOVE,
377 + f2, FlowEntryState.PENDING_ADD)));
364 CompletedBatchOperation completed = null; 378 CompletedBatchOperation completed = null;
365 try { 379 try {
366 completed = future.get(); 380 completed = future.get();
...@@ -381,9 +395,18 @@ public class FlowRuleManagerTest { ...@@ -381,9 +395,18 @@ public class FlowRuleManagerTest {
381 395
382 mgr.applyFlowRules(f1); 396 mgr.applyFlowRules(f1);
383 397
398 + assertTrue("Entries in wrong state",
399 + validateState(ImmutableMap.of(
400 + f1, FlowEntryState.PENDING_ADD)));
401 +
384 FlowEntry fe1 = new DefaultFlowEntry(f1); 402 FlowEntry fe1 = new DefaultFlowEntry(f1);
385 providerService.pushFlowMetrics(DID, Collections.<FlowEntry>singletonList(fe1)); 403 providerService.pushFlowMetrics(DID, Collections.<FlowEntry>singletonList(fe1));
386 404
405 + assertTrue("Entries in wrong state",
406 + validateState(ImmutableMap.of(
407 + f1, FlowEntryState.ADDED)));
408 +
409 +
387 FlowRuleBatchEntry fbe1 = new FlowRuleBatchEntry( 410 FlowRuleBatchEntry fbe1 = new FlowRuleBatchEntry(
388 FlowRuleBatchEntry.FlowRuleOperation.REMOVE, f1); 411 FlowRuleBatchEntry.FlowRuleOperation.REMOVE, f1);
389 412
...@@ -403,9 +426,9 @@ public class FlowRuleManagerTest { ...@@ -403,9 +426,9 @@ public class FlowRuleManagerTest {
403 * state. 426 * state.
404 */ 427 */
405 assertTrue("Entries in wrong state", 428 assertTrue("Entries in wrong state",
406 - validateState(FlowEntryState.PENDING_REMOVE, 429 + validateState(ImmutableMap.of(
407 - FlowEntryState.PENDING_ADD)); 430 + f2, FlowEntryState.PENDING_REMOVE,
408 - 431 + f1, FlowEntryState.PENDING_ADD)));
409 432
410 433
411 } 434 }
......
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 +}
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;
2 +
3 +import org.junit.Test;
4 +import org.onlab.onos.net.ConnectPoint;
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.connectPoint;
13 +
14 +/**
15 + * Unit tests for the HostToHostIntent class.
16 + */
17 +public class TestPointToPointIntent {
18 +
19 + private TrafficSelector selector = new IntentTestsMocks.MockSelector();
20 + private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment();
21 +
22 + private ConnectPoint point1 = connectPoint("dev1", 1);
23 + private ConnectPoint point2 = connectPoint("dev2", 1);
24 +
25 + private PointToPointIntent makePointToPoint(long id,
26 + ConnectPoint ingress,
27 + ConnectPoint egress) {
28 + return new PointToPointIntent(new IntentId(id),
29 + selector,
30 + treatment,
31 + ingress,
32 + egress);
33 + }
34 +
35 + /**
36 + * Tests the equals() method where two PointToPointIntents have references
37 + * to the same ingress and egress points. These should compare equal.
38 + */
39 + @Test
40 + public void testSameEquals() {
41 + PointToPointIntent i1 = makePointToPoint(12, point1, point2);
42 + PointToPointIntent i2 = makePointToPoint(12, point1, point2);
43 +
44 + assertThat(i1, is(equalTo(i2)));
45 + }
46 +
47 + /**
48 + * Tests the equals() method where two HostToHostIntents have references
49 + * to different Hosts. These should compare not equal.
50 + */
51 + @Test
52 + public void testLinksDifferentEquals() {
53 +
54 + PointToPointIntent i1 = makePointToPoint(12, point1, point2);
55 + PointToPointIntent i2 = makePointToPoint(12, point2, point1);
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 + @Test
65 + public void testBaseDifferentEquals() {
66 + PointToPointIntent i1 = makePointToPoint(12, point1, point2);
67 + PointToPointIntent i2 = makePointToPoint(11, point1, point2);
68 +
69 +
70 + assertThat(i1, is(not(equalTo(i2))));
71 + }
72 +
73 + /**
74 + * Tests that the hashCode() values for two equivalent HostToHostIntent
75 + * objects are the same.
76 + */
77 + @Test
78 + public void testHashCodeEquals() {
79 + PointToPointIntent i1 = makePointToPoint(12, point1, point2);
80 + PointToPointIntent i2 = makePointToPoint(12, point1, point2);
81 +
82 + assertThat(i1.hashCode(), is(equalTo(i2.hashCode())));
83 + }
84 +
85 + /**
86 + * Tests that the hashCode() values for two distinct LinkCollectionIntent
87 + * objects are different.
88 + */
89 + @Test
90 + public void testHashCodeDifferent() {
91 + PointToPointIntent i1 = makePointToPoint(12, point1, point2);
92 + PointToPointIntent i2 = makePointToPoint(22, point1, point2);
93 +
94 + assertThat(i1.hashCode(), is(not(equalTo(i2.hashCode()))));
95 + }
96 +}
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 +}
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 +}
1 +package org.onlab.onos.net.intent.impl;
2 +
3 +import java.util.List;
4 +
5 +import org.hamcrest.Matchers;
6 +import org.junit.Test;
7 +import org.onlab.onos.net.flow.TrafficSelector;
8 +import org.onlab.onos.net.flow.TrafficTreatment;
9 +import org.onlab.onos.net.intent.Intent;
10 +import org.onlab.onos.net.intent.IntentId;
11 +import org.onlab.onos.net.intent.IntentTestsMocks;
12 +import org.onlab.onos.net.intent.PathIntent;
13 +import org.onlab.onos.net.intent.PointToPointIntent;
14 +
15 +import static org.hamcrest.CoreMatchers.notNullValue;
16 +import static org.hamcrest.MatcherAssert.assertThat;
17 +import static org.hamcrest.Matchers.hasSize;
18 +import static org.hamcrest.Matchers.is;
19 +import static org.onlab.onos.net.NetTestTools.connectPoint;
20 +import static org.onlab.onos.net.intent.LinksHaveEntryWithSourceDestinationPairMatcher.linksHasPath;
21 +
22 +/**
23 + * Unit tests for the HostToHost intent compiler.
24 + */
25 +public class TestPointToPointIntentCompiler {
26 +
27 + private TrafficSelector selector = new IntentTestsMocks.MockSelector();
28 + private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment();
29 +
30 + /**
31 + * Creates a PointToPoint intent based on ingress and egress device Ids.
32 + *
33 + * @param ingressIdString string for id of ingress device
34 + * @param egressIdString string for id of egress device
35 + * @return PointToPointIntent for the two devices
36 + */
37 + private PointToPointIntent makeIntent(String ingressIdString,
38 + String egressIdString) {
39 + return new PointToPointIntent(new IntentId(12),
40 + selector,
41 + treatment,
42 + connectPoint(ingressIdString, 1),
43 + connectPoint(egressIdString, 1));
44 + }
45 +
46 + /**
47 + * Creates a compiler for HostToHost intents.
48 + *
49 + * @param hops string array describing the path hops to use when compiling
50 + * @return HostToHost intent compiler
51 + */
52 + private PointToPointIntentCompiler makeCompiler(String[] hops) {
53 + PointToPointIntentCompiler compiler =
54 + new PointToPointIntentCompiler();
55 + compiler.pathService = new IntentTestsMocks.MockPathService(hops);
56 + IdBlockAllocator idBlockAllocator = new DummyIdBlockAllocator();
57 + compiler.intentIdGenerator =
58 + new IdBlockAllocatorBasedIntentIdGenerator(idBlockAllocator);
59 + return compiler;
60 + }
61 +
62 +
63 + /**
64 + * Tests a pair of devices in an 8 hop path, forward direction.
65 + */
66 + @Test
67 + public void testForwardPathCompilation() {
68 +
69 + PointToPointIntent intent = makeIntent("d1", "d8");
70 + assertThat(intent, is(notNullValue()));
71 +
72 + String[] hops = {"d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8"};
73 + PointToPointIntentCompiler compiler = makeCompiler(hops);
74 + assertThat(compiler, is(notNullValue()));
75 +
76 + List<Intent> result = compiler.compile(intent);
77 + assertThat(result, is(Matchers.notNullValue()));
78 + assertThat(result, hasSize(1));
79 + Intent forwardResultIntent = result.get(0);
80 + assertThat(forwardResultIntent instanceof PathIntent, is(true));
81 +
82 + if (forwardResultIntent instanceof PathIntent) {
83 + PathIntent forwardPathIntent = (PathIntent) forwardResultIntent;
84 + // 7 links for the hops, plus one default lnk on ingress and egress
85 + assertThat(forwardPathIntent.path().links(), hasSize(hops.length + 1));
86 + assertThat(forwardPathIntent.path().links(), linksHasPath("d1", "d2"));
87 + assertThat(forwardPathIntent.path().links(), linksHasPath("d2", "d3"));
88 + assertThat(forwardPathIntent.path().links(), linksHasPath("d3", "d4"));
89 + assertThat(forwardPathIntent.path().links(), linksHasPath("d4", "d5"));
90 + assertThat(forwardPathIntent.path().links(), linksHasPath("d5", "d6"));
91 + assertThat(forwardPathIntent.path().links(), linksHasPath("d6", "d7"));
92 + assertThat(forwardPathIntent.path().links(), linksHasPath("d7", "d8"));
93 + }
94 + }
95 +
96 + /**
97 + * Tests a pair of devices in an 8 hop path, forward direction.
98 + */
99 + @Test
100 + public void testReversePathCompilation() {
101 +
102 + PointToPointIntent intent = makeIntent("d8", "d1");
103 + assertThat(intent, is(notNullValue()));
104 +
105 + String[] hops = {"d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8"};
106 + PointToPointIntentCompiler compiler = makeCompiler(hops);
107 + assertThat(compiler, is(notNullValue()));
108 +
109 + List<Intent> result = compiler.compile(intent);
110 + assertThat(result, is(Matchers.notNullValue()));
111 + assertThat(result, hasSize(1));
112 + Intent reverseResultIntent = result.get(0);
113 + assertThat(reverseResultIntent instanceof PathIntent, is(true));
114 +
115 + if (reverseResultIntent instanceof PathIntent) {
116 + PathIntent reversePathIntent = (PathIntent) reverseResultIntent;
117 + assertThat(reversePathIntent.path().links(), hasSize(hops.length + 1));
118 + assertThat(reversePathIntent.path().links(), linksHasPath("d2", "d1"));
119 + assertThat(reversePathIntent.path().links(), linksHasPath("d3", "d2"));
120 + assertThat(reversePathIntent.path().links(), linksHasPath("d4", "d3"));
121 + assertThat(reversePathIntent.path().links(), linksHasPath("d5", "d4"));
122 + assertThat(reversePathIntent.path().links(), linksHasPath("d6", "d5"));
123 + assertThat(reversePathIntent.path().links(), linksHasPath("d7", "d6"));
124 + assertThat(reversePathIntent.path().links(), linksHasPath("d8", "d7"));
125 + }
126 + }
127 +}
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
20 <module>api</module> 20 <module>api</module>
21 <module>net</module> 21 <module>net</module>
22 <module>store</module> 22 <module>store</module>
23 + <module>json</module>
23 </modules> 24 </modules>
24 25
25 <dependencies> 26 <dependencies>
......
...@@ -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>
...@@ -67,15 +52,12 @@ ...@@ -67,15 +52,12 @@
67 <artifactId>easymock</artifactId> 52 <artifactId>easymock</artifactId>
68 <scope>test</scope> 53 <scope>test</scope>
69 </dependency> 54 </dependency>
55 + <dependency>
56 + <groupId>org.onlab.onos</groupId>
57 + <artifactId>onos-api</artifactId>
58 + <classifier>tests</classifier>
59 + <scope>test</scope>
60 + </dependency>
70 </dependencies> 61 </dependencies>
71 62
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> 63 </project>
......
...@@ -4,6 +4,9 @@ import static com.google.common.base.Preconditions.checkArgument; ...@@ -4,6 +4,9 @@ import static com.google.common.base.Preconditions.checkArgument;
4 4
5 import java.io.IOException; 5 import java.io.IOException;
6 import java.util.Set; 6 import java.util.Set;
7 +import java.util.concurrent.TimeUnit;
8 +import java.util.concurrent.TimeoutException;
9 +
7 import org.apache.felix.scr.annotations.Activate; 10 import org.apache.felix.scr.annotations.Activate;
8 import org.apache.felix.scr.annotations.Component; 11 import org.apache.felix.scr.annotations.Component;
9 import org.apache.felix.scr.annotations.Deactivate; 12 import org.apache.felix.scr.annotations.Deactivate;
...@@ -17,6 +20,7 @@ import org.onlab.onos.store.cluster.impl.ClusterMembershipEvent; ...@@ -17,6 +20,7 @@ import org.onlab.onos.store.cluster.impl.ClusterMembershipEvent;
17 import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService; 20 import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService;
18 import org.onlab.onos.store.cluster.messaging.ClusterMessage; 21 import org.onlab.onos.store.cluster.messaging.ClusterMessage;
19 import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler; 22 import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler;
23 +import org.onlab.onos.store.cluster.messaging.ClusterMessageResponse;
20 import org.onlab.onos.store.cluster.messaging.MessageSubject; 24 import org.onlab.onos.store.cluster.messaging.MessageSubject;
21 import org.onlab.onos.store.serializers.ClusterMessageSerializer; 25 import org.onlab.onos.store.serializers.ClusterMessageSerializer;
22 import org.onlab.onos.store.serializers.KryoPoolUtil; 26 import org.onlab.onos.store.serializers.KryoPoolUtil;
...@@ -28,6 +32,7 @@ import org.onlab.netty.Message; ...@@ -28,6 +32,7 @@ import org.onlab.netty.Message;
28 import org.onlab.netty.MessageHandler; 32 import org.onlab.netty.MessageHandler;
29 import org.onlab.netty.MessagingService; 33 import org.onlab.netty.MessagingService;
30 import org.onlab.netty.NettyMessagingService; 34 import org.onlab.netty.NettyMessagingService;
35 +import org.onlab.netty.Response;
31 import org.slf4j.Logger; 36 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory; 37 import org.slf4j.LoggerFactory;
33 38
...@@ -114,7 +119,23 @@ public class ClusterCommunicationManager ...@@ -114,7 +119,23 @@ public class ClusterCommunicationManager
114 message.subject().value(), SERIALIZER.encode(message)); 119 message.subject().value(), SERIALIZER.encode(message));
115 return true; 120 return true;
116 } catch (IOException e) { 121 } catch (IOException e) {
117 - log.error("Failed to send cluster message to nodeId: " + toNodeId, e); 122 + log.trace("Failed to send cluster message to nodeId: " + toNodeId, e);
123 + throw e;
124 + }
125 + }
126 +
127 + @Override
128 + public ClusterMessageResponse sendAndReceive(ClusterMessage message, NodeId toNodeId) throws IOException {
129 + ControllerNode node = clusterService.getNode(toNodeId);
130 + checkArgument(node != null, "Unknown nodeId: %s", toNodeId);
131 + Endpoint nodeEp = new Endpoint(node.ip().toString(), node.tcpPort());
132 + try {
133 + Response responseFuture =
134 + messagingService.sendAndReceive(nodeEp, message.subject().value(), SERIALIZER.encode(message));
135 + return new InternalClusterMessageResponse(toNodeId, responseFuture);
136 +
137 + } catch (IOException e) {
138 + log.error("Failed interaction with remote nodeId: " + toNodeId, e);
118 throw e; 139 throw e;
119 } 140 }
120 } 141 }
...@@ -137,11 +158,52 @@ public class ClusterCommunicationManager ...@@ -137,11 +158,52 @@ public class ClusterCommunicationManager
137 public void handle(Message message) { 158 public void handle(Message message) {
138 try { 159 try {
139 ClusterMessage clusterMessage = SERIALIZER.decode(message.payload()); 160 ClusterMessage clusterMessage = SERIALIZER.decode(message.payload());
140 - handler.handle(clusterMessage); 161 + handler.handle(new InternalClusterMessage(clusterMessage, message));
141 } catch (Exception e) { 162 } catch (Exception e) {
142 log.error("Exception caught during ClusterMessageHandler", e); 163 log.error("Exception caught during ClusterMessageHandler", e);
143 throw e; 164 throw e;
144 } 165 }
145 } 166 }
146 } 167 }
168 +
169 + public static final class InternalClusterMessage extends ClusterMessage {
170 +
171 + private final Message rawMessage;
172 +
173 + public InternalClusterMessage(ClusterMessage clusterMessage, Message rawMessage) {
174 + super(clusterMessage.sender(), clusterMessage.subject(), clusterMessage.payload());
175 + this.rawMessage = rawMessage;
176 + }
177 +
178 + @Override
179 + public void respond(byte[] response) throws IOException {
180 + rawMessage.respond(response);
181 + }
182 + }
183 +
184 + private static final class InternalClusterMessageResponse implements ClusterMessageResponse {
185 +
186 + private final NodeId sender;
187 + private final Response responseFuture;
188 +
189 + public InternalClusterMessageResponse(NodeId sender, Response responseFuture) {
190 + this.sender = sender;
191 + this.responseFuture = responseFuture;
192 + }
193 + @Override
194 + public NodeId sender() {
195 + return sender;
196 + }
197 +
198 + @Override
199 + public byte[] get(long timeout, TimeUnit timeunit)
200 + throws TimeoutException {
201 + return responseFuture.get(timeout, timeunit);
202 + }
203 +
204 + @Override
205 + public byte[] get(long timeout) throws InterruptedException {
206 + return responseFuture.get();
207 + }
208 + }
147 } 209 }
......
1 -/**
2 - * Common abstractions and facilities for implementing distributed store
3 - * using gossip protocol.
4 - */
5 -package org.onlab.onos.store.common.impl;
...@@ -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,9 +38,10 @@ import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService; ...@@ -38,9 +38,10 @@ 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.util.KryoPool; 45 import org.onlab.util.KryoPool;
45 import org.onlab.util.NewConcurrentHashMap; 46 import org.onlab.util.NewConcurrentHashMap;
46 import org.slf4j.Logger; 47 import org.slf4j.Logger;
...@@ -746,6 +747,7 @@ public class GossipDeviceStore ...@@ -746,6 +747,7 @@ public class GossipDeviceStore
746 String hwVersion = base.hwVersion(); 747 String hwVersion = base.hwVersion();
747 String swVersion = base.swVersion(); 748 String swVersion = base.swVersion();
748 String serialNumber = base.serialNumber(); 749 String serialNumber = base.serialNumber();
750 + ChassisId chassisId = base.chassisId();
749 DefaultAnnotations annotations = DefaultAnnotations.builder().build(); 751 DefaultAnnotations annotations = DefaultAnnotations.builder().build();
750 annotations = merge(annotations, base.annotations()); 752 annotations = merge(annotations, base.annotations());
751 753
...@@ -763,7 +765,8 @@ public class GossipDeviceStore ...@@ -763,7 +765,8 @@ public class GossipDeviceStore
763 } 765 }
764 766
765 return new DefaultDevice(primary, deviceId , type, manufacturer, 767 return new DefaultDevice(primary, deviceId , type, manufacturer,
766 - hwVersion, swVersion, serialNumber, annotations); 768 + hwVersion, swVersion, serialNumber,
769 + chassisId, annotations);
767 } 770 }
768 771
769 /** 772 /**
...@@ -1137,7 +1140,7 @@ public class GossipDeviceStore ...@@ -1137,7 +1140,7 @@ public class GossipDeviceStore
1137 try { 1140 try {
1138 unicastMessage(peer, DEVICE_ADVERTISE, ad); 1141 unicastMessage(peer, DEVICE_ADVERTISE, ad);
1139 } catch (IOException e) { 1142 } catch (IOException e) {
1140 - log.error("Failed to send anti-entropy advertisement", e); 1143 + log.debug("Failed to send anti-entropy advertisement to {}", peer);
1141 return; 1144 return;
1142 } 1145 }
1143 } catch (Exception e) { 1146 } catch (Exception e) {
......
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 /** 1 /**
2 - * Implementation of device store using distributed distributed p2p synchronization protocol. 2 + * Implementation of distributed device store using p2p synchronization protocol.
3 */ 3 */
4 package org.onlab.onos.store.device.impl; 4 package org.onlab.onos.store.device.impl;
......
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.event.EventListener;
4 +
5 +/**
6 + * Entity capable of receiving Replica placement information-related events.
7 + */
8 +public interface ReplicaInfoEventListener extends EventListener<ReplicaInfoEvent> {
9 +
10 +}
11 +
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 +
19 + /**
20 + * Adds the specified replica placement info change listener.
21 + *
22 + * @param listener the replica placement info change listener
23 + */
24 + void addListener(ReplicaInfoEventListener listener);
25 +
26 + /**
27 + * Removes the specified replica placement info change listener.
28 + *
29 + * @param listener the replica placement info change listener
30 + */
31 + void removeListener(ReplicaInfoEventListener listener);
32 +
33 +}
...@@ -3,14 +3,20 @@ package org.onlab.onos.store.flow.impl; ...@@ -3,14 +3,20 @@ package org.onlab.onos.store.flow.impl;
3 import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; 3 import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
4 import static org.slf4j.LoggerFactory.getLogger; 4 import static org.slf4j.LoggerFactory.getLogger;
5 5
6 +import java.io.IOException;
6 import java.util.Collection; 7 import java.util.Collection;
7 import java.util.Collections; 8 import java.util.Collections;
9 +import java.util.concurrent.TimeUnit;
10 +import java.util.concurrent.TimeoutException;
8 11
9 import org.apache.felix.scr.annotations.Activate; 12 import org.apache.felix.scr.annotations.Activate;
10 import org.apache.felix.scr.annotations.Component; 13 import org.apache.felix.scr.annotations.Component;
11 import org.apache.felix.scr.annotations.Deactivate; 14 import org.apache.felix.scr.annotations.Deactivate;
15 +import org.apache.felix.scr.annotations.Reference;
16 +import org.apache.felix.scr.annotations.ReferenceCardinality;
12 import org.apache.felix.scr.annotations.Service; 17 import org.apache.felix.scr.annotations.Service;
13 import org.onlab.onos.ApplicationId; 18 import org.onlab.onos.ApplicationId;
19 +import org.onlab.onos.cluster.ClusterService;
14 import org.onlab.onos.net.DeviceId; 20 import org.onlab.onos.net.DeviceId;
15 import org.onlab.onos.net.flow.DefaultFlowEntry; 21 import org.onlab.onos.net.flow.DefaultFlowEntry;
16 import org.onlab.onos.net.flow.FlowEntry; 22 import org.onlab.onos.net.flow.FlowEntry;
...@@ -21,6 +27,14 @@ import org.onlab.onos.net.flow.FlowRuleEvent.Type; ...@@ -21,6 +27,14 @@ import org.onlab.onos.net.flow.FlowRuleEvent.Type;
21 import org.onlab.onos.net.flow.FlowRuleStore; 27 import org.onlab.onos.net.flow.FlowRuleStore;
22 import org.onlab.onos.net.flow.FlowRuleStoreDelegate; 28 import org.onlab.onos.net.flow.FlowRuleStoreDelegate;
23 import org.onlab.onos.store.AbstractStore; 29 import org.onlab.onos.store.AbstractStore;
30 +import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService;
31 +import org.onlab.onos.store.cluster.messaging.ClusterMessage;
32 +import org.onlab.onos.store.cluster.messaging.ClusterMessageResponse;
33 +import org.onlab.onos.store.flow.ReplicaInfo;
34 +import org.onlab.onos.store.flow.ReplicaInfoService;
35 +import org.onlab.onos.store.serializers.DistributedStoreSerializers;
36 +import org.onlab.onos.store.serializers.KryoSerializer;
37 +import org.onlab.util.KryoPool;
24 import org.slf4j.Logger; 38 import org.slf4j.Logger;
25 39
26 import com.google.common.collect.ArrayListMultimap; 40 import com.google.common.collect.ArrayListMultimap;
...@@ -28,9 +42,8 @@ import com.google.common.collect.ImmutableSet; ...@@ -28,9 +42,8 @@ import com.google.common.collect.ImmutableSet;
28 import com.google.common.collect.Multimap; 42 import com.google.common.collect.Multimap;
29 43
30 /** 44 /**
31 - * Manages inventory of flow rules using trivial in-memory implementation. 45 + * Manages inventory of flow rules using a distributed state management protocol.
32 */ 46 */
33 -//FIXME I LIE. I AIN'T DISTRIBUTED
34 @Component(immediate = true) 47 @Component(immediate = true)
35 @Service 48 @Service
36 public class DistributedFlowRuleStore 49 public class DistributedFlowRuleStore
...@@ -46,6 +59,28 @@ public class DistributedFlowRuleStore ...@@ -46,6 +59,28 @@ public class DistributedFlowRuleStore
46 private final Multimap<Short, FlowRule> flowEntriesById = 59 private final Multimap<Short, FlowRule> flowEntriesById =
47 ArrayListMultimap.<Short, FlowRule>create(); 60 ArrayListMultimap.<Short, FlowRule>create();
48 61
62 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
63 + private ReplicaInfoService replicaInfoManager;
64 +
65 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
66 + private ClusterCommunicationService clusterCommunicator;
67 +
68 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
69 + private ClusterService clusterService;
70 +
71 + protected static final KryoSerializer SERIALIZER = new KryoSerializer() {
72 + @Override
73 + protected void setupKryoPool() {
74 + serializerPool = KryoPool.newBuilder()
75 + .register(DistributedStoreSerializers.COMMON)
76 + .build()
77 + .populate(1);
78 + }
79 + };
80 +
81 + // TODO: make this configurable
82 + private static final long FLOW_RULE_STORE_TIMEOUT_MILLIS = 1000;
83 +
49 @Activate 84 @Activate
50 public void activate() { 85 public void activate() {
51 log.info("Started"); 86 log.info("Started");
...@@ -91,26 +126,92 @@ public class DistributedFlowRuleStore ...@@ -91,26 +126,92 @@ public class DistributedFlowRuleStore
91 } 126 }
92 127
93 @Override 128 @Override
94 - public synchronized void storeFlowRule(FlowRule rule) { 129 + public void storeFlowRule(FlowRule rule) {
95 - FlowEntry f = new DefaultFlowEntry(rule); 130 + ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(rule.deviceId());
96 - DeviceId did = f.deviceId(); 131 + if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) {
97 - if (!flowEntries.containsEntry(did, f)) { 132 + storeFlowEntryInternal(rule);
98 - flowEntries.put(did, f); 133 + return;
99 - flowEntriesById.put(rule.appId(), f);
100 } 134 }
135 +
136 + ClusterMessage message = new ClusterMessage(
137 + clusterService.getLocalNode().id(),
138 + FlowStoreMessageSubjects.STORE_FLOW_RULE,
139 + SERIALIZER.encode(rule));
140 +
141 + try {
142 + ClusterMessageResponse response = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get());
143 + response.get(FLOW_RULE_STORE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
144 + } catch (IOException | TimeoutException e) {
145 + // FIXME: throw a FlowStoreException
146 + throw new RuntimeException(e);
147 + }
148 + }
149 +
150 + private synchronized void storeFlowEntryInternal(FlowRule flowRule) {
151 + FlowEntry flowEntry = new DefaultFlowEntry(flowRule);
152 + DeviceId deviceId = flowRule.deviceId();
153 + // write to local copy.
154 + if (!flowEntries.containsEntry(deviceId, flowEntry)) {
155 + flowEntries.put(deviceId, flowEntry);
156 + flowEntriesById.put(flowRule.appId(), flowEntry);
157 + }
158 + // write to backup.
159 + // TODO: write to a hazelcast map.
101 } 160 }
102 161
103 @Override 162 @Override
104 public synchronized void deleteFlowRule(FlowRule rule) { 163 public synchronized void deleteFlowRule(FlowRule rule) {
105 - FlowEntry entry = getFlowEntry(rule); 164 + ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(rule.deviceId());
165 + if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) {
166 + deleteFlowRuleInternal(rule);
167 + return;
168 + }
169 +
170 + ClusterMessage message = new ClusterMessage(
171 + clusterService.getLocalNode().id(),
172 + FlowStoreMessageSubjects.DELETE_FLOW_RULE,
173 + SERIALIZER.encode(rule));
174 +
175 + try {
176 + ClusterMessageResponse response = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get());
177 + response.get(FLOW_RULE_STORE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
178 + } catch (IOException | TimeoutException e) {
179 + // FIXME: throw a FlowStoreException
180 + throw new RuntimeException(e);
181 + }
182 + }
183 +
184 + private synchronized void deleteFlowRuleInternal(FlowRule flowRule) {
185 + FlowEntry entry = getFlowEntry(flowRule);
106 if (entry == null) { 186 if (entry == null) {
107 return; 187 return;
108 } 188 }
109 entry.setState(FlowEntryState.PENDING_REMOVE); 189 entry.setState(FlowEntryState.PENDING_REMOVE);
190 + // TODO: also update backup.
110 } 191 }
111 192
112 @Override 193 @Override
113 - public synchronized FlowRuleEvent addOrUpdateFlowRule(FlowEntry rule) { 194 + public FlowRuleEvent addOrUpdateFlowRule(FlowEntry rule) {
195 + ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(rule.deviceId());
196 + if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) {
197 + return addOrUpdateFlowRuleInternal(rule);
198 + }
199 +
200 + ClusterMessage message = new ClusterMessage(
201 + clusterService.getLocalNode().id(),
202 + FlowStoreMessageSubjects.ADD_OR_UPDATE_FLOW_RULE,
203 + SERIALIZER.encode(rule));
204 +
205 + try {
206 + ClusterMessageResponse response = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get());
207 + return SERIALIZER.decode(response.get(FLOW_RULE_STORE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
208 + } catch (IOException | TimeoutException e) {
209 + // FIXME: throw a FlowStoreException
210 + throw new RuntimeException(e);
211 + }
212 + }
213 +
214 + private synchronized FlowRuleEvent addOrUpdateFlowRuleInternal(FlowEntry rule) {
114 DeviceId did = rule.deviceId(); 215 DeviceId did = rule.deviceId();
115 216
116 // check if this new rule is an update to an existing entry 217 // check if this new rule is an update to an existing entry
...@@ -128,15 +229,39 @@ public class DistributedFlowRuleStore ...@@ -128,15 +229,39 @@ public class DistributedFlowRuleStore
128 229
129 flowEntries.put(did, rule); 230 flowEntries.put(did, rule);
130 return null; 231 return null;
232 +
233 + // TODO: also update backup.
131 } 234 }
132 235
133 @Override 236 @Override
134 - public synchronized FlowRuleEvent removeFlowRule(FlowEntry rule) { 237 + public FlowRuleEvent removeFlowRule(FlowEntry rule) {
238 + ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(rule.deviceId());
239 + if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) {
240 + // bypass and handle it locally
241 + return removeFlowRuleInternal(rule);
242 + }
243 +
244 + ClusterMessage message = new ClusterMessage(
245 + clusterService.getLocalNode().id(),
246 + FlowStoreMessageSubjects.REMOVE_FLOW_RULE,
247 + SERIALIZER.encode(rule));
248 +
249 + try {
250 + ClusterMessageResponse response = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get());
251 + return SERIALIZER.decode(response.get(FLOW_RULE_STORE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
252 + } catch (IOException | TimeoutException e) {
253 + // FIXME: throw a FlowStoreException
254 + throw new RuntimeException(e);
255 + }
256 + }
257 +
258 + private synchronized FlowRuleEvent removeFlowRuleInternal(FlowEntry rule) {
135 // This is where one could mark a rule as removed and still keep it in the store. 259 // This is where one could mark a rule as removed and still keep it in the store.
136 if (flowEntries.remove(rule.deviceId(), rule)) { 260 if (flowEntries.remove(rule.deviceId(), rule)) {
137 return new FlowRuleEvent(RULE_REMOVED, rule); 261 return new FlowRuleEvent(RULE_REMOVED, rule);
138 } else { 262 } else {
139 return null; 263 return null;
140 } 264 }
265 + // TODO: also update backup.
141 } 266 }
142 } 267 }
......
1 +package org.onlab.onos.store.flow.impl;
2 +
3 +import org.onlab.onos.store.cluster.messaging.MessageSubject;
4 +
5 +/**
6 + * MessageSubjects used by DistributedFlowRuleStore peer-peer communication.
7 + */
8 +public final class FlowStoreMessageSubjects {
9 + private FlowStoreMessageSubjects() {}
10 + public static final MessageSubject STORE_FLOW_RULE = new MessageSubject("peer-forward-store-flow-rule");
11 + public static final MessageSubject DELETE_FLOW_RULE = new MessageSubject("peer-forward-delete-flow-rule");
12 + public static final MessageSubject ADD_OR_UPDATE_FLOW_RULE =
13 + new MessageSubject("peer-forward-add-or-update-flow-rule");
14 + public static final MessageSubject REMOVE_FLOW_RULE = new MessageSubject("peer-forward-remove-flow-rule");
15 +}
1 +package org.onlab.onos.store.flow.impl;
2 +
3 +import static com.google.common.base.Preconditions.checkNotNull;
4 +import static org.slf4j.LoggerFactory.getLogger;
5 +import static org.onlab.onos.store.flow.ReplicaInfoEvent.Type.MASTER_CHANGED;
6 +
7 +import java.util.Collections;
8 +import java.util.List;
9 +
10 +import org.apache.felix.scr.annotations.Activate;
11 +import org.apache.felix.scr.annotations.Component;
12 +import org.apache.felix.scr.annotations.Deactivate;
13 +import org.apache.felix.scr.annotations.Reference;
14 +import org.apache.felix.scr.annotations.ReferenceCardinality;
15 +import org.apache.felix.scr.annotations.Service;
16 +import org.onlab.onos.cluster.NodeId;
17 +import org.onlab.onos.event.AbstractListenerRegistry;
18 +import org.onlab.onos.event.EventDeliveryService;
19 +import org.onlab.onos.mastership.MastershipEvent;
20 +import org.onlab.onos.mastership.MastershipListener;
21 +import org.onlab.onos.mastership.MastershipService;
22 +import org.onlab.onos.net.DeviceId;
23 +import org.onlab.onos.store.flow.ReplicaInfo;
24 +import org.onlab.onos.store.flow.ReplicaInfoEvent;
25 +import org.onlab.onos.store.flow.ReplicaInfoEventListener;
26 +import org.onlab.onos.store.flow.ReplicaInfoService;
27 +import org.slf4j.Logger;
28 +
29 +/**
30 + * Manages replica placement information.
31 + */
32 +@Component(immediate = true)
33 +@Service
34 +public class ReplicaInfoManager implements ReplicaInfoService {
35 +
36 + private final Logger log = getLogger(getClass());
37 +
38 + private final MastershipListener mastershipListener = new InternalMastershipListener();
39 +
40 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
41 + protected EventDeliveryService eventDispatcher;
42 +
43 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
44 + protected MastershipService mastershipService;
45 +
46 + protected final AbstractListenerRegistry<ReplicaInfoEvent, ReplicaInfoEventListener>
47 + listenerRegistry = new AbstractListenerRegistry<>();
48 +
49 + @Activate
50 + public void activate() {
51 + eventDispatcher.addSink(ReplicaInfoEvent.class, listenerRegistry);
52 + mastershipService.addListener(mastershipListener);
53 + log.info("Started");
54 + }
55 +
56 + @Deactivate
57 + public void deactivate() {
58 + eventDispatcher.removeSink(ReplicaInfoEvent.class);
59 + mastershipService.removeListener(mastershipListener);
60 + log.info("Stopped");
61 + }
62 +
63 + @Override
64 + public ReplicaInfo getReplicaInfoFor(DeviceId deviceId) {
65 + // TODO: populate backup List when we reach the point we need them.
66 + return new ReplicaInfo(mastershipService.getMasterFor(deviceId),
67 + Collections.<NodeId>emptyList());
68 + }
69 +
70 + @Override
71 + public void addListener(ReplicaInfoEventListener listener) {
72 + listenerRegistry.addListener(checkNotNull(listener));
73 + }
74 +
75 + @Override
76 + public void removeListener(ReplicaInfoEventListener listener) {
77 + listenerRegistry.removeListener(checkNotNull(listener));
78 + }
79 +
80 + final class InternalMastershipListener implements MastershipListener {
81 +
82 + @Override
83 + public void event(MastershipEvent event) {
84 + // TODO: distinguish stby list update, when MastershipService,
85 + // start publishing them
86 + final List<NodeId> standbyList = Collections.<NodeId>emptyList();
87 + eventDispatcher.post(new ReplicaInfoEvent(MASTER_CHANGED,
88 + event.subject(),
89 + new ReplicaInfo(event.master(), standbyList)));
90 + }
91 + }
92 +
93 +}
1 +/**
2 + * Implementation of the distributed flow rule store using p2p synchronization
3 + * protocol.
4 + */
5 +package org.onlab.onos.store.flow.impl;
...@@ -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.DistributedStoreSerializers; 42 import org.onlab.onos.store.serializers.DistributedStoreSerializers;
43 import org.onlab.onos.store.serializers.KryoSerializer; 43 import org.onlab.onos.store.serializers.KryoSerializer;
44 import org.onlab.packet.IpPrefix; 44 import org.onlab.packet.IpPrefix;
...@@ -534,7 +534,7 @@ public class GossipHostStore ...@@ -534,7 +534,7 @@ public class GossipHostStore
534 try { 534 try {
535 unicastMessage(peer, GossipHostStoreMessageSubjects.HOST_ANTI_ENTROPY_ADVERTISEMENT, ad); 535 unicastMessage(peer, GossipHostStoreMessageSubjects.HOST_ANTI_ENTROPY_ADVERTISEMENT, ad);
536 } catch (IOException e) { 536 } catch (IOException e) {
537 - log.debug("Failed to send anti-entropy advertisement", e); 537 + log.debug("Failed to send anti-entropy advertisement to {}", peer);
538 return; 538 return;
539 } 539 }
540 } catch (Exception e) { 540 } catch (Exception e) {
......
1 /** 1 /**
2 - * Implementation of host store using distributed p2p synchronization protocol. 2 + * Implementation of the distributed host store using p2p synchronization protocol.
3 */ 3 */
4 package org.onlab.onos.store.host.impl; 4 package org.onlab.onos.store.host.impl;
......
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
......
...@@ -39,7 +39,7 @@ import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService; ...@@ -39,7 +39,7 @@ import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService;
39 import org.onlab.onos.store.cluster.messaging.ClusterMessage; 39 import org.onlab.onos.store.cluster.messaging.ClusterMessage;
40 import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler; 40 import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler;
41 import org.onlab.onos.store.cluster.messaging.MessageSubject; 41 import org.onlab.onos.store.cluster.messaging.MessageSubject;
42 -import org.onlab.onos.store.common.impl.Timestamped; 42 +import org.onlab.onos.store.impl.Timestamped;
43 import org.onlab.onos.store.serializers.DistributedStoreSerializers; 43 import org.onlab.onos.store.serializers.DistributedStoreSerializers;
44 import org.onlab.onos.store.serializers.KryoSerializer; 44 import org.onlab.onos.store.serializers.KryoSerializer;
45 import org.onlab.util.KryoPool; 45 import org.onlab.util.KryoPool;
......
...@@ -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 /** 1 /**
2 - * Implementation of link store using distributed p2p synchronization protocol. 2 + * Implementation of distributed link store using p2p synchronization protocol.
3 */ 3 */
4 package org.onlab.onos.store.link.impl; 4 package org.onlab.onos.store.link.impl;
......
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
......
1 +/**
2 + * Implementation of distributed topology store using p2p synchronization protocol.
3 + */
4 +package org.onlab.onos.store.topology.impl;
...@@ -53,6 +53,7 @@ import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService; ...@@ -53,6 +53,7 @@ import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService;
53 import org.onlab.onos.store.cluster.messaging.ClusterMessage; 53 import org.onlab.onos.store.cluster.messaging.ClusterMessage;
54 import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler; 54 import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler;
55 import org.onlab.onos.store.cluster.messaging.MessageSubject; 55 import org.onlab.onos.store.cluster.messaging.MessageSubject;
56 +import org.onlab.packet.ChassisId;
56 import org.onlab.packet.IpPrefix; 57 import org.onlab.packet.IpPrefix;
57 58
58 import com.google.common.collect.Iterables; 59 import com.google.common.collect.Iterables;
...@@ -74,6 +75,7 @@ public class GossipDeviceStoreTest { ...@@ -74,6 +75,7 @@ public class GossipDeviceStoreTest {
74 private static final String SW1 = "3.8.1"; 75 private static final String SW1 = "3.8.1";
75 private static final String SW2 = "3.9.5"; 76 private static final String SW2 = "3.9.5";
76 private static final String SN = "43311-12345"; 77 private static final String SN = "43311-12345";
78 + private static final ChassisId CID = new ChassisId();
77 79
78 private static final PortNumber P1 = PortNumber.portNumber(1); 80 private static final PortNumber P1 = PortNumber.portNumber(1);
79 private static final PortNumber P2 = PortNumber.portNumber(2); 81 private static final PortNumber P2 = PortNumber.portNumber(2);
...@@ -158,7 +160,7 @@ public class GossipDeviceStoreTest { ...@@ -158,7 +160,7 @@ public class GossipDeviceStoreTest {
158 SparseAnnotations... annotations) { 160 SparseAnnotations... annotations) {
159 DeviceDescription description = 161 DeviceDescription description =
160 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR, 162 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
161 - HW, swVersion, SN, annotations); 163 + HW, swVersion, SN, CID, annotations);
162 reset(clusterCommunicator); 164 reset(clusterCommunicator);
163 try { 165 try {
164 expect(clusterCommunicator.broadcast(anyObject(ClusterMessage.class))) 166 expect(clusterCommunicator.broadcast(anyObject(ClusterMessage.class)))
...@@ -175,7 +177,7 @@ public class GossipDeviceStoreTest { ...@@ -175,7 +177,7 @@ public class GossipDeviceStoreTest {
175 SparseAnnotations... annotations) { 177 SparseAnnotations... annotations) {
176 DeviceDescription description = 178 DeviceDescription description =
177 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR, 179 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
178 - HW, swVersion, SN, annotations); 180 + HW, swVersion, SN, CID, annotations);
179 deviceStore.createOrUpdateDevice(PIDA, deviceId, description); 181 deviceStore.createOrUpdateDevice(PIDA, deviceId, description);
180 } 182 }
181 183
...@@ -315,7 +317,7 @@ public class GossipDeviceStoreTest { ...@@ -315,7 +317,7 @@ public class GossipDeviceStoreTest {
315 public final void testCreateOrUpdateDevice() throws IOException { 317 public final void testCreateOrUpdateDevice() throws IOException {
316 DeviceDescription description = 318 DeviceDescription description =
317 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, 319 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
318 - HW, SW1, SN); 320 + HW, SW1, SN, CID);
319 Capture<ClusterMessage> bcast = new Capture<>(); 321 Capture<ClusterMessage> bcast = new Capture<>();
320 322
321 resetCommunicatorExpectingSingleBroadcast(bcast); 323 resetCommunicatorExpectingSingleBroadcast(bcast);
...@@ -328,7 +330,7 @@ public class GossipDeviceStoreTest { ...@@ -328,7 +330,7 @@ public class GossipDeviceStoreTest {
328 330
329 DeviceDescription description2 = 331 DeviceDescription description2 =
330 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, 332 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
331 - HW, SW2, SN); 333 + HW, SW2, SN, CID);
332 resetCommunicatorExpectingSingleBroadcast(bcast); 334 resetCommunicatorExpectingSingleBroadcast(bcast);
333 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2); 335 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
334 assertEquals(DEVICE_UPDATED, event2.type()); 336 assertEquals(DEVICE_UPDATED, event2.type());
...@@ -346,7 +348,7 @@ public class GossipDeviceStoreTest { ...@@ -346,7 +348,7 @@ public class GossipDeviceStoreTest {
346 // add 348 // add
347 DeviceDescription description = 349 DeviceDescription description =
348 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, 350 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
349 - HW, SW1, SN, A2); 351 + HW, SW1, SN, CID, A2);
350 Capture<ClusterMessage> bcast = new Capture<>(); 352 Capture<ClusterMessage> bcast = new Capture<>();
351 353
352 resetCommunicatorExpectingSingleBroadcast(bcast); 354 resetCommunicatorExpectingSingleBroadcast(bcast);
...@@ -362,7 +364,7 @@ public class GossipDeviceStoreTest { ...@@ -362,7 +364,7 @@ public class GossipDeviceStoreTest {
362 // update from primary 364 // update from primary
363 DeviceDescription description2 = 365 DeviceDescription description2 =
364 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, 366 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
365 - HW, SW2, SN, A1); 367 + HW, SW2, SN, CID, A1);
366 resetCommunicatorExpectingSingleBroadcast(bcast); 368 resetCommunicatorExpectingSingleBroadcast(bcast);
367 369
368 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2); 370 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
...@@ -392,7 +394,7 @@ public class GossipDeviceStoreTest { ...@@ -392,7 +394,7 @@ public class GossipDeviceStoreTest {
392 // But, Ancillary annotations will be in effect 394 // But, Ancillary annotations will be in effect
393 DeviceDescription description3 = 395 DeviceDescription description3 =
394 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, 396 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
395 - HW, SW1, SN, A2_2); 397 + HW, SW1, SN, CID, A2_2);
396 resetCommunicatorExpectingSingleBroadcast(bcast); 398 resetCommunicatorExpectingSingleBroadcast(bcast);
397 399
398 DeviceEvent event3 = deviceStore.createOrUpdateDevice(PIDA, DID1, description3); 400 DeviceEvent event3 = deviceStore.createOrUpdateDevice(PIDA, DID1, description3);
...@@ -775,7 +777,7 @@ public class GossipDeviceStoreTest { ...@@ -775,7 +777,7 @@ public class GossipDeviceStoreTest {
775 777
776 DeviceDescription description = 778 DeviceDescription description =
777 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, 779 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
778 - HW, SW1, SN); 780 + HW, SW1, SN, CID);
779 deviceStore.setDelegate(checkAdd); 781 deviceStore.setDelegate(checkAdd);
780 deviceStore.createOrUpdateDevice(PID, DID1, description); 782 deviceStore.createOrUpdateDevice(PID, DID1, description);
781 assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS)); 783 assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS));
...@@ -783,7 +785,7 @@ public class GossipDeviceStoreTest { ...@@ -783,7 +785,7 @@ public class GossipDeviceStoreTest {
783 785
784 DeviceDescription description2 = 786 DeviceDescription description2 =
785 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, 787 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
786 - HW, SW2, SN); 788 + HW, SW2, SN, CID);
787 deviceStore.unsetDelegate(checkAdd); 789 deviceStore.unsetDelegate(checkAdd);
788 deviceStore.setDelegate(checkUpdate); 790 deviceStore.setDelegate(checkUpdate);
789 deviceStore.createOrUpdateDevice(PID, DID1, description2); 791 deviceStore.createOrUpdateDevice(PID, DID1, description2);
......
1 +package org.onlab.onos.store.flow.impl;
2 +
3 +import static com.google.common.base.Preconditions.checkState;
4 +import static org.junit.Assert.*;
5 +
6 +import java.util.Collections;
7 +import java.util.Map;
8 +import java.util.concurrent.CountDownLatch;
9 +import java.util.concurrent.TimeUnit;
10 +
11 +import org.junit.After;
12 +import org.junit.Before;
13 +import org.junit.Test;
14 +import org.onlab.onos.cluster.NodeId;
15 +import org.onlab.onos.event.AbstractListenerRegistry;
16 +import org.onlab.onos.event.DefaultEventSinkRegistry;
17 +import org.onlab.onos.event.Event;
18 +import org.onlab.onos.event.EventDeliveryService;
19 +import org.onlab.onos.event.EventSink;
20 +import org.onlab.onos.mastership.MastershipEvent;
21 +import org.onlab.onos.mastership.MastershipEvent.Type;
22 +import org.onlab.onos.mastership.MastershipListener;
23 +import org.onlab.onos.mastership.MastershipService;
24 +import org.onlab.onos.mastership.MastershipServiceAdapter;
25 +import org.onlab.onos.net.DeviceId;
26 +import org.onlab.onos.store.flow.ReplicaInfo;
27 +import org.onlab.onos.store.flow.ReplicaInfoEvent;
28 +import org.onlab.onos.store.flow.ReplicaInfoEventListener;
29 +import org.onlab.onos.store.flow.ReplicaInfoService;
30 +
31 +import com.google.common.base.Optional;
32 +import com.google.common.collect.Maps;
33 +
34 +public class ReplicaInfoManagerTest {
35 +
36 +
37 + private static final DeviceId DID1 = DeviceId.deviceId("of:1");
38 + private static final DeviceId DID2 = DeviceId.deviceId("of:2");
39 + private static final NodeId NID1 = new NodeId("foo");
40 +
41 + private ReplicaInfoManager mgr;
42 + private ReplicaInfoService service;
43 +
44 + private AbstractListenerRegistry<MastershipEvent, MastershipListener>
45 + mastershipListenerRegistry;
46 + private TestEventDispatcher eventDispatcher;
47 +
48 +
49 + @Before
50 + public void setUp() throws Exception {
51 + mastershipListenerRegistry = new AbstractListenerRegistry<>();
52 +
53 + mgr = new ReplicaInfoManager();
54 + service = mgr;
55 +
56 + eventDispatcher = new TestEventDispatcher();
57 + mgr.eventDispatcher = eventDispatcher;
58 + mgr.mastershipService = new TestMastershipService();
59 +
60 + // register dummy mastership event source
61 + mgr.eventDispatcher.addSink(MastershipEvent.class, mastershipListenerRegistry);
62 +
63 + mgr.activate();
64 + }
65 +
66 + @After
67 + public void tearDown() throws Exception {
68 + mgr.deactivate();
69 + }
70 +
71 + @Test
72 + public void testGetReplicaInfoFor() {
73 + ReplicaInfo info1 = service.getReplicaInfoFor(DID1);
74 + assertEquals(Optional.of(NID1), info1.master());
75 + // backups are always empty for now
76 + assertEquals(Collections.emptyList(), info1.backups());
77 +
78 + ReplicaInfo info2 = service.getReplicaInfoFor(DID2);
79 + assertEquals("There's no master", Optional.absent(), info2.master());
80 + // backups are always empty for now
81 + assertEquals(Collections.emptyList(), info2.backups());
82 + }
83 +
84 + @Test
85 + public void testReplicaInfoEvent() throws InterruptedException {
86 + final CountDownLatch latch = new CountDownLatch(1);
87 + service.addListener(new MasterNodeCheck(latch, DID1, NID1));
88 +
89 + // fake MastershipEvent
90 + eventDispatcher.post(new MastershipEvent(Type.MASTER_CHANGED, DID1, NID1));
91 +
92 + assertTrue(latch.await(1, TimeUnit.SECONDS));
93 + }
94 +
95 +
96 + private final class MasterNodeCheck implements ReplicaInfoEventListener {
97 + private final CountDownLatch latch;
98 + private Optional<NodeId> expectedMaster;
99 + private DeviceId expectedDevice;
100 +
101 +
102 + MasterNodeCheck(CountDownLatch latch, DeviceId did,
103 + NodeId nid) {
104 + this.latch = latch;
105 + this.expectedMaster = Optional.fromNullable(nid);
106 + this.expectedDevice = did;
107 + }
108 +
109 + @Override
110 + public void event(ReplicaInfoEvent event) {
111 + assertEquals(expectedDevice, event.subject());
112 + assertEquals(expectedMaster, event.replicaInfo().master());
113 + // backups are always empty for now
114 + assertEquals(Collections.emptyList(), event.replicaInfo().backups());
115 + latch.countDown();
116 + }
117 + }
118 +
119 +
120 + private final class TestMastershipService
121 + extends MastershipServiceAdapter
122 + implements MastershipService {
123 +
124 + private Map<DeviceId, NodeId> masters;
125 +
126 + TestMastershipService() {
127 + masters = Maps.newHashMap();
128 + masters.put(DID1, NID1);
129 + // DID2 has no master
130 + }
131 +
132 + @Override
133 + public NodeId getMasterFor(DeviceId deviceId) {
134 + return masters.get(deviceId);
135 + }
136 +
137 + @Override
138 + public void addListener(MastershipListener listener) {
139 + mastershipListenerRegistry.addListener(listener);
140 + }
141 +
142 + @Override
143 + public void removeListener(MastershipListener listener) {
144 + mastershipListenerRegistry.removeListener(listener);
145 + }
146 + }
147 +
148 +
149 + // code clone
150 + /**
151 + * Implements event delivery system that delivers events synchronously, or
152 + * in-line with the post method invocation.
153 + */
154 + private static class TestEventDispatcher extends DefaultEventSinkRegistry
155 + implements EventDeliveryService {
156 +
157 + @SuppressWarnings({ "rawtypes", "unchecked" })
158 + @Override
159 + public void post(Event event) {
160 + EventSink sink = getSink(event.getClass());
161 + checkState(sink != null, "No sink for event %s", event);
162 + sink.process(event);
163 + }
164 + }
165 +}
1 -package org.onlab.onos.store.common.impl; 1 +package org.onlab.onos.store.impl;
2 2
3 import static org.junit.Assert.*; 3 import static org.junit.Assert.*;
4 4
...@@ -6,7 +6,6 @@ import java.nio.ByteBuffer; ...@@ -6,7 +6,6 @@ import java.nio.ByteBuffer;
6 6
7 import org.junit.Test; 7 import org.junit.Test;
8 import org.onlab.onos.store.Timestamp; 8 import org.onlab.onos.store.Timestamp;
9 -import org.onlab.onos.store.impl.MastershipBasedTimestamp;
10 import org.onlab.util.KryoPool; 9 import org.onlab.util.KryoPool;
11 10
12 import com.google.common.testing.EqualsTester; 11 import com.google.common.testing.EqualsTester;
......
...@@ -19,10 +19,6 @@ ...@@ -19,10 +19,6 @@
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>
...@@ -38,23 +34,6 @@ ...@@ -38,23 +34,6 @@
38 <scope>test</scope> 34 <scope>test</scope>
39 <version>${project.version}</version> 35 <version>${project.version}</version>
40 </dependency> 36 </dependency>
41 - <dependency>
42 - <groupId>org.apache.felix</groupId>
43 - <artifactId>org.apache.felix.scr.annotations</artifactId>
44 - </dependency>
45 - <dependency>
46 - <groupId>com.hazelcast</groupId>
47 - <artifactId>hazelcast</artifactId>
48 - </dependency>
49 </dependencies> 37 </dependencies>
50 38
51 - <build>
52 - <plugins>
53 - <plugin>
54 - <groupId>org.apache.felix</groupId>
55 - <artifactId>maven-scr-plugin</artifactId>
56 - </plugin>
57 - </plugins>
58 - </build>
59 -
60 </project> 39 </project>
......
...@@ -19,34 +19,13 @@ ...@@ -19,34 +19,13 @@
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 <dependency> 25 <dependency>
30 - <groupId>org.apache.felix</groupId>
31 - <artifactId>org.apache.felix.scr.annotations</artifactId>
32 - </dependency>
33 - <dependency>
34 - <groupId>com.hazelcast</groupId>
35 - <artifactId>hazelcast</artifactId>
36 - </dependency>
37 - <dependency>
38 <groupId>org.apache.commons</groupId> 26 <groupId>org.apache.commons</groupId>
39 <artifactId>commons-lang3</artifactId> 27 <artifactId>commons-lang3</artifactId>
40 </dependency> 28 </dependency>
41 </dependencies> 29 </dependencies>
42 30
43 - <build>
44 - <plugins>
45 - <plugin>
46 - <groupId>org.apache.felix</groupId>
47 - <artifactId>maven-scr-plugin</artifactId>
48 - </plugin>
49 - </plugins>
50 - </build>
51 -
52 </project> 31 </project>
......
...@@ -21,30 +21,9 @@ ...@@ -21,30 +21,9 @@
21 21
22 <dependencies> 22 <dependencies>
23 <dependency> 23 <dependency>
24 - <groupId>com.google.guava</groupId>
25 - <artifactId>guava</artifactId>
26 - </dependency>
27 - <dependency>
28 - <groupId>org.onlab.onos</groupId>
29 - <artifactId>onlab-misc</artifactId>
30 - </dependency>
31 - <dependency>
32 - <groupId>org.onlab.onos</groupId>
33 - <artifactId>onlab-junit</artifactId>
34 - </dependency>
35 - <dependency>
36 <groupId>com.hazelcast</groupId> 24 <groupId>com.hazelcast</groupId>
37 <artifactId>hazelcast</artifactId> 25 <artifactId>hazelcast</artifactId>
38 </dependency> 26 </dependency>
39 </dependencies> 27 </dependencies>
40 28
41 - <build>
42 - <plugins>
43 - <plugin>
44 - <groupId>org.apache.felix</groupId>
45 - <artifactId>maven-bundle-plugin</artifactId>
46 - </plugin>
47 - </plugins>
48 - </build>
49 -
50 </project> 29 </project>
......
1 <?xml version="1.0" encoding="UTF-8"?> 1 <?xml version="1.0" encoding="UTF-8"?>
2 -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 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">
3 <modelVersion>4.0.0</modelVersion> 5 <modelVersion>4.0.0</modelVersion>
4 6
5 <parent> 7 <parent>
...@@ -23,20 +25,13 @@ ...@@ -23,20 +25,13 @@
23 25
24 <dependencies> 26 <dependencies>
25 <dependency> 27 <dependency>
26 - <groupId>com.google.guava</groupId>
27 - <artifactId>guava</artifactId>
28 - </dependency>
29 - <dependency>
30 <groupId>org.onlab.onos</groupId> 28 <groupId>org.onlab.onos</groupId>
31 - <artifactId>onlab-misc</artifactId> 29 + <artifactId>onos-api</artifactId>
32 - </dependency>
33 - <dependency>
34 - <groupId>org.onlab.onos</groupId>
35 - <artifactId>onlab-junit</artifactId>
36 </dependency> 30 </dependency>
31 +
37 <dependency> 32 <dependency>
38 - <groupId>com.hazelcast</groupId> 33 + <groupId>org.apache.felix</groupId>
39 - <artifactId>hazelcast</artifactId> 34 + <artifactId>org.apache.felix.scr.annotations</artifactId>
40 </dependency> 35 </dependency>
41 </dependencies> 36 </dependencies>
42 37
...@@ -44,7 +39,7 @@ ...@@ -44,7 +39,7 @@
44 <plugins> 39 <plugins>
45 <plugin> 40 <plugin>
46 <groupId>org.apache.felix</groupId> 41 <groupId>org.apache.felix</groupId>
47 - <artifactId>maven-bundle-plugin</artifactId> 42 + <artifactId>maven-scr-plugin</artifactId>
48 </plugin> 43 </plugin>
49 </plugins> 44 </plugins>
50 </build> 45 </build>
......
...@@ -18,14 +18,6 @@ ...@@ -18,14 +18,6 @@
18 18
19 <dependencies> 19 <dependencies>
20 <dependency> 20 <dependency>
21 - <groupId>org.onlab.onos</groupId>
22 - <artifactId>onos-api</artifactId>
23 - </dependency>
24 - <dependency>
25 - <groupId>org.apache.felix</groupId>
26 - <artifactId>org.apache.felix.scr.annotations</artifactId>
27 - </dependency>
28 - <dependency>
29 <groupId>com.esotericsoftware</groupId> 21 <groupId>com.esotericsoftware</groupId>
30 <artifactId>kryo</artifactId> 22 <artifactId>kryo</artifactId>
31 </dependency> 23 </dependency>
...@@ -36,13 +28,4 @@ ...@@ -36,13 +28,4 @@
36 </dependency> 28 </dependency>
37 </dependencies> 29 </dependencies>
38 30
39 - <build>
40 - <plugins>
41 - <plugin>
42 - <groupId>org.apache.felix</groupId>
43 - <artifactId>maven-scr-plugin</artifactId>
44 - </plugin>
45 - </plugins>
46 - </build>
47 -
48 </project> 31 </project>
......
...@@ -25,11 +25,13 @@ import org.onlab.onos.net.Port; ...@@ -25,11 +25,13 @@ import org.onlab.onos.net.Port;
25 import org.onlab.onos.net.PortNumber; 25 import org.onlab.onos.net.PortNumber;
26 import org.onlab.onos.net.device.DefaultDeviceDescription; 26 import org.onlab.onos.net.device.DefaultDeviceDescription;
27 import org.onlab.onos.net.device.DefaultPortDescription; 27 import org.onlab.onos.net.device.DefaultPortDescription;
28 +import org.onlab.onos.net.flow.DefaultFlowRule;
28 import org.onlab.onos.net.host.DefaultHostDescription; 29 import org.onlab.onos.net.host.DefaultHostDescription;
29 import org.onlab.onos.net.host.HostDescription; 30 import org.onlab.onos.net.host.HostDescription;
30 import org.onlab.onos.net.link.DefaultLinkDescription; 31 import org.onlab.onos.net.link.DefaultLinkDescription;
31 import org.onlab.onos.net.provider.ProviderId; 32 import org.onlab.onos.net.provider.ProviderId;
32 import org.onlab.onos.store.Timestamp; 33 import org.onlab.onos.store.Timestamp;
34 +import org.onlab.packet.ChassisId;
33 import org.onlab.packet.IpAddress; 35 import org.onlab.packet.IpAddress;
34 import org.onlab.packet.IpPrefix; 36 import org.onlab.packet.IpPrefix;
35 import org.onlab.packet.MacAddress; 37 import org.onlab.packet.MacAddress;
...@@ -70,6 +72,7 @@ public final class KryoPoolUtil { ...@@ -70,6 +72,7 @@ public final class KryoPoolUtil {
70 // 72 //
71 ControllerNode.State.class, 73 ControllerNode.State.class,
72 Device.Type.class, 74 Device.Type.class,
75 + ChassisId.class,
73 DefaultAnnotations.class, 76 DefaultAnnotations.class,
74 DefaultControllerNode.class, 77 DefaultControllerNode.class,
75 DefaultDevice.class, 78 DefaultDevice.class,
...@@ -82,7 +85,8 @@ public final class KryoPoolUtil { ...@@ -82,7 +85,8 @@ public final class KryoPoolUtil {
82 Timestamp.class, 85 Timestamp.class,
83 HostId.class, 86 HostId.class,
84 HostDescription.class, 87 HostDescription.class,
85 - DefaultHostDescription.class 88 + DefaultHostDescription.class,
89 + DefaultFlowRule.class
86 ) 90 )
87 .register(URI.class, new URISerializer()) 91 .register(URI.class, new URISerializer())
88 .register(NodeId.class, new NodeIdSerializer()) 92 .register(NodeId.class, new NodeIdSerializer())
......
...@@ -25,6 +25,7 @@ import org.onlab.onos.net.LinkKey; ...@@ -25,6 +25,7 @@ import org.onlab.onos.net.LinkKey;
25 import org.onlab.onos.net.PortNumber; 25 import org.onlab.onos.net.PortNumber;
26 import org.onlab.onos.net.SparseAnnotations; 26 import org.onlab.onos.net.SparseAnnotations;
27 import org.onlab.onos.net.provider.ProviderId; 27 import org.onlab.onos.net.provider.ProviderId;
28 +import org.onlab.packet.ChassisId;
28 import org.onlab.packet.IpAddress; 29 import org.onlab.packet.IpAddress;
29 import org.onlab.packet.IpPrefix; 30 import org.onlab.packet.IpPrefix;
30 import org.onlab.util.KryoPool; 31 import org.onlab.util.KryoPool;
...@@ -48,7 +49,9 @@ public class KryoSerializerTest { ...@@ -48,7 +49,9 @@ public class KryoSerializerTest {
48 private static final String SW1 = "3.8.1"; 49 private static final String SW1 = "3.8.1";
49 private static final String SW2 = "3.9.5"; 50 private static final String SW2 = "3.9.5";
50 private static final String SN = "43311-12345"; 51 private static final String SN = "43311-12345";
51 - private static final Device DEV1 = new DefaultDevice(PID, DID1, Device.Type.SWITCH, MFR, HW, SW1, SN); 52 + private static final ChassisId CID = new ChassisId();
53 + private static final Device DEV1 = new DefaultDevice(PID, DID1, Device.Type.SWITCH, MFR, HW,
54 + SW1, SN, CID);
52 private static final SparseAnnotations A1 = DefaultAnnotations.builder() 55 private static final SparseAnnotations A1 = DefaultAnnotations.builder()
53 .set("A1", "a1") 56 .set("A1", "a1")
54 .set("B1", "b1") 57 .set("B1", "b1")
......
...@@ -18,26 +18,9 @@ ...@@ -18,26 +18,9 @@
18 18
19 <dependencies> 19 <dependencies>
20 <dependency> 20 <dependency>
21 - <groupId>org.onlab.onos</groupId>
22 - <artifactId>onos-api</artifactId>
23 - </dependency>
24 - <dependency>
25 - <groupId>org.apache.felix</groupId>
26 - <artifactId>org.apache.felix.scr.annotations</artifactId>
27 - </dependency>
28 - <dependency>
29 <groupId>org.apache.commons</groupId> 21 <groupId>org.apache.commons</groupId>
30 <artifactId>commons-lang3</artifactId> 22 <artifactId>commons-lang3</artifactId>
31 </dependency> 23 </dependency>
32 </dependencies> 24 </dependencies>
33 25
34 - <build>
35 - <plugins>
36 - <plugin>
37 - <groupId>org.apache.felix</groupId>
38 - <artifactId>maven-scr-plugin</artifactId>
39 - </plugin>
40 - </plugins>
41 - </build>
42 -
43 </project> 26 </project>
......
...@@ -5,8 +5,6 @@ import com.google.common.collect.ImmutableList; ...@@ -5,8 +5,6 @@ import com.google.common.collect.ImmutableList;
5 import com.google.common.collect.Maps; 5 import com.google.common.collect.Maps;
6 import com.google.common.collect.Sets; 6 import com.google.common.collect.Sets;
7 7
8 -import org.apache.commons.lang3.concurrent.ConcurrentException;
9 -import org.apache.commons.lang3.concurrent.ConcurrentInitializer;
10 import org.apache.felix.scr.annotations.Activate; 8 import org.apache.felix.scr.annotations.Activate;
11 import org.apache.felix.scr.annotations.Component; 9 import org.apache.felix.scr.annotations.Component;
12 import org.apache.felix.scr.annotations.Deactivate; 10 import org.apache.felix.scr.annotations.Deactivate;
...@@ -30,11 +28,13 @@ import org.onlab.onos.net.device.DeviceStoreDelegate; ...@@ -30,11 +28,13 @@ import org.onlab.onos.net.device.DeviceStoreDelegate;
30 import org.onlab.onos.net.device.PortDescription; 28 import org.onlab.onos.net.device.PortDescription;
31 import org.onlab.onos.net.provider.ProviderId; 29 import org.onlab.onos.net.provider.ProviderId;
32 import org.onlab.onos.store.AbstractStore; 30 import org.onlab.onos.store.AbstractStore;
31 +import org.onlab.packet.ChassisId;
33 import org.onlab.util.NewConcurrentHashMap; 32 import org.onlab.util.NewConcurrentHashMap;
34 import org.slf4j.Logger; 33 import org.slf4j.Logger;
35 34
36 import java.util.ArrayList; 35 import java.util.ArrayList;
37 import java.util.Collections; 36 import java.util.Collections;
37 +import java.util.HashMap;
38 import java.util.HashSet; 38 import java.util.HashSet;
39 import java.util.Iterator; 39 import java.util.Iterator;
40 import java.util.List; 40 import java.util.List;
...@@ -71,8 +71,7 @@ public class SimpleDeviceStore ...@@ -71,8 +71,7 @@ public class SimpleDeviceStore
71 public static final String DEVICE_NOT_FOUND = "Device with ID %s not found"; 71 public static final String DEVICE_NOT_FOUND = "Device with ID %s not found";
72 72
73 // collection of Description given from various providers 73 // collection of Description given from various providers
74 - private final ConcurrentMap<DeviceId, 74 + private final ConcurrentMap<DeviceId, Map<ProviderId, DeviceDescriptions>>
75 - ConcurrentMap<ProviderId, DeviceDescriptions>>
76 deviceDescs = Maps.newConcurrentMap(); 75 deviceDescs = Maps.newConcurrentMap();
77 76
78 // cache of Device and Ports generated by compositing descriptions from providers 77 // cache of Device and Ports generated by compositing descriptions from providers
...@@ -117,15 +116,16 @@ public class SimpleDeviceStore ...@@ -117,15 +116,16 @@ public class SimpleDeviceStore
117 DeviceId deviceId, 116 DeviceId deviceId,
118 DeviceDescription deviceDescription) { 117 DeviceDescription deviceDescription) {
119 118
120 - ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs 119 + Map<ProviderId, DeviceDescriptions> providerDescs
121 - = getDeviceDescriptions(deviceId); 120 + = getOrCreateDeviceDescriptions(deviceId);
122 121
123 synchronized (providerDescs) { 122 synchronized (providerDescs) {
124 // locking per device 123 // locking per device
125 124
126 DeviceDescriptions descs 125 DeviceDescriptions descs
127 - = createIfAbsentUnchecked(providerDescs, providerId, 126 + = getOrCreateProviderDeviceDescriptions(providerDescs,
128 - new InitDeviceDescs(deviceDescription)); 127 + providerId,
128 + deviceDescription);
129 129
130 Device oldDevice = devices.get(deviceId); 130 Device oldDevice = devices.get(deviceId);
131 // update description 131 // update description
...@@ -192,8 +192,8 @@ public class SimpleDeviceStore ...@@ -192,8 +192,8 @@ public class SimpleDeviceStore
192 192
193 @Override 193 @Override
194 public DeviceEvent markOffline(DeviceId deviceId) { 194 public DeviceEvent markOffline(DeviceId deviceId) {
195 - ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs 195 + Map<ProviderId, DeviceDescriptions> providerDescs
196 - = getDeviceDescriptions(deviceId); 196 + = getOrCreateDeviceDescriptions(deviceId);
197 197
198 // locking device 198 // locking device
199 synchronized (providerDescs) { 199 synchronized (providerDescs) {
...@@ -218,7 +218,7 @@ public class SimpleDeviceStore ...@@ -218,7 +218,7 @@ public class SimpleDeviceStore
218 Device device = devices.get(deviceId); 218 Device device = devices.get(deviceId);
219 checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); 219 checkArgument(device != null, DEVICE_NOT_FOUND, deviceId);
220 220
221 - ConcurrentMap<ProviderId, DeviceDescriptions> descsMap = deviceDescs.get(deviceId); 221 + Map<ProviderId, DeviceDescriptions> descsMap = deviceDescs.get(deviceId);
222 checkArgument(descsMap != null, DEVICE_NOT_FOUND, deviceId); 222 checkArgument(descsMap != null, DEVICE_NOT_FOUND, deviceId);
223 223
224 List<DeviceEvent> events = new ArrayList<>(); 224 List<DeviceEvent> events = new ArrayList<>();
...@@ -287,12 +287,12 @@ public class SimpleDeviceStore ...@@ -287,12 +287,12 @@ public class SimpleDeviceStore
287 Map<PortNumber, Port> ports, 287 Map<PortNumber, Port> ports,
288 Set<PortNumber> processed) { 288 Set<PortNumber> processed) {
289 List<DeviceEvent> events = new ArrayList<>(); 289 List<DeviceEvent> events = new ArrayList<>();
290 - Iterator<PortNumber> iterator = ports.keySet().iterator(); 290 + Iterator<Entry<PortNumber, Port>> iterator = ports.entrySet().iterator();
291 while (iterator.hasNext()) { 291 while (iterator.hasNext()) {
292 - PortNumber portNumber = iterator.next(); 292 + Entry<PortNumber, Port> e = iterator.next();
293 + PortNumber portNumber = e.getKey();
293 if (!processed.contains(portNumber)) { 294 if (!processed.contains(portNumber)) {
294 - events.add(new DeviceEvent(PORT_REMOVED, device, 295 + events.add(new DeviceEvent(PORT_REMOVED, device, e.getValue()));
295 - ports.get(portNumber)));
296 iterator.remove(); 296 iterator.remove();
297 } 297 }
298 } 298 }
...@@ -306,10 +306,36 @@ public class SimpleDeviceStore ...@@ -306,10 +306,36 @@ public class SimpleDeviceStore
306 NewConcurrentHashMap.<PortNumber, Port>ifNeeded()); 306 NewConcurrentHashMap.<PortNumber, Port>ifNeeded());
307 } 307 }
308 308
309 - private ConcurrentMap<ProviderId, DeviceDescriptions> getDeviceDescriptions( 309 + private Map<ProviderId, DeviceDescriptions> getOrCreateDeviceDescriptions(
310 DeviceId deviceId) { 310 DeviceId deviceId) {
311 - return createIfAbsentUnchecked(deviceDescs, deviceId, 311 + Map<ProviderId, DeviceDescriptions> r;
312 - NewConcurrentHashMap.<ProviderId, DeviceDescriptions>ifNeeded()); 312 + r = deviceDescs.get(deviceId);
313 + if (r != null) {
314 + return r;
315 + }
316 + r = new HashMap<>();
317 + final Map<ProviderId, DeviceDescriptions> concurrentlyAdded;
318 + concurrentlyAdded = deviceDescs.putIfAbsent(deviceId, r);
319 + if (concurrentlyAdded != null) {
320 + return concurrentlyAdded;
321 + } else {
322 + return r;
323 + }
324 + }
325 +
326 + // Guarded by deviceDescs value (=Device lock)
327 + private DeviceDescriptions getOrCreateProviderDeviceDescriptions(
328 + Map<ProviderId, DeviceDescriptions> device,
329 + ProviderId providerId, DeviceDescription deltaDesc) {
330 +
331 + synchronized (device) {
332 + DeviceDescriptions r = device.get(providerId);
333 + if (r == null) {
334 + r = new DeviceDescriptions(deltaDesc);
335 + device.put(providerId, r);
336 + }
337 + return r;
338 + }
313 } 339 }
314 340
315 @Override 341 @Override
...@@ -318,12 +344,12 @@ public class SimpleDeviceStore ...@@ -318,12 +344,12 @@ public class SimpleDeviceStore
318 Device device = devices.get(deviceId); 344 Device device = devices.get(deviceId);
319 checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); 345 checkArgument(device != null, DEVICE_NOT_FOUND, deviceId);
320 346
321 - ConcurrentMap<ProviderId, DeviceDescriptions> descsMap = deviceDescs.get(deviceId); 347 + Map<ProviderId, DeviceDescriptions> descsMap = deviceDescs.get(deviceId);
322 checkArgument(descsMap != null, DEVICE_NOT_FOUND, deviceId); 348 checkArgument(descsMap != null, DEVICE_NOT_FOUND, deviceId);
323 349
324 synchronized (descsMap) { 350 synchronized (descsMap) {
325 DeviceDescriptions descs = descsMap.get(providerId); 351 DeviceDescriptions descs = descsMap.get(providerId);
326 - // assuming all providers must to give DeviceDescription 352 + // assuming all providers must give DeviceDescription first
327 checkArgument(descs != null, 353 checkArgument(descs != null,
328 "Device description for Device ID %s from Provider %s was not found", 354 "Device description for Device ID %s from Provider %s was not found",
329 deviceId, providerId); 355 deviceId, providerId);
...@@ -367,7 +393,7 @@ public class SimpleDeviceStore ...@@ -367,7 +393,7 @@ public class SimpleDeviceStore
367 393
368 @Override 394 @Override
369 public DeviceEvent removeDevice(DeviceId deviceId) { 395 public DeviceEvent removeDevice(DeviceId deviceId) {
370 - ConcurrentMap<ProviderId, DeviceDescriptions> descs = getDeviceDescriptions(deviceId); 396 + Map<ProviderId, DeviceDescriptions> descs = getOrCreateDeviceDescriptions(deviceId);
371 synchronized (descs) { 397 synchronized (descs) {
372 Device device = devices.remove(deviceId); 398 Device device = devices.remove(deviceId);
373 // should DEVICE_REMOVED carry removed ports? 399 // should DEVICE_REMOVED carry removed ports?
...@@ -390,7 +416,7 @@ public class SimpleDeviceStore ...@@ -390,7 +416,7 @@ public class SimpleDeviceStore
390 * @return Device instance 416 * @return Device instance
391 */ 417 */
392 private Device composeDevice(DeviceId deviceId, 418 private Device composeDevice(DeviceId deviceId,
393 - ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs) { 419 + Map<ProviderId, DeviceDescriptions> providerDescs) {
394 420
395 checkArgument(!providerDescs.isEmpty(), "No Device descriptions supplied"); 421 checkArgument(!providerDescs.isEmpty(), "No Device descriptions supplied");
396 422
...@@ -404,6 +430,7 @@ public class SimpleDeviceStore ...@@ -404,6 +430,7 @@ public class SimpleDeviceStore
404 String hwVersion = base.hwVersion(); 430 String hwVersion = base.hwVersion();
405 String swVersion = base.swVersion(); 431 String swVersion = base.swVersion();
406 String serialNumber = base.serialNumber(); 432 String serialNumber = base.serialNumber();
433 + ChassisId chassisId = base.chassisId();
407 DefaultAnnotations annotations = DefaultAnnotations.builder().build(); 434 DefaultAnnotations annotations = DefaultAnnotations.builder().build();
408 annotations = merge(annotations, base.annotations()); 435 annotations = merge(annotations, base.annotations());
409 436
...@@ -421,7 +448,8 @@ public class SimpleDeviceStore ...@@ -421,7 +448,8 @@ public class SimpleDeviceStore
421 } 448 }
422 449
423 return new DefaultDevice(primary, deviceId , type, manufacturer, 450 return new DefaultDevice(primary, deviceId , type, manufacturer,
424 - hwVersion, swVersion, serialNumber, annotations); 451 + hwVersion, swVersion, serialNumber,
452 + chassisId, annotations);
425 } 453 }
426 454
427 /** 455 /**
...@@ -429,14 +457,14 @@ public class SimpleDeviceStore ...@@ -429,14 +457,14 @@ public class SimpleDeviceStore
429 * 457 *
430 * @param device device the port is on 458 * @param device device the port is on
431 * @param number port number 459 * @param number port number
432 - * @param providerDescs Collection of Descriptions from multiple providers 460 + * @param descsMap Collection of Descriptions from multiple providers
433 * @return Port instance 461 * @return Port instance
434 */ 462 */
435 private Port composePort(Device device, PortNumber number, 463 private Port composePort(Device device, PortNumber number,
436 - ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs) { 464 + Map<ProviderId, DeviceDescriptions> descsMap) {
437 465
438 - ProviderId primary = pickPrimaryPID(providerDescs); 466 + ProviderId primary = pickPrimaryPID(descsMap);
439 - DeviceDescriptions primDescs = providerDescs.get(primary); 467 + DeviceDescriptions primDescs = descsMap.get(primary);
440 // if no primary, assume not enabled 468 // if no primary, assume not enabled
441 // TODO: revisit this default port enabled/disabled behavior 469 // TODO: revisit this default port enabled/disabled behavior
442 boolean isEnabled = false; 470 boolean isEnabled = false;
...@@ -448,7 +476,7 @@ public class SimpleDeviceStore ...@@ -448,7 +476,7 @@ public class SimpleDeviceStore
448 annotations = merge(annotations, portDesc.annotations()); 476 annotations = merge(annotations, portDesc.annotations());
449 } 477 }
450 478
451 - for (Entry<ProviderId, DeviceDescriptions> e : providerDescs.entrySet()) { 479 + for (Entry<ProviderId, DeviceDescriptions> e : descsMap.entrySet()) {
452 if (e.getKey().equals(primary)) { 480 if (e.getKey().equals(primary)) {
453 continue; 481 continue;
454 } 482 }
...@@ -470,10 +498,9 @@ public class SimpleDeviceStore ...@@ -470,10 +498,9 @@ public class SimpleDeviceStore
470 /** 498 /**
471 * @return primary ProviderID, or randomly chosen one if none exists 499 * @return primary ProviderID, or randomly chosen one if none exists
472 */ 500 */
473 - private ProviderId pickPrimaryPID( 501 + private ProviderId pickPrimaryPID(Map<ProviderId, DeviceDescriptions> descsMap) {
474 - ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs) {
475 ProviderId fallBackPrimary = null; 502 ProviderId fallBackPrimary = null;
476 - for (Entry<ProviderId, DeviceDescriptions> e : providerDescs.entrySet()) { 503 + for (Entry<ProviderId, DeviceDescriptions> e : descsMap.entrySet()) {
477 if (!e.getKey().isAncillary()) { 504 if (!e.getKey().isAncillary()) {
478 return e.getKey(); 505 return e.getKey();
479 } else if (fallBackPrimary == null) { 506 } else if (fallBackPrimary == null) {
...@@ -484,21 +511,6 @@ public class SimpleDeviceStore ...@@ -484,21 +511,6 @@ public class SimpleDeviceStore
484 return fallBackPrimary; 511 return fallBackPrimary;
485 } 512 }
486 513
487 - public static final class InitDeviceDescs
488 - implements ConcurrentInitializer<DeviceDescriptions> {
489 -
490 - private final DeviceDescription deviceDesc;
491 -
492 - public InitDeviceDescs(DeviceDescription deviceDesc) {
493 - this.deviceDesc = checkNotNull(deviceDesc);
494 - }
495 - @Override
496 - public DeviceDescriptions get() throws ConcurrentException {
497 - return new DeviceDescriptions(deviceDesc);
498 - }
499 - }
500 -
501 -
502 /** 514 /**
503 * Collection of Description of a Device and it's Ports given from a Provider. 515 * Collection of Description of a Device and it's Ports given from a Provider.
504 */ 516 */
......
...@@ -2,9 +2,13 @@ package org.onlab.onos.store.trivial.impl; ...@@ -2,9 +2,13 @@ package org.onlab.onos.store.trivial.impl;
2 2
3 import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; 3 import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
4 import static org.slf4j.LoggerFactory.getLogger; 4 import static org.slf4j.LoggerFactory.getLogger;
5 +import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked;
6 +import static java.util.Collections.unmodifiableCollection;
5 7
6 -import java.util.Collection; 8 +import java.util.HashSet;
7 -import java.util.Collections; 9 +import java.util.Set;
10 +import java.util.concurrent.ConcurrentHashMap;
11 +import java.util.concurrent.ConcurrentMap;
8 12
9 import org.apache.felix.scr.annotations.Activate; 13 import org.apache.felix.scr.annotations.Activate;
10 import org.apache.felix.scr.annotations.Component; 14 import org.apache.felix.scr.annotations.Component;
...@@ -15,18 +19,16 @@ import org.onlab.onos.net.DeviceId; ...@@ -15,18 +19,16 @@ import org.onlab.onos.net.DeviceId;
15 import org.onlab.onos.net.flow.DefaultFlowEntry; 19 import org.onlab.onos.net.flow.DefaultFlowEntry;
16 import org.onlab.onos.net.flow.FlowEntry; 20 import org.onlab.onos.net.flow.FlowEntry;
17 import org.onlab.onos.net.flow.FlowEntry.FlowEntryState; 21 import org.onlab.onos.net.flow.FlowEntry.FlowEntryState;
22 +import org.onlab.onos.net.flow.FlowId;
18 import org.onlab.onos.net.flow.FlowRule; 23 import org.onlab.onos.net.flow.FlowRule;
19 import org.onlab.onos.net.flow.FlowRuleEvent; 24 import org.onlab.onos.net.flow.FlowRuleEvent;
20 import org.onlab.onos.net.flow.FlowRuleEvent.Type; 25 import org.onlab.onos.net.flow.FlowRuleEvent.Type;
21 import org.onlab.onos.net.flow.FlowRuleStore; 26 import org.onlab.onos.net.flow.FlowRuleStore;
22 import org.onlab.onos.net.flow.FlowRuleStoreDelegate; 27 import org.onlab.onos.net.flow.FlowRuleStoreDelegate;
23 import org.onlab.onos.store.AbstractStore; 28 import org.onlab.onos.store.AbstractStore;
29 +import org.onlab.util.NewConcurrentHashMap;
24 import org.slf4j.Logger; 30 import org.slf4j.Logger;
25 31
26 -import com.google.common.collect.ArrayListMultimap;
27 -import com.google.common.collect.ImmutableSet;
28 -import com.google.common.collect.Multimap;
29 -
30 /** 32 /**
31 * Manages inventory of flow rules using trivial in-memory implementation. 33 * Manages inventory of flow rules using trivial in-memory implementation.
32 */ 34 */
...@@ -38,12 +40,11 @@ public class SimpleFlowRuleStore ...@@ -38,12 +40,11 @@ public class SimpleFlowRuleStore
38 40
39 private final Logger log = getLogger(getClass()); 41 private final Logger log = getLogger(getClass());
40 42
41 - // store entries as a pile of rules, no info about device tables
42 - private final Multimap<DeviceId, FlowEntry> flowEntries =
43 - ArrayListMultimap.<DeviceId, FlowEntry>create();
44 43
45 - private final Multimap<Short, FlowRule> flowEntriesById = 44 + // inner Map is Device flow table
46 - ArrayListMultimap.<Short, FlowRule>create(); 45 + // Assumption: FlowId cannot have synonyms
46 + private final ConcurrentMap<DeviceId, ConcurrentMap<FlowId, FlowEntry>>
47 + flowEntries = new ConcurrentHashMap<>();
47 48
48 @Activate 49 @Activate
49 public void activate() { 50 public void activate() {
...@@ -52,88 +53,130 @@ public class SimpleFlowRuleStore ...@@ -52,88 +53,130 @@ public class SimpleFlowRuleStore
52 53
53 @Deactivate 54 @Deactivate
54 public void deactivate() { 55 public void deactivate() {
56 + flowEntries.clear();
55 log.info("Stopped"); 57 log.info("Stopped");
56 } 58 }
57 59
58 60
59 @Override 61 @Override
60 public int getFlowRuleCount() { 62 public int getFlowRuleCount() {
61 - return flowEntries.size(); 63 + int sum = 0;
64 + for (ConcurrentMap<FlowId, FlowEntry> ft : flowEntries.values()) {
65 + sum += ft.size();
66 + }
67 + return sum;
62 } 68 }
63 69
64 - @Override 70 + private static NewConcurrentHashMap<FlowId, FlowEntry> lazyEmptyFlowTable() {
65 - public synchronized FlowEntry getFlowEntry(FlowRule rule) { 71 + return NewConcurrentHashMap.<FlowId, FlowEntry>ifNeeded();
66 - for (FlowEntry f : flowEntries.get(rule.deviceId())) {
67 - if (f.equals(rule)) {
68 - return f;
69 } 72 }
73 +
74 + /**
75 + * Returns the flow table for specified device.
76 + *
77 + * @param deviceId identifier of the device
78 + * @return Map representing Flow Table of given device.
79 + */
80 + private ConcurrentMap<FlowId, FlowEntry> getFlowTable(DeviceId deviceId) {
81 + return createIfAbsentUnchecked(flowEntries,
82 + deviceId, lazyEmptyFlowTable());
70 } 83 }
71 - return null; 84 +
85 + private FlowEntry getFlowEntry(DeviceId deviceId, FlowId flowId) {
86 + return getFlowTable(deviceId).get(flowId);
72 } 87 }
73 88
74 @Override 89 @Override
75 - public synchronized Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) { 90 + public FlowEntry getFlowEntry(FlowRule rule) {
76 - Collection<FlowEntry> rules = flowEntries.get(deviceId); 91 + return getFlowEntry(rule.deviceId(), rule.id());
77 - if (rules == null) {
78 - return Collections.emptyList();
79 } 92 }
80 - return ImmutableSet.copyOf(rules); 93 +
94 + @Override
95 + public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
96 + return unmodifiableCollection(getFlowTable(deviceId).values());
81 } 97 }
82 98
83 @Override 99 @Override
84 - public synchronized Iterable<FlowRule> getFlowRulesByAppId(ApplicationId appId) { 100 + public Iterable<FlowRule> getFlowRulesByAppId(ApplicationId appId) {
85 - Collection<FlowRule> rules = flowEntriesById.get(appId.id()); 101 +
86 - if (rules == null) { 102 + Set<FlowRule> rules = new HashSet<>();
87 - return Collections.emptyList(); 103 + for (DeviceId did : flowEntries.keySet()) {
104 + ConcurrentMap<FlowId, FlowEntry> ft = getFlowTable(did);
105 + for (FlowEntry fe : ft.values()) {
106 + if (fe.appId() == appId.id()) {
107 + rules.add(fe);
88 } 108 }
89 - return ImmutableSet.copyOf(rules); 109 + }
110 + }
111 + return rules;
90 } 112 }
91 113
92 @Override 114 @Override
93 - public synchronized void storeFlowRule(FlowRule rule) { 115 + public void storeFlowRule(FlowRule rule) {
116 + final boolean added = storeFlowRuleInternal(rule);
117 + }
118 +
119 + private boolean storeFlowRuleInternal(FlowRule rule) {
94 FlowEntry f = new DefaultFlowEntry(rule); 120 FlowEntry f = new DefaultFlowEntry(rule);
95 - DeviceId did = f.deviceId(); 121 + final DeviceId did = f.deviceId();
96 - if (!flowEntries.containsEntry(did, f)) { 122 + final FlowId fid = f.id();
97 - flowEntries.put(did, f); 123 + FlowEntry existing = getFlowTable(did).putIfAbsent(fid, f);
98 - flowEntriesById.put(rule.appId(), f); 124 + if (existing != null) {
125 + // was already there? ignore
126 + return false;
99 } 127 }
128 + // new flow rule added
129 + // TODO: notify through delegate about remote event?
130 + return true;
100 } 131 }
101 132
102 @Override 133 @Override
103 - public synchronized void deleteFlowRule(FlowRule rule) { 134 + public void deleteFlowRule(FlowRule rule) {
104 - FlowEntry entry = getFlowEntry(rule); 135 +
136 + FlowEntry entry = getFlowEntry(rule.deviceId(), rule.id());
105 if (entry == null) { 137 if (entry == null) {
106 - //log.warn("Cannot find rule {}", rule); 138 + log.warn("Cannot find rule {}", rule);
139 + System.err.println("Cannot find rule " + rule);
107 return; 140 return;
108 } 141 }
142 + synchronized (entry) {
109 entry.setState(FlowEntryState.PENDING_REMOVE); 143 entry.setState(FlowEntryState.PENDING_REMOVE);
110 } 144 }
145 + }
111 146
112 @Override 147 @Override
113 - public synchronized FlowRuleEvent addOrUpdateFlowRule(FlowEntry rule) { 148 + public FlowRuleEvent addOrUpdateFlowRule(FlowEntry rule) {
114 - DeviceId did = rule.deviceId();
115 -
116 // check if this new rule is an update to an existing entry 149 // check if this new rule is an update to an existing entry
117 - FlowEntry stored = getFlowEntry(rule); 150 + FlowEntry stored = getFlowEntry(rule.deviceId(), rule.id());
118 if (stored != null) { 151 if (stored != null) {
152 + synchronized (stored) {
119 stored.setBytes(rule.bytes()); 153 stored.setBytes(rule.bytes());
120 stored.setLife(rule.life()); 154 stored.setLife(rule.life());
121 stored.setPackets(rule.packets()); 155 stored.setPackets(rule.packets());
122 if (stored.state() == FlowEntryState.PENDING_ADD) { 156 if (stored.state() == FlowEntryState.PENDING_ADD) {
123 stored.setState(FlowEntryState.ADDED); 157 stored.setState(FlowEntryState.ADDED);
158 + // TODO: Do we need to change `rule` state?
124 return new FlowRuleEvent(Type.RULE_ADDED, rule); 159 return new FlowRuleEvent(Type.RULE_ADDED, rule);
125 } 160 }
126 return new FlowRuleEvent(Type.RULE_UPDATED, rule); 161 return new FlowRuleEvent(Type.RULE_UPDATED, rule);
127 } 162 }
163 + }
164 +
165 + // should not reach here
166 + // storeFlowRule was expected to be called
167 + log.error("FlowRule was not found in store {} to update", rule);
128 168
129 //flowEntries.put(did, rule); 169 //flowEntries.put(did, rule);
130 return null; 170 return null;
131 } 171 }
132 172
133 @Override 173 @Override
134 - public synchronized FlowRuleEvent removeFlowRule(FlowEntry rule) { 174 + public FlowRuleEvent removeFlowRule(FlowEntry rule) {
135 // This is where one could mark a rule as removed and still keep it in the store. 175 // This is where one could mark a rule as removed and still keep it in the store.
136 - if (flowEntries.remove(rule.deviceId(), rule)) { 176 + final DeviceId did = rule.deviceId();
177 +
178 + ConcurrentMap<FlowId, FlowEntry> ft = getFlowTable(did);
179 + if (ft.remove(rule.id(), rule)) {
137 return new FlowRuleEvent(RULE_REMOVED, rule); 180 return new FlowRuleEvent(RULE_REMOVED, rule);
138 } else { 181 } else {
139 return null; 182 return null;
......
1 package org.onlab.onos.store.trivial.impl; 1 package org.onlab.onos.store.trivial.impl;
2 2
3 import com.google.common.base.Function; 3 import com.google.common.base.Function;
4 -import com.google.common.base.Predicate;
5 import com.google.common.collect.FluentIterable; 4 import com.google.common.collect.FluentIterable;
6 import com.google.common.collect.HashMultimap; 5 import com.google.common.collect.HashMultimap;
7 import com.google.common.collect.SetMultimap; 6 import com.google.common.collect.SetMultimap;
8 7
9 -import org.apache.commons.lang3.concurrent.ConcurrentUtils;
10 import org.apache.felix.scr.annotations.Activate; 8 import org.apache.felix.scr.annotations.Activate;
11 import org.apache.felix.scr.annotations.Component; 9 import org.apache.felix.scr.annotations.Component;
12 import org.apache.felix.scr.annotations.Deactivate; 10 import org.apache.felix.scr.annotations.Deactivate;
...@@ -20,7 +18,6 @@ import org.onlab.onos.net.Link; ...@@ -20,7 +18,6 @@ import org.onlab.onos.net.Link;
20 import org.onlab.onos.net.SparseAnnotations; 18 import org.onlab.onos.net.SparseAnnotations;
21 import org.onlab.onos.net.Link.Type; 19 import org.onlab.onos.net.Link.Type;
22 import org.onlab.onos.net.LinkKey; 20 import org.onlab.onos.net.LinkKey;
23 -import org.onlab.onos.net.Provided;
24 import org.onlab.onos.net.link.DefaultLinkDescription; 21 import org.onlab.onos.net.link.DefaultLinkDescription;
25 import org.onlab.onos.net.link.LinkDescription; 22 import org.onlab.onos.net.link.LinkDescription;
26 import org.onlab.onos.net.link.LinkEvent; 23 import org.onlab.onos.net.link.LinkEvent;
...@@ -28,11 +25,12 @@ import org.onlab.onos.net.link.LinkStore; ...@@ -28,11 +25,12 @@ import org.onlab.onos.net.link.LinkStore;
28 import org.onlab.onos.net.link.LinkStoreDelegate; 25 import org.onlab.onos.net.link.LinkStoreDelegate;
29 import org.onlab.onos.net.provider.ProviderId; 26 import org.onlab.onos.net.provider.ProviderId;
30 import org.onlab.onos.store.AbstractStore; 27 import org.onlab.onos.store.AbstractStore;
31 -import org.onlab.util.NewConcurrentHashMap;
32 import org.slf4j.Logger; 28 import org.slf4j.Logger;
33 29
34 import java.util.Collections; 30 import java.util.Collections;
31 +import java.util.HashMap;
35 import java.util.HashSet; 32 import java.util.HashSet;
33 +import java.util.Map;
36 import java.util.Set; 34 import java.util.Set;
37 import java.util.Map.Entry; 35 import java.util.Map.Entry;
38 import java.util.concurrent.ConcurrentHashMap; 36 import java.util.concurrent.ConcurrentHashMap;
...@@ -47,6 +45,7 @@ import static org.onlab.onos.net.link.LinkEvent.Type.*; ...@@ -47,6 +45,7 @@ import static org.onlab.onos.net.link.LinkEvent.Type.*;
47 import static org.slf4j.LoggerFactory.getLogger; 45 import static org.slf4j.LoggerFactory.getLogger;
48 import static com.google.common.collect.Multimaps.synchronizedSetMultimap; 46 import static com.google.common.collect.Multimaps.synchronizedSetMultimap;
49 import static com.google.common.base.Predicates.notNull; 47 import static com.google.common.base.Predicates.notNull;
48 +import static com.google.common.base.Verify.verifyNotNull;
50 49
51 /** 50 /**
52 * Manages inventory of infrastructure links using trivial in-memory structures 51 * Manages inventory of infrastructure links using trivial in-memory structures
...@@ -61,8 +60,7 @@ public class SimpleLinkStore ...@@ -61,8 +60,7 @@ public class SimpleLinkStore
61 private final Logger log = getLogger(getClass()); 60 private final Logger log = getLogger(getClass());
62 61
63 // Link inventory 62 // Link inventory
64 - private final ConcurrentMap<LinkKey, 63 + private final ConcurrentMap<LinkKey, Map<ProviderId, LinkDescription>>
65 - ConcurrentMap<ProviderId, LinkDescription>>
66 linkDescs = new ConcurrentHashMap<>(); 64 linkDescs = new ConcurrentHashMap<>();
67 65
68 // Link instance cache 66 // Link instance cache
...@@ -151,7 +149,7 @@ public class SimpleLinkStore ...@@ -151,7 +149,7 @@ public class SimpleLinkStore
151 LinkDescription linkDescription) { 149 LinkDescription linkDescription) {
152 LinkKey key = linkKey(linkDescription.src(), linkDescription.dst()); 150 LinkKey key = linkKey(linkDescription.src(), linkDescription.dst());
153 151
154 - ConcurrentMap<ProviderId, LinkDescription> descs = getLinkDescriptions(key); 152 + Map<ProviderId, LinkDescription> descs = getOrCreateLinkDescriptions(key);
155 synchronized (descs) { 153 synchronized (descs) {
156 final Link oldLink = links.get(key); 154 final Link oldLink = links.get(key);
157 // update description 155 // update description
...@@ -166,7 +164,7 @@ public class SimpleLinkStore ...@@ -166,7 +164,7 @@ public class SimpleLinkStore
166 164
167 // Guarded by linkDescs value (=locking each Link) 165 // Guarded by linkDescs value (=locking each Link)
168 private LinkDescription createOrUpdateLinkDescription( 166 private LinkDescription createOrUpdateLinkDescription(
169 - ConcurrentMap<ProviderId, LinkDescription> descs, 167 + Map<ProviderId, LinkDescription> descs,
170 ProviderId providerId, 168 ProviderId providerId,
171 LinkDescription linkDescription) { 169 LinkDescription linkDescription) {
172 170
...@@ -227,7 +225,7 @@ public class SimpleLinkStore ...@@ -227,7 +225,7 @@ public class SimpleLinkStore
227 @Override 225 @Override
228 public LinkEvent removeLink(ConnectPoint src, ConnectPoint dst) { 226 public LinkEvent removeLink(ConnectPoint src, ConnectPoint dst) {
229 final LinkKey key = linkKey(src, dst); 227 final LinkKey key = linkKey(src, dst);
230 - ConcurrentMap<ProviderId, LinkDescription> descs = getLinkDescriptions(key); 228 + Map<ProviderId, LinkDescription> descs = getOrCreateLinkDescriptions(key);
231 synchronized (descs) { 229 synchronized (descs) {
232 Link link = links.remove(key); 230 Link link = links.remove(key);
233 descs.clear(); 231 descs.clear();
...@@ -247,8 +245,8 @@ public class SimpleLinkStore ...@@ -247,8 +245,8 @@ public class SimpleLinkStore
247 /** 245 /**
248 * @return primary ProviderID, or randomly chosen one if none exists 246 * @return primary ProviderID, or randomly chosen one if none exists
249 */ 247 */
250 - private ProviderId pickPrimaryPID( 248 + // Guarded by linkDescs value (=locking each Link)
251 - ConcurrentMap<ProviderId, LinkDescription> providerDescs) { 249 + private ProviderId getBaseProviderId(Map<ProviderId, LinkDescription> providerDescs) {
252 250
253 ProviderId fallBackPrimary = null; 251 ProviderId fallBackPrimary = null;
254 for (Entry<ProviderId, LinkDescription> e : providerDescs.entrySet()) { 252 for (Entry<ProviderId, LinkDescription> e : providerDescs.entrySet()) {
...@@ -262,9 +260,10 @@ public class SimpleLinkStore ...@@ -262,9 +260,10 @@ public class SimpleLinkStore
262 return fallBackPrimary; 260 return fallBackPrimary;
263 } 261 }
264 262
265 - private Link composeLink(ConcurrentMap<ProviderId, LinkDescription> descs) { 263 + // Guarded by linkDescs value (=locking each Link)
266 - ProviderId primary = pickPrimaryPID(descs); 264 + private Link composeLink(Map<ProviderId, LinkDescription> descs) {
267 - LinkDescription base = descs.get(primary); 265 + ProviderId primary = getBaseProviderId(descs);
266 + LinkDescription base = descs.get(verifyNotNull(primary));
268 267
269 ConnectPoint src = base.src(); 268 ConnectPoint src = base.src();
270 ConnectPoint dst = base.dst(); 269 ConnectPoint dst = base.dst();
...@@ -289,9 +288,20 @@ public class SimpleLinkStore ...@@ -289,9 +288,20 @@ public class SimpleLinkStore
289 return new DefaultLink(primary , src, dst, type, annotations); 288 return new DefaultLink(primary , src, dst, type, annotations);
290 } 289 }
291 290
292 - private ConcurrentMap<ProviderId, LinkDescription> getLinkDescriptions(LinkKey key) { 291 + private Map<ProviderId, LinkDescription> getOrCreateLinkDescriptions(LinkKey key) {
293 - return ConcurrentUtils.createIfAbsentUnchecked(linkDescs, key, 292 + Map<ProviderId, LinkDescription> r;
294 - NewConcurrentHashMap.<ProviderId, LinkDescription>ifNeeded()); 293 + r = linkDescs.get(key);
294 + if (r != null) {
295 + return r;
296 + }
297 + r = new HashMap<>();
298 + final Map<ProviderId, LinkDescription> concurrentlyAdded;
299 + concurrentlyAdded = linkDescs.putIfAbsent(key, r);
300 + if (concurrentlyAdded == null) {
301 + return r;
302 + } else {
303 + return concurrentlyAdded;
304 + }
295 } 305 }
296 306
297 private final Function<LinkKey, Link> lookupLink = new LookupLink(); 307 private final Function<LinkKey, Link> lookupLink = new LookupLink();
...@@ -302,20 +312,11 @@ public class SimpleLinkStore ...@@ -302,20 +312,11 @@ public class SimpleLinkStore
302 private final class LookupLink implements Function<LinkKey, Link> { 312 private final class LookupLink implements Function<LinkKey, Link> {
303 @Override 313 @Override
304 public Link apply(LinkKey input) { 314 public Link apply(LinkKey input) {
315 + if (input == null) {
316 + return null;
317 + } else {
305 return links.get(input); 318 return links.get(input);
306 } 319 }
307 } 320 }
308 -
309 - private static final Predicate<Provided> IS_PRIMARY = new IsPrimary();
310 - private static final Predicate<Provided> isPrimary() {
311 - return IS_PRIMARY;
312 - }
313 -
314 - private static final class IsPrimary implements Predicate<Provided> {
315 -
316 - @Override
317 - public boolean apply(Provided input) {
318 - return !input.providerId().isAncillary();
319 - }
320 } 321 }
321 } 322 }
......
...@@ -17,6 +17,7 @@ import org.onlab.onos.net.topology.GraphDescription; ...@@ -17,6 +17,7 @@ import org.onlab.onos.net.topology.GraphDescription;
17 import org.onlab.onos.net.topology.LinkWeight; 17 import org.onlab.onos.net.topology.LinkWeight;
18 import org.onlab.onos.net.topology.TopologyCluster; 18 import org.onlab.onos.net.topology.TopologyCluster;
19 import org.onlab.onos.net.topology.TopologyEdge; 19 import org.onlab.onos.net.topology.TopologyEdge;
20 +import org.onlab.packet.ChassisId;
20 21
21 import java.util.Set; 22 import java.util.Set;
22 23
...@@ -119,7 +120,7 @@ public class DefaultTopologyTest { ...@@ -119,7 +120,7 @@ public class DefaultTopologyTest {
119 // Crates a new device with the specified id 120 // Crates a new device with the specified id
120 public static Device device(String id) { 121 public static Device device(String id) {
121 return new DefaultDevice(PID, did(id), Device.Type.SWITCH, 122 return new DefaultDevice(PID, did(id), Device.Type.SWITCH,
122 - "mfg", "1.0", "1.1", "1234"); 123 + "mfg", "1.0", "1.1", "1234", new ChassisId());
123 } 124 }
124 125
125 // Short-hand for producing a device id from a string 126 // Short-hand for producing a device id from a string
......
...@@ -40,6 +40,7 @@ import org.onlab.onos.net.provider.ProviderId; ...@@ -40,6 +40,7 @@ import org.onlab.onos.net.provider.ProviderId;
40 40
41 import com.google.common.collect.Iterables; 41 import com.google.common.collect.Iterables;
42 import com.google.common.collect.Sets; 42 import com.google.common.collect.Sets;
43 +import org.onlab.packet.ChassisId;
43 44
44 /** 45 /**
45 * Test of the simple DeviceStore implementation. 46 * Test of the simple DeviceStore implementation.
...@@ -55,6 +56,7 @@ public class SimpleDeviceStoreTest { ...@@ -55,6 +56,7 @@ public class SimpleDeviceStoreTest {
55 private static final String SW1 = "3.8.1"; 56 private static final String SW1 = "3.8.1";
56 private static final String SW2 = "3.9.5"; 57 private static final String SW2 = "3.9.5";
57 private static final String SN = "43311-12345"; 58 private static final String SN = "43311-12345";
59 + private static final ChassisId CID = new ChassisId();
58 60
59 private static final PortNumber P1 = PortNumber.portNumber(1); 61 private static final PortNumber P1 = PortNumber.portNumber(1);
60 private static final PortNumber P2 = PortNumber.portNumber(2); 62 private static final PortNumber P2 = PortNumber.portNumber(2);
...@@ -107,7 +109,7 @@ public class SimpleDeviceStoreTest { ...@@ -107,7 +109,7 @@ public class SimpleDeviceStoreTest {
107 SparseAnnotations... annotations) { 109 SparseAnnotations... annotations) {
108 DeviceDescription description = 110 DeviceDescription description =
109 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR, 111 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
110 - HW, swVersion, SN, annotations); 112 + HW, swVersion, SN, CID, annotations);
111 deviceStore.createOrUpdateDevice(PID, deviceId, description); 113 deviceStore.createOrUpdateDevice(PID, deviceId, description);
112 } 114 }
113 115
...@@ -115,7 +117,7 @@ public class SimpleDeviceStoreTest { ...@@ -115,7 +117,7 @@ public class SimpleDeviceStoreTest {
115 SparseAnnotations... annotations) { 117 SparseAnnotations... annotations) {
116 DeviceDescription description = 118 DeviceDescription description =
117 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR, 119 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
118 - HW, swVersion, SN, annotations); 120 + HW, swVersion, SN, CID, annotations);
119 deviceStore.createOrUpdateDevice(PIDA, deviceId, description); 121 deviceStore.createOrUpdateDevice(PIDA, deviceId, description);
120 } 122 }
121 123
...@@ -193,14 +195,14 @@ public class SimpleDeviceStoreTest { ...@@ -193,14 +195,14 @@ public class SimpleDeviceStoreTest {
193 public final void testCreateOrUpdateDevice() { 195 public final void testCreateOrUpdateDevice() {
194 DeviceDescription description = 196 DeviceDescription description =
195 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, 197 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
196 - HW, SW1, SN); 198 + HW, SW1, SN, CID);
197 DeviceEvent event = deviceStore.createOrUpdateDevice(PID, DID1, description); 199 DeviceEvent event = deviceStore.createOrUpdateDevice(PID, DID1, description);
198 assertEquals(DEVICE_ADDED, event.type()); 200 assertEquals(DEVICE_ADDED, event.type());
199 assertDevice(DID1, SW1, event.subject()); 201 assertDevice(DID1, SW1, event.subject());
200 202
201 DeviceDescription description2 = 203 DeviceDescription description2 =
202 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, 204 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
203 - HW, SW2, SN); 205 + HW, SW2, SN, CID);
204 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2); 206 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
205 assertEquals(DEVICE_UPDATED, event2.type()); 207 assertEquals(DEVICE_UPDATED, event2.type());
206 assertDevice(DID1, SW2, event2.subject()); 208 assertDevice(DID1, SW2, event2.subject());
...@@ -212,7 +214,7 @@ public class SimpleDeviceStoreTest { ...@@ -212,7 +214,7 @@ public class SimpleDeviceStoreTest {
212 public final void testCreateOrUpdateDeviceAncillary() { 214 public final void testCreateOrUpdateDeviceAncillary() {
213 DeviceDescription description = 215 DeviceDescription description =
214 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, 216 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
215 - HW, SW1, SN, A2); 217 + HW, SW1, SN, CID, A2);
216 DeviceEvent event = deviceStore.createOrUpdateDevice(PIDA, DID1, description); 218 DeviceEvent event = deviceStore.createOrUpdateDevice(PIDA, DID1, description);
217 assertEquals(DEVICE_ADDED, event.type()); 219 assertEquals(DEVICE_ADDED, event.type());
218 assertDevice(DID1, SW1, event.subject()); 220 assertDevice(DID1, SW1, event.subject());
...@@ -222,7 +224,7 @@ public class SimpleDeviceStoreTest { ...@@ -222,7 +224,7 @@ public class SimpleDeviceStoreTest {
222 224
223 DeviceDescription description2 = 225 DeviceDescription description2 =
224 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, 226 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
225 - HW, SW2, SN, A1); 227 + HW, SW2, SN, CID, A1);
226 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2); 228 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
227 assertEquals(DEVICE_UPDATED, event2.type()); 229 assertEquals(DEVICE_UPDATED, event2.type());
228 assertDevice(DID1, SW2, event2.subject()); 230 assertDevice(DID1, SW2, event2.subject());
...@@ -238,7 +240,7 @@ public class SimpleDeviceStoreTest { ...@@ -238,7 +240,7 @@ public class SimpleDeviceStoreTest {
238 // But, Ancillary annotations will be in effect 240 // But, Ancillary annotations will be in effect
239 DeviceDescription description3 = 241 DeviceDescription description3 =
240 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, 242 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
241 - HW, SW1, SN, A2_2); 243 + HW, SW1, SN, CID, A2_2);
242 DeviceEvent event3 = deviceStore.createOrUpdateDevice(PIDA, DID1, description3); 244 DeviceEvent event3 = deviceStore.createOrUpdateDevice(PIDA, DID1, description3);
243 assertEquals(DEVICE_UPDATED, event3.type()); 245 assertEquals(DEVICE_UPDATED, event3.type());
244 // basic information will be the one from Primary 246 // basic information will be the one from Primary
...@@ -508,7 +510,7 @@ public class SimpleDeviceStoreTest { ...@@ -508,7 +510,7 @@ public class SimpleDeviceStoreTest {
508 510
509 DeviceDescription description = 511 DeviceDescription description =
510 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, 512 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
511 - HW, SW1, SN); 513 + HW, SW1, SN, CID);
512 deviceStore.setDelegate(checkAdd); 514 deviceStore.setDelegate(checkAdd);
513 deviceStore.createOrUpdateDevice(PID, DID1, description); 515 deviceStore.createOrUpdateDevice(PID, DID1, description);
514 assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS)); 516 assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS));
...@@ -516,7 +518,7 @@ public class SimpleDeviceStoreTest { ...@@ -516,7 +518,7 @@ public class SimpleDeviceStoreTest {
516 518
517 DeviceDescription description2 = 519 DeviceDescription description2 =
518 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, 520 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
519 - HW, SW2, SN); 521 + HW, SW2, SN, CID);
520 deviceStore.unsetDelegate(checkAdd); 522 deviceStore.unsetDelegate(checkAdd);
521 deviceStore.setDelegate(checkUpdate); 523 deviceStore.setDelegate(checkUpdate);
522 deviceStore.createOrUpdateDevice(PID, DID1, description2); 524 deviceStore.createOrUpdateDevice(PID, DID1, description2);
......
1 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> 1 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2 <features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" 2 <features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
3 name="onos-1.0.0"> 3 name="onos-1.0.0">
4 - <repository>mvn:org.onlab.onos/onos-features/1.0.0-SNAPSHOT/xml/features</repository> 4 + <repository>mvn:org.onlab.onos/onos-features/1.0.0-SNAPSHOT/xml/features
5 + </repository>
5 6
6 <feature name="onos-thirdparty-base" version="1.0.0" 7 <feature name="onos-thirdparty-base" version="1.0.0"
7 description="ONOS 3rd party dependencies"> 8 description="ONOS 3rd party dependencies">
...@@ -37,7 +38,8 @@ ...@@ -37,7 +38,8 @@
37 description="ONOS 3rd party dependencies"> 38 description="ONOS 3rd party dependencies">
38 <feature>war</feature> 39 <feature>war</feature>
39 <bundle>mvn:com.fasterxml.jackson.core/jackson-core/2.4.2</bundle> 40 <bundle>mvn:com.fasterxml.jackson.core/jackson-core/2.4.2</bundle>
40 - <bundle>mvn:com.fasterxml.jackson.core/jackson-annotations/2.4.2</bundle> 41 + <bundle>mvn:com.fasterxml.jackson.core/jackson-annotations/2.4.2
42 + </bundle>
41 <bundle>mvn:com.fasterxml.jackson.core/jackson-databind/2.4.2</bundle> 43 <bundle>mvn:com.fasterxml.jackson.core/jackson-databind/2.4.2</bundle>
42 <bundle>mvn:com.sun.jersey/jersey-core/1.18.1</bundle> 44 <bundle>mvn:com.sun.jersey/jersey-core/1.18.1</bundle>
43 <bundle>mvn:com.sun.jersey/jersey-server/1.18.1</bundle> 45 <bundle>mvn:com.sun.jersey/jersey-server/1.18.1</bundle>
...@@ -102,9 +104,9 @@ ...@@ -102,9 +104,9 @@
102 <bundle>mvn:org.onlab.onos/onos-of-api/1.0.0-SNAPSHOT</bundle> 104 <bundle>mvn:org.onlab.onos/onos-of-api/1.0.0-SNAPSHOT</bundle>
103 <bundle>mvn:org.onlab.onos/onos-of-ctl/1.0.0-SNAPSHOT</bundle> 105 <bundle>mvn:org.onlab.onos/onos-of-ctl/1.0.0-SNAPSHOT</bundle>
104 106
107 + <bundle>mvn:org.onlab.onos/onos-lldp-provider/1.0.0-SNAPSHOT</bundle>
108 + <bundle>mvn:org.onlab.onos/onos-host-provider/1.0.0-SNAPSHOT</bundle>
105 <bundle>mvn:org.onlab.onos/onos-of-provider-device/1.0.0-SNAPSHOT</bundle> 109 <bundle>mvn:org.onlab.onos/onos-of-provider-device/1.0.0-SNAPSHOT</bundle>
106 - <bundle>mvn:org.onlab.onos/onos-of-provider-link/1.0.0-SNAPSHOT</bundle>
107 - <bundle>mvn:org.onlab.onos/onos-of-provider-host/1.0.0-SNAPSHOT</bundle>
108 <bundle>mvn:org.onlab.onos/onos-of-provider-packet/1.0.0-SNAPSHOT</bundle> 110 <bundle>mvn:org.onlab.onos/onos-of-provider-packet/1.0.0-SNAPSHOT</bundle>
109 <bundle>mvn:org.onlab.onos/onos-of-provider-flow/1.0.0-SNAPSHOT</bundle> 111 <bundle>mvn:org.onlab.onos/onos-of-provider-flow/1.0.0-SNAPSHOT</bundle>
110 112
...@@ -154,10 +156,24 @@ ...@@ -154,10 +156,24 @@
154 <bundle>mvn:org.onlab.onos/onos-app-config/1.0.0-SNAPSHOT</bundle> 156 <bundle>mvn:org.onlab.onos/onos-app-config/1.0.0-SNAPSHOT</bundle>
155 </feature> 157 </feature>
156 158
159 + <feature name="onos-app-optical" version="1.0.0"
160 + description="ONOS optical network config">
161 + <feature>onos-api</feature>
162 + <bundle>mvn:org.onlab.onos/onos-app-optical/1.0.0-SNAPSHOT</bundle>
163 + </feature>
164 +
165 +
157 <feature name="onos-app-sdnip" version="1.0.0" 166 <feature name="onos-app-sdnip" version="1.0.0"
158 description="SDN-IP peering application"> 167 description="SDN-IP peering application">
159 <feature>onos-api</feature> 168 <feature>onos-api</feature>
160 <bundle>mvn:org.onlab.onos/onos-app-sdnip/1.0.0-SNAPSHOT</bundle> 169 <bundle>mvn:org.onlab.onos/onos-app-sdnip/1.0.0-SNAPSHOT</bundle>
161 </feature> 170 </feature>
162 171
172 + <feature name="onos-app-calendar" version="1.0.0"
173 + description="REST interface for scheduling intents from an external calendar">
174 + <feature>onos-api</feature>
175 + <feature>onos-thirdparty-web</feature>
176 + <bundle>mvn:org.onlab.onos/onos-app-calendar/1.0.0-SNAPSHOT</bundle>
177 + </feature>
178 +
163 </features> 179 </features>
......
...@@ -431,7 +431,7 @@ ...@@ -431,7 +431,7 @@
431 <plugin> 431 <plugin>
432 <groupId>org.apache.maven.plugins</groupId> 432 <groupId>org.apache.maven.plugins</groupId>
433 <artifactId>maven-checkstyle-plugin</artifactId> 433 <artifactId>maven-checkstyle-plugin</artifactId>
434 - <version>2.12.1</version> 434 + <version>2.13</version>
435 <dependencies> 435 <dependencies>
436 <dependency> 436 <dependency>
437 <groupId>org.onlab.tools</groupId> 437 <groupId>org.onlab.tools</groupId>
...@@ -521,7 +521,7 @@ ...@@ -521,7 +521,7 @@
521 <group> 521 <group>
522 <title>Core Subsystems</title> 522 <title>Core Subsystems</title>
523 <packages> 523 <packages>
524 - org.onlab.onos.impl:org.onlab.onos.cluster.impl:org.onlab.onos.net.device.impl:org.onlab.onos.net.link.impl:org.onlab.onos.net.host.impl:org.onlab.onos.net.topology.impl:org.onlab.onos.net.packet.impl:org.onlab.onos.net.flow.impl:org.onlab.onos.store.trivial.*:org.onlab.onos.net.*.impl:org.onlab.onos.event.impl:org.onlab.onos.store.*:org.onlab.onos.net.intent.impl:org.onlab.onos.net.proxyarp.impl:org.onlab.onos.mastership.impl 524 + org.onlab.onos.impl:org.onlab.onos.cluster.impl:org.onlab.onos.net.device.impl:org.onlab.onos.net.link.impl:org.onlab.onos.net.host.impl:org.onlab.onos.net.topology.impl:org.onlab.onos.net.packet.impl:org.onlab.onos.net.flow.impl:org.onlab.onos.store.trivial.*:org.onlab.onos.net.*.impl:org.onlab.onos.event.impl:org.onlab.onos.store.*:org.onlab.onos.net.intent.impl:org.onlab.onos.net.proxyarp.impl:org.onlab.onos.mastership.impl:org.onlab.onos.json:org.onlab.onos.json.*
525 </packages> 525 </packages>
526 </group> 526 </group>
527 <group> 527 <group>
...@@ -546,10 +546,11 @@ ...@@ -546,10 +546,11 @@
546 <group> 546 <group>
547 <title>Sample Applications</title> 547 <title>Sample Applications</title>
548 <packages> 548 <packages>
549 - org.onlab.onos.tvue:org.onlab.onos.fwd:org.onlab.onos.ifwd:org.onlab.onos.mobility:org.onlab.onos.proxyarp:org.onlab.onos.foo 549 + org.onlab.onos.tvue:org.onlab.onos.fwd:org.onlab.onos.ifwd:org.onlab.onos.mobility:org.onlab.onos.proxyarp:org.onlab.onos.foo:org.onlab.onos.calendar
550 </packages> 550 </packages>
551 </group> 551 </group>
552 </groups> 552 </groups>
553 + <excludePackageNames>org.onlab.thirdparty</excludePackageNames>
553 </configuration> 554 </configuration>
554 </plugin> 555 </plugin>
555 556
......
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-of-providers</artifactId>
10 + <version>1.0.0-SNAPSHOT</version>
11 + <relativePath>../pom.xml</relativePath>
12 + </parent>
13 +
14 + <artifactId>onos-of-provider-host</artifactId>
15 + <packaging>bundle</packaging>
16 +
17 + <description>ONOS OpenFlow protocol host provider</description>
18 +
19 +</project>
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-providers</artifactId>
10 + <version>1.0.0-SNAPSHOT</version>
11 + <relativePath>../pom.xml</relativePath>
12 + </parent>
13 +
14 +
15 + <artifactId>onos-host-provider</artifactId>
16 + <packaging>bundle</packaging>
17 +
18 + <description>ONOS host tracking provider</description>
19 + <dependencies>
20 + <dependency>
21 + <groupId>org.onlab.onos</groupId>
22 + <artifactId>onos-api</artifactId>
23 + <classifier>tests</classifier>
24 + <scope>test</scope>
25 + </dependency>
26 + </dependencies>
27 +
28 +
29 +
30 +</project>
1 +package org.onlab.onos.provider.host.impl;
2 +
3 +import static org.slf4j.LoggerFactory.getLogger;
4 +
5 +import org.apache.felix.scr.annotations.Activate;
6 +import org.apache.felix.scr.annotations.Component;
7 +import org.apache.felix.scr.annotations.Deactivate;
8 +import org.apache.felix.scr.annotations.Reference;
9 +import org.apache.felix.scr.annotations.ReferenceCardinality;
10 +import org.onlab.onos.net.ConnectPoint;
11 +import org.onlab.onos.net.Host;
12 +import org.onlab.onos.net.HostId;
13 +import org.onlab.onos.net.HostLocation;
14 +import org.onlab.onos.net.host.DefaultHostDescription;
15 +import org.onlab.onos.net.host.HostDescription;
16 +import org.onlab.onos.net.host.HostProvider;
17 +import org.onlab.onos.net.host.HostProviderRegistry;
18 +import org.onlab.onos.net.host.HostProviderService;
19 +import org.onlab.onos.net.packet.PacketContext;
20 +import org.onlab.onos.net.packet.PacketProcessor;
21 +import org.onlab.onos.net.packet.PacketService;
22 +import org.onlab.onos.net.provider.AbstractProvider;
23 +import org.onlab.onos.net.provider.ProviderId;
24 +import org.onlab.onos.net.topology.Topology;
25 +import org.onlab.onos.net.topology.TopologyService;
26 +import org.onlab.packet.ARP;
27 +import org.onlab.packet.Ethernet;
28 +import org.onlab.packet.IpPrefix;
29 +import org.onlab.packet.VlanId;
30 +import org.slf4j.Logger;
31 +
32 +/**
33 + * Provider which uses an OpenFlow controller to detect network
34 + * end-station hosts.
35 + */
36 +@Component(immediate = true)
37 +public class HostLocationProvider extends AbstractProvider implements HostProvider {
38 +
39 + private final Logger log = getLogger(getClass());
40 +
41 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
42 + protected HostProviderRegistry providerRegistry;
43 +
44 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
45 + protected PacketService pktService;
46 +
47 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
48 + protected TopologyService topologyService;
49 +
50 + private HostProviderService providerService;
51 +
52 + private final InternalHostProvider processor = new InternalHostProvider();
53 +
54 +
55 + /**
56 + * Creates an OpenFlow host provider.
57 + */
58 + public HostLocationProvider() {
59 + super(new ProviderId("of", "org.onlab.onos.provider.host"));
60 + }
61 +
62 + @Activate
63 + public void activate() {
64 + providerService = providerRegistry.register(this);
65 + pktService.addProcessor(processor, 1);
66 + log.info("Started");
67 + }
68 +
69 + @Deactivate
70 + public void deactivate() {
71 + providerRegistry.unregister(this);
72 + pktService.removeProcessor(processor);
73 + providerService = null;
74 + log.info("Stopped");
75 + }
76 +
77 + @Override
78 + public void triggerProbe(Host host) {
79 + log.info("Triggering probe on device {}", host);
80 + }
81 +
82 + private class InternalHostProvider implements PacketProcessor {
83 +
84 + @Override
85 + public void process(PacketContext context) {
86 + if (context == null) {
87 + return;
88 + }
89 + Ethernet eth = context.inPacket().parsed();
90 +
91 + VlanId vlan = VlanId.vlanId(eth.getVlanID());
92 + ConnectPoint heardOn = context.inPacket().receivedFrom();
93 +
94 + // If this is not an edge port, bail out.
95 + Topology topology = topologyService.currentTopology();
96 + if (topologyService.isInfrastructure(topology, heardOn)) {
97 + return;
98 + }
99 +
100 + HostLocation hloc = new HostLocation(heardOn, System.currentTimeMillis());
101 +
102 + HostId hid = HostId.hostId(eth.getSourceMAC(), vlan);
103 +
104 + // Potentially a new or moved host
105 + if (eth.getEtherType() == Ethernet.TYPE_ARP) {
106 + ARP arp = (ARP) eth.getPayload();
107 + IpPrefix ip = IpPrefix.valueOf(arp.getSenderProtocolAddress(),
108 + IpPrefix.MAX_INET_MASK);
109 + HostDescription hdescr =
110 + new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ip);
111 + providerService.hostDetected(hid, hdescr);
112 +
113 + } else if (eth.getEtherType() == Ethernet.TYPE_IPV4) {
114 + //Do not learn new ip from ip packet.
115 + HostDescription hdescr =
116 + new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc);
117 + providerService.hostDetected(hid, hdescr);
118 +
119 + }
120 + }
121 + }
122 +}
1 +/**
2 + * Provider that uses packet service as a means of host discovery and tracking.
3 + */
4 +package org.onlab.onos.provider.host.impl;
1 +package org.onlab.onos.provider.host.impl;
2 +
3 +import static org.junit.Assert.assertEquals;
4 +import static org.junit.Assert.assertNotNull;
5 +import static org.junit.Assert.assertNull;
6 +
7 +import java.nio.ByteBuffer;
8 +import java.util.Set;
9 +
10 +import org.junit.After;
11 +import org.junit.Before;
12 +import org.junit.Test;
13 +import org.onlab.onos.net.ConnectPoint;
14 +import org.onlab.onos.net.DeviceId;
15 +import org.onlab.onos.net.HostId;
16 +import org.onlab.onos.net.PortNumber;
17 +import org.onlab.onos.net.flow.TrafficTreatment;
18 +import org.onlab.onos.net.host.HostDescription;
19 +import org.onlab.onos.net.host.HostProvider;
20 +import org.onlab.onos.net.host.HostProviderRegistry;
21 +import org.onlab.onos.net.host.HostProviderService;
22 +import org.onlab.onos.net.packet.DefaultInboundPacket;
23 +import org.onlab.onos.net.packet.InboundPacket;
24 +import org.onlab.onos.net.packet.OutboundPacket;
25 +import org.onlab.onos.net.packet.PacketContext;
26 +import org.onlab.onos.net.packet.PacketProcessor;
27 +import org.onlab.onos.net.packet.PacketService;
28 +import org.onlab.onos.net.provider.AbstractProviderService;
29 +import org.onlab.onos.net.provider.ProviderId;
30 +import org.onlab.onos.net.topology.Topology;
31 +
32 +import org.onlab.onos.net.topology.TopologyServiceAdapter;
33 +import org.onlab.packet.ARP;
34 +import org.onlab.packet.Ethernet;
35 +import org.onlab.packet.MacAddress;
36 +import org.onlab.packet.VlanId;
37 +
38 +public class HostLocationProviderTest {
39 +
40 + private static final Integer INPORT = 10;
41 + private static final String DEV1 = "of:1";
42 + private static final String DEV2 = "of:2";
43 + private static final String DEV3 = "of:3";
44 +
45 + private static final VlanId VLAN = VlanId.vlanId();
46 + private static final MacAddress MAC = MacAddress.valueOf("00:00:11:00:00:01");
47 + private static final MacAddress BCMAC = MacAddress.valueOf("ff:ff:ff:ff:ff:ff");
48 + private static final byte[] IP = new byte[]{10, 0, 0, 1};
49 +
50 + private final HostLocationProvider provider = new HostLocationProvider();
51 + private final TestHostRegistry hostService = new TestHostRegistry();
52 + private final TestTopologyService topoService = new TestTopologyService();
53 + private final TestPacketService packetService = new TestPacketService();
54 +
55 + private PacketProcessor testProcessor;
56 + private TestHostProviderService providerService;
57 +
58 + @Before
59 + public void setUp() {
60 + provider.providerRegistry = hostService;
61 + provider.topologyService = topoService;
62 + provider.pktService = packetService;
63 +
64 + provider.activate();
65 +
66 + }
67 +
68 + @Test
69 + public void basics() {
70 + assertNotNull("registration expected", providerService);
71 + assertEquals("incorrect provider", provider, providerService.provider());
72 + }
73 +
74 + @Test
75 + public void events() {
76 + // new host
77 +
78 +
79 + testProcessor.process(new TestPacketContext(DEV1));
80 + assertNotNull("new host expected", providerService.added);
81 + assertNull("host motion unexpected", providerService.moved);
82 +
83 + // the host moved to new switch
84 + testProcessor.process(new TestPacketContext(DEV2));
85 + assertNotNull("host motion expected", providerService.moved);
86 +
87 + // the host was misheard on a spine
88 + testProcessor.process(new TestPacketContext(DEV3));
89 + assertNull("host misheard on spine switch", providerService.spine);
90 + }
91 +
92 + @After
93 + public void tearDown() {
94 + provider.deactivate();
95 + provider.providerRegistry = null;
96 +
97 + }
98 +
99 + private class TestHostRegistry implements HostProviderRegistry {
100 +
101 + @Override
102 + public HostProviderService register(HostProvider provider) {
103 + providerService = new TestHostProviderService(provider);
104 + return providerService;
105 + }
106 +
107 + @Override
108 + public void unregister(HostProvider provider) {
109 + }
110 +
111 + @Override
112 + public Set<ProviderId> getProviders() {
113 + return null;
114 + }
115 +
116 + }
117 +
118 + private class TestHostProviderService
119 + extends AbstractProviderService<HostProvider>
120 + implements HostProviderService {
121 +
122 + DeviceId added = null;
123 + DeviceId moved = null;
124 + DeviceId spine = null;
125 +
126 + protected TestHostProviderService(HostProvider provider) {
127 + super(provider);
128 + }
129 +
130 + @Override
131 + public void hostDetected(HostId hostId, HostDescription hostDescription) {
132 + DeviceId descr = hostDescription.location().deviceId();
133 + if (added == null) {
134 + added = descr;
135 + } else if ((moved == null) && !descr.equals(added)) {
136 + moved = descr;
137 + } else {
138 + spine = descr;
139 + }
140 + }
141 +
142 + @Override
143 + public void hostVanished(HostId hostId) {
144 + }
145 +
146 + }
147 +
148 + private class TestPacketService implements PacketService {
149 +
150 + @Override
151 + public void addProcessor(PacketProcessor processor, int priority) {
152 + testProcessor = processor;
153 + }
154 +
155 + @Override
156 + public void removeProcessor(PacketProcessor processor) {
157 +
158 + }
159 +
160 + @Override
161 + public void emit(OutboundPacket packet) {
162 +
163 + }
164 + }
165 +
166 +
167 + private class TestTopologyService extends TopologyServiceAdapter {
168 + @Override
169 + public boolean isInfrastructure(Topology topology,
170 + ConnectPoint connectPoint) {
171 + //simulate DPID3 as an infrastructure switch
172 + if ((connectPoint.deviceId()).equals(DeviceId.deviceId(DEV3))) {
173 + return true;
174 + }
175 + return false;
176 + }
177 + }
178 +
179 + private class TestPacketContext implements PacketContext {
180 +
181 + private final String deviceId;
182 +
183 + public TestPacketContext(String deviceId) {
184 + this.deviceId = deviceId;
185 + }
186 +
187 + @Override
188 + public long time() {
189 + return 0;
190 + }
191 +
192 + @Override
193 + public InboundPacket inPacket() {
194 + ARP arp = new ARP();
195 + arp.setSenderProtocolAddress(IP)
196 + .setSenderHardwareAddress(MAC.toBytes())
197 + .setTargetHardwareAddress(BCMAC.toBytes())
198 + .setTargetProtocolAddress(IP);
199 +
200 + Ethernet eth = new Ethernet();
201 + eth.setEtherType(Ethernet.TYPE_ARP)
202 + .setVlanID(VLAN.toShort())
203 + .setSourceMACAddress(MAC.toBytes())
204 + .setDestinationMACAddress(BCMAC.getAddress())
205 + .setPayload(arp);
206 + ConnectPoint receivedFrom = new ConnectPoint(DeviceId.deviceId(deviceId),
207 + PortNumber.portNumber(INPORT));
208 + return new DefaultInboundPacket(receivedFrom, eth,
209 + ByteBuffer.wrap(eth.serialize()));
210 + }
211 +
212 + @Override
213 + public OutboundPacket outPacket() {
214 + return null;
215 + }
216 +
217 + @Override
218 + public TrafficTreatment.Builder treatmentBuilder() {
219 + return null;
220 + }
221 +
222 + @Override
223 + public void send() {
224 +
225 + }
226 +
227 + @Override
228 + public boolean block() {
229 + return false;
230 + }
231 +
232 + @Override
233 + public boolean isHandled() {
234 + return false;
235 + }
236 + }
237 +}
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 +
8 + <parent>
9 + <groupId>org.onlab.onos</groupId>
10 + <artifactId>onos-providers</artifactId>
11 + <version>1.0.0-SNAPSHOT</version>
12 + <relativePath>../pom.xml</relativePath>
13 + </parent>
14 +
15 + <artifactId>onos-lldp-provider</artifactId>
16 + <packaging>bundle</packaging>
17 +
18 + <description>ONOS LLDP Link Discovery</description>
19 +
20 +</project>
1 +package org.onlab.onos.provider.lldp.impl;
2 +
3 +import org.apache.felix.scr.annotations.Activate;
4 +import org.apache.felix.scr.annotations.Component;
5 +import org.apache.felix.scr.annotations.Deactivate;
6 +import org.apache.felix.scr.annotations.Reference;
7 +import org.apache.felix.scr.annotations.ReferenceCardinality;
8 +import org.onlab.onos.mastership.MastershipService;
9 +import org.onlab.onos.net.ConnectPoint;
10 +import org.onlab.onos.net.Device;
11 +import org.onlab.onos.net.DeviceId;
12 +import org.onlab.onos.net.Port;
13 +import org.onlab.onos.net.device.DeviceEvent;
14 +import org.onlab.onos.net.device.DeviceListener;
15 +import org.onlab.onos.net.device.DeviceService;
16 +import org.onlab.onos.net.link.LinkProvider;
17 +import org.onlab.onos.net.link.LinkProviderRegistry;
18 +import org.onlab.onos.net.link.LinkProviderService;
19 +import org.onlab.onos.net.packet.PacketContext;
20 +import org.onlab.onos.net.packet.PacketProcessor;
21 +import org.onlab.onos.net.packet.PacketService;
22 +import org.onlab.onos.net.provider.AbstractProvider;
23 +import org.onlab.onos.net.provider.ProviderId;
24 +import org.slf4j.Logger;
25 +
26 +import java.util.Map;
27 +import java.util.concurrent.ConcurrentHashMap;
28 +
29 +import static org.slf4j.LoggerFactory.getLogger;
30 +
31 +
32 +/**
33 + * Provider which uses an OpenFlow controller to detect network
34 + * infrastructure links.
35 + */
36 +@Component(immediate = true)
37 +public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
38 +
39 + private final Logger log = getLogger(getClass());
40 +
41 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
42 + protected LinkProviderRegistry providerRegistry;
43 +
44 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
45 + protected DeviceService deviceService;
46 +
47 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
48 + protected PacketService packetSevice;
49 +
50 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
51 + protected MastershipService masterService;
52 +
53 + private LinkProviderService providerService;
54 +
55 + private final boolean useBDDP = true;
56 +
57 +
58 + private final InternalLinkProvider listener = new InternalLinkProvider();
59 +
60 + protected final Map<DeviceId, LinkDiscovery> discoverers = new ConcurrentHashMap<>();
61 +
62 + /**
63 + * Creates an OpenFlow link provider.
64 + */
65 + public LLDPLinkProvider() {
66 + super(new ProviderId("lldp", "org.onlab.onos.provider.lldp"));
67 + }
68 +
69 + @Activate
70 + public void activate() {
71 + providerService = providerRegistry.register(this);
72 + deviceService.addListener(listener);
73 + packetSevice.addProcessor(listener, 0);
74 +
75 + log.info("Started");
76 + }
77 +
78 + @Deactivate
79 + public void deactivate() {
80 + for (LinkDiscovery ld : discoverers.values()) {
81 + ld.stop();
82 + }
83 + providerRegistry.unregister(this);
84 + deviceService.removeListener(listener);
85 + packetSevice.removeProcessor(listener);
86 + providerService = null;
87 +
88 + log.info("Stopped");
89 + }
90 +
91 +
92 + private class InternalLinkProvider implements PacketProcessor, DeviceListener {
93 +
94 + @Override
95 + public void event(DeviceEvent event) {
96 + LinkDiscovery ld = null;
97 + Device device = event.subject();
98 + Port port = event.port();
99 + switch (event.type()) {
100 + case DEVICE_ADDED:
101 + discoverers.put(device.id(),
102 + new LinkDiscovery(device, packetSevice, masterService,
103 + providerService, useBDDP));
104 + break;
105 + case PORT_ADDED:
106 + case PORT_UPDATED:
107 + if (event.port().isEnabled()) {
108 + ld = discoverers.get(device.id());
109 + if (ld == null) {
110 + return;
111 + }
112 + ld.addPort(port);
113 + } else {
114 + ConnectPoint point = new ConnectPoint(device.id(),
115 + port.number());
116 + providerService.linksVanished(point);
117 + }
118 + break;
119 + case PORT_REMOVED:
120 + ConnectPoint point = new ConnectPoint(device.id(),
121 + port.number());
122 + providerService.linksVanished(point);
123 + break;
124 + case DEVICE_REMOVED:
125 + case DEVICE_SUSPENDED:
126 + ld = discoverers.get(device.id());
127 + if (ld == null) {
128 + return;
129 + }
130 + ld.stop();
131 + providerService.linksVanished(device.id());
132 + break;
133 + case DEVICE_AVAILABILITY_CHANGED:
134 + ld = discoverers.get(device.id());
135 + if (ld == null) {
136 + return;
137 + }
138 + if (deviceService.isAvailable(device.id())) {
139 + ld.start();
140 + } else {
141 + providerService.linksVanished(device.id());
142 + ld.stop();
143 + }
144 + break;
145 + case DEVICE_UPDATED:
146 + case DEVICE_MASTERSHIP_CHANGED:
147 + break;
148 + default:
149 + log.debug("Unknown event {}", event);
150 + }
151 + }
152 +
153 + @Override
154 + public void process(PacketContext context) {
155 + if (context == null) {
156 + return;
157 + }
158 + LinkDiscovery ld = discoverers.get(
159 + context.inPacket().receivedFrom().deviceId());
160 + if (ld == null) {
161 + return;
162 + }
163 +
164 + if (ld.handleLLDP(context)) {
165 + context.block();
166 + }
167 + }
168 + }
169 +
170 +}
1 +/*******************************************************************************
2 + * Copyright 2014 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + ******************************************************************************/
16 +package org.onlab.onos.provider.lldp.impl;
17 +
18 +
19 +import static org.slf4j.LoggerFactory.getLogger;
20 +
21 +import java.nio.ByteBuffer;
22 +import java.util.Collections;
23 +import java.util.HashMap;
24 +import java.util.HashSet;
25 +import java.util.Iterator;
26 +import java.util.Map;
27 +import java.util.Set;
28 +import java.util.concurrent.TimeUnit;
29 +import java.util.concurrent.atomic.AtomicInteger;
30 +
31 +import org.jboss.netty.util.Timeout;
32 +import org.jboss.netty.util.TimerTask;
33 +import org.onlab.onos.mastership.MastershipService;
34 +import org.onlab.onos.net.ConnectPoint;
35 +import org.onlab.onos.net.Device;
36 +import org.onlab.onos.net.DeviceId;
37 +import org.onlab.onos.net.Link.Type;
38 +import org.onlab.onos.net.MastershipRole;
39 +import org.onlab.onos.net.Port;
40 +import org.onlab.onos.net.PortNumber;
41 +import org.onlab.onos.net.flow.DefaultTrafficTreatment;
42 +import org.onlab.onos.net.link.DefaultLinkDescription;
43 +import org.onlab.onos.net.link.LinkDescription;
44 +import org.onlab.onos.net.link.LinkProviderService;
45 +import org.onlab.onos.net.packet.DefaultOutboundPacket;
46 +import org.onlab.onos.net.packet.OutboundPacket;
47 +import org.onlab.onos.net.packet.PacketContext;
48 +import org.onlab.onos.net.packet.PacketService;
49 +import org.onlab.packet.Ethernet;
50 +import org.onlab.packet.ONOSLLDP;
51 +import org.onlab.util.Timer;
52 +import org.slf4j.Logger;
53 +
54 +
55 +
56 +/**
57 + * Run discovery process from a physical switch. Ports are initially labeled as
58 + * slow ports. When an LLDP is successfully received, label the remote port as
59 + * fast. Every probeRate milliseconds, loop over all fast ports and send an
60 + * LLDP, send an LLDP for a single slow port. Based on FlowVisor topology
61 + * discovery implementation.
62 + *
63 + * TODO: add 'fast discovery' mode: drop LLDPs in destination switch but listen
64 + * for flow_removed messages
65 + */
66 +public class LinkDiscovery implements TimerTask {
67 +
68 + private final Device device;
69 + // send 1 probe every probeRate milliseconds
70 + private final long probeRate;
71 + private final Set<Long> slowPorts;
72 + private final Set<Long> fastPorts;
73 + // number of unacknowledged probes per port
74 + private final Map<Long, AtomicInteger> portProbeCount;
75 + // number of probes to send before link is removed
76 + private static final short MAX_PROBE_COUNT = 3;
77 + private final Logger log = getLogger(getClass());
78 + private final ONOSLLDP lldpPacket;
79 + private final Ethernet ethPacket;
80 + private Ethernet bddpEth;
81 + private final boolean useBDDP;
82 + private final LinkProviderService linkProvider;
83 + private final PacketService pktService;
84 + private final MastershipService mastershipService;
85 + private Timeout timeout;
86 +
87 + /**
88 + * Instantiates discovery manager for the given physical switch. Creates a
89 + * generic LLDP packet that will be customized for the port it is sent out on.
90 + * Starts the the timer for the discovery process.
91 + * @param device the physical switch
92 + * @param masterService
93 + * @param useBDDP flag to also use BDDP for discovery
94 + */
95 + public LinkDiscovery(Device device, PacketService pktService,
96 + MastershipService masterService, LinkProviderService providerService, Boolean... useBDDP) {
97 + this.device = device;
98 + this.probeRate = 3000;
99 + this.linkProvider = providerService;
100 + this.pktService = pktService;
101 + this.mastershipService = masterService;
102 + this.slowPorts = Collections.synchronizedSet(new HashSet<Long>());
103 + this.fastPorts = Collections.synchronizedSet(new HashSet<Long>());
104 + this.portProbeCount = new HashMap<>();
105 + this.lldpPacket = new ONOSLLDP();
106 + this.lldpPacket.setChassisId(device.chassisId());
107 + this.lldpPacket.setDevice(device.id().toString());
108 +
109 +
110 + this.ethPacket = new Ethernet();
111 + this.ethPacket.setEtherType(Ethernet.TYPE_LLDP);
112 + this.ethPacket.setDestinationMACAddress(ONOSLLDP.LLDP_NICIRA);
113 + this.ethPacket.setPayload(this.lldpPacket);
114 + this.ethPacket.setPad(true);
115 + this.useBDDP = useBDDP.length > 0 ? useBDDP[0] : false;
116 + if (this.useBDDP) {
117 + this.bddpEth = new Ethernet();
118 + this.bddpEth.setPayload(this.lldpPacket);
119 + this.bddpEth.setEtherType(Ethernet.TYPE_BSN);
120 + this.bddpEth.setDestinationMACAddress(ONOSLLDP.BDDP_MULTICAST);
121 + this.bddpEth.setPad(true);
122 + log.info("Using BDDP to discover network");
123 + }
124 +
125 + start();
126 + this.log.debug("Started discovery manager for switch {}",
127 + device.id());
128 +
129 + }
130 +
131 + /**
132 + * Add physical port port to discovery process.
133 + * Send out initial LLDP and label it as slow port.
134 + *
135 + * @param port the port
136 + */
137 + public void addPort(final Port port) {
138 + this.log.debug("sending init probe to port {}",
139 + port.number().toLong());
140 +
141 + sendProbes(port.number().toLong());
142 +
143 + synchronized (this) {
144 + this.slowPorts.add(port.number().toLong());
145 + }
146 +
147 +
148 + }
149 +
150 + /**
151 + * Removes physical port from discovery process.
152 + *
153 + * @param port the port
154 + */
155 + public void removePort(final Port port) {
156 + // Ignore ports that are not on this switch
157 +
158 + long portnum = port.number().toLong();
159 + synchronized (this) {
160 + if (this.slowPorts.contains(portnum)) {
161 + this.slowPorts.remove(portnum);
162 +
163 + } else if (this.fastPorts.contains(portnum)) {
164 + this.fastPorts.remove(portnum);
165 + this.portProbeCount.remove(portnum);
166 + // no iterator to update
167 + } else {
168 + this.log.warn(
169 + "tried to dynamically remove non-existing port {}",
170 + portnum);
171 + }
172 + }
173 + }
174 +
175 + /**
176 + * Method called by remote port to acknowledge receipt of LLDP sent by
177 + * this port. If slow port, updates label to fast. If fast port, decrements
178 + * number of unacknowledged probes.
179 + *
180 + * @param portNumber the port
181 + */
182 + public void ackProbe(final Long portNumber) {
183 +
184 + synchronized (this) {
185 + if (this.slowPorts.contains(portNumber)) {
186 + this.log.debug("Setting slow port to fast: {}:{}",
187 + this.device.id(), portNumber);
188 + this.slowPorts.remove(portNumber);
189 + this.fastPorts.add(portNumber);
190 + this.portProbeCount.put(portNumber, new AtomicInteger(0));
191 + } else if (this.fastPorts.contains(portNumber)) {
192 + this.portProbeCount.get(portNumber).set(0);
193 + } else {
194 + this.log.debug(
195 + "Got ackProbe for non-existing port: {}",
196 + portNumber);
197 +
198 + }
199 + }
200 + }
201 +
202 +
203 + /**
204 + * Handles an incoming LLDP packet. Creates link in topology and sends ACK
205 + * to port where LLDP originated.
206 + */
207 + public boolean handleLLDP(PacketContext context) {
208 + Ethernet eth = context.inPacket().parsed();
209 + ONOSLLDP onoslldp = ONOSLLDP.parseONOSLLDP(eth);
210 + if (onoslldp != null) {
211 + final PortNumber dstPort =
212 + context.inPacket().receivedFrom().port();
213 + final PortNumber srcPort = PortNumber.portNumber(onoslldp.getPort());
214 + final DeviceId srcDeviceId = DeviceId.deviceId(onoslldp.getDeviceString());
215 + final DeviceId dstDeviceId = context.inPacket().receivedFrom().deviceId();
216 + this.ackProbe(srcPort.toLong());
217 + ConnectPoint src = new ConnectPoint(srcDeviceId, srcPort);
218 + ConnectPoint dst = new ConnectPoint(dstDeviceId, dstPort);
219 +
220 + LinkDescription ld;
221 + if (eth.getEtherType() == Ethernet.TYPE_BSN) {
222 + ld = new DefaultLinkDescription(src, dst, Type.INDIRECT);
223 + } else {
224 + ld = new DefaultLinkDescription(src, dst, Type.DIRECT);
225 + }
226 + linkProvider.linkDetected(ld);
227 + return true;
228 + }
229 + return false;
230 + }
231 +
232 +
233 +
234 + /**
235 + * Execute this method every t milliseconds. Loops over all ports
236 + * labeled as fast and sends out an LLDP. Send out an LLDP on a single slow
237 + * port.
238 + *
239 + * @param t timeout
240 + * @throws Exception
241 + */
242 + @Override
243 + public void run(final Timeout t) {
244 + this.log.debug("sending probes");
245 + synchronized (this) {
246 + final Iterator<Long> fastIterator = this.fastPorts.iterator();
247 + Long portNumber;
248 + Integer probeCount;
249 + while (fastIterator.hasNext()) {
250 + portNumber = fastIterator.next();
251 + probeCount = this.portProbeCount.get(portNumber)
252 + .getAndIncrement();
253 +
254 + if (probeCount < LinkDiscovery.MAX_PROBE_COUNT) {
255 + this.log.debug("sending fast probe to port");
256 + sendProbes(portNumber);
257 + } else {
258 + // Update fast and slow ports
259 + //fastIterator.remove();
260 + //this.slowPorts.add(portNumber);
261 + //this.portProbeCount.remove(portNumber);
262 + this.portProbeCount.get(portNumber).set(0);
263 +
264 + ConnectPoint cp = new ConnectPoint(
265 + device.id(),
266 + PortNumber.portNumber(portNumber));
267 + log.debug("Link down -> {}", cp);
268 + linkProvider.linksVanished(cp);
269 + }
270 + }
271 +
272 + // send a probe for the next slow port
273 + if (!this.slowPorts.isEmpty()) {
274 + Iterator<Long> slowIterator = this.slowPorts.iterator();
275 + while (slowIterator.hasNext()) {
276 + portNumber = slowIterator.next();
277 + this.log.debug("sending slow probe to port {}", portNumber);
278 +
279 + sendProbes(portNumber);
280 +
281 + }
282 + }
283 + }
284 +
285 + // reschedule timer
286 + timeout = Timer.getTimer().newTimeout(this, this.probeRate,
287 + TimeUnit.MILLISECONDS);
288 + }
289 +
290 + public void stop() {
291 + timeout.cancel();
292 + }
293 +
294 + public void start() {
295 + timeout = Timer.getTimer().newTimeout(this, 0,
296 + TimeUnit.MILLISECONDS);
297 + }
298 +
299 + /**
300 + * Creates packet_out LLDP for specified output port.
301 + *
302 + * @param port the port
303 + * @return Packet_out message with LLDP data
304 + */
305 + private OutboundPacket createOutBoundLLDP(final Long port) {
306 + if (port == null) {
307 + return null;
308 + }
309 + this.lldpPacket.setPortId(port.intValue());
310 + this.ethPacket.setSourceMACAddress("DE:AD:BE:EF:BA:11");
311 +
312 + final byte[] lldp = this.ethPacket.serialize();
313 + OutboundPacket outboundPacket = new DefaultOutboundPacket(
314 + this.device.id(),
315 + DefaultTrafficTreatment.builder().setOutput(
316 + PortNumber.portNumber(port)).build(),
317 + ByteBuffer.wrap(lldp));
318 + return outboundPacket;
319 + }
320 +
321 + /**
322 + * Creates packet_out BDDP for specified output port.
323 + *
324 + * @param port the port
325 + * @return Packet_out message with LLDP data
326 + */
327 + private OutboundPacket createOutBoundBDDP(final Long port) {
328 + if (port == null) {
329 + return null;
330 + }
331 + this.lldpPacket.setPortId(port.intValue());
332 + this.bddpEth.setSourceMACAddress("DE:AD:BE:EF:BA:11");
333 +
334 + final byte[] bddp = this.bddpEth.serialize();
335 + OutboundPacket outboundPacket = new DefaultOutboundPacket(
336 + this.device.id(),
337 + DefaultTrafficTreatment.builder()
338 + .setOutput(PortNumber.portNumber(port)).build(),
339 + ByteBuffer.wrap(bddp));
340 + return outboundPacket;
341 + }
342 +
343 + private void sendProbes(Long portNumber) {
344 + if (mastershipService.getLocalRole(this.device.id()) ==
345 + MastershipRole.MASTER) {
346 + OutboundPacket pkt = this.createOutBoundLLDP(portNumber);
347 + pktService.emit(pkt);
348 + if (useBDDP) {
349 + OutboundPacket bpkt = this.createOutBoundBDDP(portNumber);
350 + pktService.emit(bpkt);
351 + }
352 + }
353 + }
354 +
355 +}
1 +/**
2 + * Provider that uses the core as a means of infrastructure link inference.
3 + */
4 +package org.onlab.onos.provider.lldp.impl;
...@@ -23,6 +23,7 @@ import org.onlab.onos.openflow.controller.OpenFlowController; ...@@ -23,6 +23,7 @@ import org.onlab.onos.openflow.controller.OpenFlowController;
23 import org.onlab.onos.openflow.controller.OpenFlowSwitch; 23 import org.onlab.onos.openflow.controller.OpenFlowSwitch;
24 import org.onlab.onos.openflow.controller.OpenFlowSwitchListener; 24 import org.onlab.onos.openflow.controller.OpenFlowSwitchListener;
25 import org.onlab.onos.openflow.controller.RoleState; 25 import org.onlab.onos.openflow.controller.RoleState;
26 +import org.onlab.packet.ChassisId;
26 import org.projectfloodlight.openflow.protocol.OFPortConfig; 27 import org.projectfloodlight.openflow.protocol.OFPortConfig;
27 import org.projectfloodlight.openflow.protocol.OFPortDesc; 28 import org.projectfloodlight.openflow.protocol.OFPortDesc;
28 import org.projectfloodlight.openflow.protocol.OFPortState; 29 import org.projectfloodlight.openflow.protocol.OFPortState;
...@@ -117,13 +118,14 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr ...@@ -117,13 +118,14 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
117 } 118 }
118 DeviceId did = deviceId(uri(dpid)); 119 DeviceId did = deviceId(uri(dpid));
119 OpenFlowSwitch sw = controller.getSwitch(dpid); 120 OpenFlowSwitch sw = controller.getSwitch(dpid);
120 - 121 + ChassisId cId = new ChassisId(dpid.value());
121 DeviceDescription description = 122 DeviceDescription description =
122 new DefaultDeviceDescription(did.uri(), Device.Type.SWITCH, 123 new DefaultDeviceDescription(did.uri(), Device.Type.SWITCH,
123 sw.manfacturerDescription(), 124 sw.manfacturerDescription(),
124 sw.hardwareDescription(), 125 sw.hardwareDescription(),
125 sw.softwareDescription(), 126 sw.softwareDescription(),
126 - sw.serialNumber()); 127 + sw.serialNumber(),
128 + cId);
127 providerService.deviceConnected(did, description); 129 providerService.deviceConnected(did, description);
128 providerService.updatePorts(did, buildPortDescriptions(sw.getPorts())); 130 providerService.updatePorts(did, buildPortDescriptions(sw.getPorts()));
129 } 131 }
...@@ -170,7 +172,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr ...@@ -170,7 +172,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
170 */ 172 */
171 private List<PortDescription> buildPortDescriptions( 173 private List<PortDescription> buildPortDescriptions(
172 List<OFPortDesc> ports) { 174 List<OFPortDesc> ports) {
173 - final List<PortDescription> portDescs = new ArrayList<>(); 175 + final List<PortDescription> portDescs = new ArrayList<>(ports.size());
174 for (OFPortDesc port : ports) { 176 for (OFPortDesc port : ports) {
175 portDescs.add(buildPortDescription(port)); 177 portDescs.add(buildPortDescription(port));
176 } 178 }
......
...@@ -59,7 +59,7 @@ public class OpenFlowDeviceProviderTest { ...@@ -59,7 +59,7 @@ public class OpenFlowDeviceProviderTest {
59 private static final List<OFPortDesc> PLIST = Lists.newArrayList(PD1, PD2); 59 private static final List<OFPortDesc> PLIST = Lists.newArrayList(PD1, PD2);
60 60
61 private static final Device DEV1 = 61 private static final Device DEV1 =
62 - new DefaultDevice(PID, DID1, SWITCH, "", "", "", ""); 62 + new DefaultDevice(PID, DID1, SWITCH, "", "", "", "", null);
63 63
64 private static final TestOpenFlowSwitch SW1 = new TestOpenFlowSwitch(); 64 private static final TestOpenFlowSwitch SW1 = new TestOpenFlowSwitch();
65 65
......
...@@ -35,6 +35,7 @@ import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyAct ...@@ -35,6 +35,7 @@ import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyAct
35 import org.projectfloodlight.openflow.protocol.match.Match; 35 import org.projectfloodlight.openflow.protocol.match.Match;
36 import org.projectfloodlight.openflow.protocol.match.MatchField; 36 import org.projectfloodlight.openflow.protocol.match.MatchField;
37 import org.projectfloodlight.openflow.types.IPv4Address; 37 import org.projectfloodlight.openflow.types.IPv4Address;
38 +import org.projectfloodlight.openflow.types.Masked;
38 import org.slf4j.Logger; 39 import org.slf4j.Logger;
39 40
40 import com.google.common.collect.Lists; 41 import com.google.common.collect.Lists;
...@@ -218,23 +219,35 @@ public class FlowEntryBuilder { ...@@ -218,23 +219,35 @@ public class FlowEntryBuilder {
218 builder.matchEthType((short) ethType); 219 builder.matchEthType((short) ethType);
219 break; 220 break;
220 case IPV4_DST: 221 case IPV4_DST:
221 - IPv4Address di = match.get(MatchField.IPV4_DST);
222 IpPrefix dip; 222 IpPrefix dip;
223 - if (di.isCidrMask()) { 223 + if (match.isPartiallyMasked(MatchField.IPV4_DST)) {
224 - dip = IpPrefix.valueOf(di.getInt(), di.asCidrMaskLength()); 224 + Masked<IPv4Address> maskedIp = match.getMasked(MatchField.IPV4_DST);
225 +
226 + dip = IpPrefix.valueOf(
227 + maskedIp.getValue().getInt(),
228 + maskedIp.getMask().asCidrMaskLength());
225 } else { 229 } else {
226 - dip = IpPrefix.valueOf(di.getInt()); 230 + dip = IpPrefix.valueOf(
231 + match.get(MatchField.IPV4_DST).getInt(),
232 + IpPrefix.MAX_INET_MASK);
227 } 233 }
234 +
228 builder.matchIPDst(dip); 235 builder.matchIPDst(dip);
229 break; 236 break;
230 case IPV4_SRC: 237 case IPV4_SRC:
231 - IPv4Address si = match.get(MatchField.IPV4_SRC);
232 IpPrefix sip; 238 IpPrefix sip;
233 - if (si.isCidrMask()) { 239 + if (match.isPartiallyMasked(MatchField.IPV4_SRC)) {
234 - sip = IpPrefix.valueOf(si.getInt(), si.asCidrMaskLength()); 240 + Masked<IPv4Address> maskedIp = match.getMasked(MatchField.IPV4_SRC);
241 +
242 + sip = IpPrefix.valueOf(
243 + maskedIp.getValue().getInt(),
244 + maskedIp.getMask().asCidrMaskLength());
235 } else { 245 } else {
236 - sip = IpPrefix.valueOf(si.getInt()); 246 + sip = IpPrefix.valueOf(
247 + match.get(MatchField.IPV4_SRC).getInt(),
248 + IpPrefix.MAX_INET_MASK);
237 } 249 }
250 +
238 builder.matchIPSrc(sip); 251 builder.matchIPSrc(sip);
239 break; 252 break;
240 case IP_PROTO: 253 case IP_PROTO:
...@@ -249,6 +262,12 @@ public class FlowEntryBuilder { ...@@ -249,6 +262,12 @@ public class FlowEntryBuilder {
249 VlanId vlanId = VlanId.vlanId(match.get(MatchField.VLAN_VID).getVlan()); 262 VlanId vlanId = VlanId.vlanId(match.get(MatchField.VLAN_VID).getVlan());
250 builder.matchVlanId(vlanId); 263 builder.matchVlanId(vlanId);
251 break; 264 break;
265 + case TCP_DST:
266 + builder.matchTcpDst((short) match.get(MatchField.TCP_DST).getPort());
267 + break;
268 + case TCP_SRC:
269 + builder.matchTcpSrc((short) match.get(MatchField.TCP_SRC).getPort());
270 + break;
252 case ARP_OP: 271 case ARP_OP:
253 case ARP_SHA: 272 case ARP_SHA:
254 case ARP_SPA: 273 case ARP_SPA:
...@@ -272,8 +291,6 @@ public class FlowEntryBuilder { ...@@ -272,8 +291,6 @@ public class FlowEntryBuilder {
272 case MPLS_TC: 291 case MPLS_TC:
273 case SCTP_DST: 292 case SCTP_DST:
274 case SCTP_SRC: 293 case SCTP_SRC:
275 - case TCP_DST:
276 - case TCP_SRC:
277 case TUNNEL_ID: 294 case TUNNEL_ID:
278 case UDP_DST: 295 case UDP_DST:
279 case UDP_SRC: 296 case UDP_SRC:
......
...@@ -15,6 +15,7 @@ import org.onlab.onos.net.flow.criteria.Criteria.EthTypeCriterion; ...@@ -15,6 +15,7 @@ import org.onlab.onos.net.flow.criteria.Criteria.EthTypeCriterion;
15 import org.onlab.onos.net.flow.criteria.Criteria.IPCriterion; 15 import org.onlab.onos.net.flow.criteria.Criteria.IPCriterion;
16 import org.onlab.onos.net.flow.criteria.Criteria.IPProtocolCriterion; 16 import org.onlab.onos.net.flow.criteria.Criteria.IPProtocolCriterion;
17 import org.onlab.onos.net.flow.criteria.Criteria.PortCriterion; 17 import org.onlab.onos.net.flow.criteria.Criteria.PortCriterion;
18 +import org.onlab.onos.net.flow.criteria.Criteria.TcpPortCriterion;
18 import org.onlab.onos.net.flow.criteria.Criteria.VlanIdCriterion; 19 import org.onlab.onos.net.flow.criteria.Criteria.VlanIdCriterion;
19 import org.onlab.onos.net.flow.criteria.Criteria.VlanPcpCriterion; 20 import org.onlab.onos.net.flow.criteria.Criteria.VlanPcpCriterion;
20 import org.onlab.onos.net.flow.criteria.Criterion; 21 import org.onlab.onos.net.flow.criteria.Criterion;
...@@ -42,6 +43,7 @@ import org.projectfloodlight.openflow.types.Masked; ...@@ -42,6 +43,7 @@ import org.projectfloodlight.openflow.types.Masked;
42 import org.projectfloodlight.openflow.types.OFBufferId; 43 import org.projectfloodlight.openflow.types.OFBufferId;
43 import org.projectfloodlight.openflow.types.OFPort; 44 import org.projectfloodlight.openflow.types.OFPort;
44 import org.projectfloodlight.openflow.types.OFVlanVidMatch; 45 import org.projectfloodlight.openflow.types.OFVlanVidMatch;
46 +import org.projectfloodlight.openflow.types.TransportPort;
45 import org.projectfloodlight.openflow.types.U64; 47 import org.projectfloodlight.openflow.types.U64;
46 import org.projectfloodlight.openflow.types.VlanPcp; 48 import org.projectfloodlight.openflow.types.VlanPcp;
47 import org.projectfloodlight.openflow.types.VlanVid; 49 import org.projectfloodlight.openflow.types.VlanVid;
...@@ -199,6 +201,7 @@ public class FlowModBuilder { ...@@ -199,6 +201,7 @@ public class FlowModBuilder {
199 Match.Builder mBuilder = factory.buildMatch(); 201 Match.Builder mBuilder = factory.buildMatch();
200 EthCriterion eth; 202 EthCriterion eth;
201 IPCriterion ip; 203 IPCriterion ip;
204 + TcpPortCriterion tp;
202 for (Criterion c : selector.criteria()) { 205 for (Criterion c : selector.criteria()) {
203 switch (c.type()) { 206 switch (c.type()) {
204 case IN_PORT: 207 case IN_PORT:
...@@ -250,6 +253,14 @@ public class FlowModBuilder { ...@@ -250,6 +253,14 @@ public class FlowModBuilder {
250 mBuilder.setExact(MatchField.VLAN_VID, 253 mBuilder.setExact(MatchField.VLAN_VID,
251 OFVlanVidMatch.ofVlanVid(VlanVid.ofVlan(vid.vlanId().toShort()))); 254 OFVlanVidMatch.ofVlanVid(VlanVid.ofVlan(vid.vlanId().toShort())));
252 break; 255 break;
256 + case TCP_DST:
257 + tp = (TcpPortCriterion) c;
258 + mBuilder.setExact(MatchField.TCP_DST, TransportPort.of(tp.tcpPort()));
259 + break;
260 + case TCP_SRC:
261 + tp = (TcpPortCriterion) c;
262 + mBuilder.setExact(MatchField.TCP_SRC, TransportPort.of(tp.tcpPort()));
263 + break;
253 case ARP_OP: 264 case ARP_OP:
254 case ARP_SHA: 265 case ARP_SHA:
255 case ARP_SPA: 266 case ARP_SPA:
...@@ -276,8 +287,6 @@ public class FlowModBuilder { ...@@ -276,8 +287,6 @@ public class FlowModBuilder {
276 case PBB_ISID: 287 case PBB_ISID:
277 case SCTP_DST: 288 case SCTP_DST:
278 case SCTP_SRC: 289 case SCTP_SRC:
279 - case TCP_DST:
280 - case TCP_SRC:
281 case TUNNEL_ID: 290 case TUNNEL_ID:
282 case UDP_DST: 291 case UDP_DST:
283 case UDP_SRC: 292 case UDP_SRC:
......
1 package org.onlab.onos.provider.of.flow.impl; 1 package org.onlab.onos.provider.of.flow.impl;
2 2
3 -import static org.slf4j.LoggerFactory.getLogger; 3 +import com.google.common.collect.ArrayListMultimap;
4 - 4 +import com.google.common.collect.Lists;
5 -import java.util.HashMap; 5 +import com.google.common.collect.Maps;
6 -import java.util.HashSet; 6 +import com.google.common.collect.Multimap;
7 -import java.util.List;
8 -import java.util.Map;
9 -import java.util.Set;
10 -import java.util.concurrent.ConcurrentHashMap;
11 -import java.util.concurrent.CountDownLatch;
12 -import java.util.concurrent.ExecutionException;
13 -import java.util.concurrent.Future;
14 -import java.util.concurrent.TimeUnit;
15 -import java.util.concurrent.TimeoutException;
16 -import java.util.concurrent.atomic.AtomicBoolean;
17 -
18 import org.apache.felix.scr.annotations.Activate; 7 import org.apache.felix.scr.annotations.Activate;
19 import org.apache.felix.scr.annotations.Component; 8 import org.apache.felix.scr.annotations.Component;
20 import org.apache.felix.scr.annotations.Deactivate; 9 import org.apache.felix.scr.annotations.Deactivate;
...@@ -68,10 +57,20 @@ import org.projectfloodlight.openflow.types.OFPort; ...@@ -68,10 +57,20 @@ import org.projectfloodlight.openflow.types.OFPort;
68 import org.projectfloodlight.openflow.types.U32; 57 import org.projectfloodlight.openflow.types.U32;
69 import org.slf4j.Logger; 58 import org.slf4j.Logger;
70 59
71 -import com.google.common.collect.ArrayListMultimap; 60 +import java.util.HashMap;
72 -import com.google.common.collect.Lists; 61 +import java.util.HashSet;
73 -import com.google.common.collect.Maps; 62 +import java.util.List;
74 -import com.google.common.collect.Multimap; 63 +import java.util.Map;
64 +import java.util.Set;
65 +import java.util.concurrent.ConcurrentHashMap;
66 +import java.util.concurrent.CountDownLatch;
67 +import java.util.concurrent.ExecutionException;
68 +import java.util.concurrent.Future;
69 +import java.util.concurrent.TimeUnit;
70 +import java.util.concurrent.TimeoutException;
71 +import java.util.concurrent.atomic.AtomicBoolean;
72 +
73 +import static org.slf4j.LoggerFactory.getLogger;
75 74
76 /** 75 /**
77 * Provider which uses an OpenFlow controller to detect network 76 * Provider which uses an OpenFlow controller to detect network
...@@ -166,6 +165,16 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -166,6 +165,16 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
166 for (FlowRuleBatchEntry fbe : batch.getOperations()) { 165 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
167 FlowRule flowRule = fbe.getTarget(); 166 FlowRule flowRule = fbe.getTarget();
168 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri())); 167 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
168 + if (sw == null) {
169 + /*
170 + * if a switch we are supposed to install to is gone then
171 + * cancel (ie. rollback) the work that has been done so far
172 + * and return the associated future.
173 + */
174 + InstallationFuture failed = new InstallationFuture(sws, fmXids);
175 + failed.cancel(true);
176 + return failed;
177 + }
169 sws.add(new Dpid(sw.getId())); 178 sws.add(new Dpid(sw.getId()));
170 FlowModBuilder builder = new FlowModBuilder(flowRule, sw.factory()); 179 FlowModBuilder builder = new FlowModBuilder(flowRule, sw.factory());
171 switch (fbe.getOperator()) { 180 switch (fbe.getOperator()) {
...@@ -322,6 +331,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -322,6 +331,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
322 331
323 public void fail(OFErrorMsg msg, Dpid dpid) { 332 public void fail(OFErrorMsg msg, Dpid dpid) {
324 ok.set(false); 333 ok.set(false);
334 + removeRequirement(dpid);
325 FlowEntry fe = null; 335 FlowEntry fe = null;
326 FlowRuleBatchEntry fbe = fms.get(msg.getXid()); 336 FlowRuleBatchEntry fbe = fms.get(msg.getXid());
327 FlowRule offending = fbe.getTarget(); 337 FlowRule offending = fbe.getTarget();
...@@ -374,11 +384,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -374,11 +384,8 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
374 384
375 385
376 public void satisfyRequirement(Dpid dpid) { 386 public void satisfyRequirement(Dpid dpid) {
377 - log.warn("Satisfaction from switch {}", dpid); 387 + log.debug("Satisfaction from switch {}", dpid);
378 - sws.remove(dpid); 388 + removeRequirement(dpid);
379 - countDownLatch.countDown();
380 - cleanUp();
381 -
382 } 389 }
383 390
384 391
...@@ -395,6 +402,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -395,6 +402,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
395 402
396 @Override 403 @Override
397 public boolean cancel(boolean mayInterruptIfRunning) { 404 public boolean cancel(boolean mayInterruptIfRunning) {
405 + ok.set(false);
398 this.state = BatchState.CANCELLED; 406 this.state = BatchState.CANCELLED;
399 cleanUp(); 407 cleanUp();
400 for (FlowRuleBatchEntry fbe : fms.values()) { 408 for (FlowRuleBatchEntry fbe : fms.values()) {
...@@ -438,7 +446,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -438,7 +446,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
438 } 446 }
439 447
440 private void cleanUp() { 448 private void cleanUp() {
441 - if (sws.isEmpty()) { 449 + if (isDone() || isCancelled()) {
442 pendingFutures.remove(pendingXid); 450 pendingFutures.remove(pendingXid);
443 for (Long xid : fms.keySet()) { 451 for (Long xid : fms.keySet()) {
444 pendingFMs.remove(xid); 452 pendingFMs.remove(xid);
...@@ -446,6 +454,12 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -446,6 +454,12 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
446 } 454 }
447 } 455 }
448 456
457 + private void removeRequirement(Dpid dpid) {
458 + countDownLatch.countDown();
459 + sws.remove(dpid);
460 + cleanUp();
461 + }
462 +
449 } 463 }
450 464
451 } 465 }
......
1 package org.onlab.onos.provider.of.host.impl; 1 package org.onlab.onos.provider.of.host.impl;
2 2
3 +import static org.onlab.onos.net.DeviceId.deviceId;
4 +import static org.onlab.onos.net.PortNumber.portNumber;
5 +import static org.slf4j.LoggerFactory.getLogger;
6 +
3 import org.apache.felix.scr.annotations.Activate; 7 import org.apache.felix.scr.annotations.Activate;
4 import org.apache.felix.scr.annotations.Component; 8 import org.apache.felix.scr.annotations.Component;
5 import org.apache.felix.scr.annotations.Deactivate; 9 import org.apache.felix.scr.annotations.Deactivate;
...@@ -29,15 +33,12 @@ import org.onlab.packet.IpPrefix; ...@@ -29,15 +33,12 @@ import org.onlab.packet.IpPrefix;
29 import org.onlab.packet.VlanId; 33 import org.onlab.packet.VlanId;
30 import org.slf4j.Logger; 34 import org.slf4j.Logger;
31 35
32 -import static org.onlab.onos.net.DeviceId.deviceId;
33 -import static org.onlab.onos.net.PortNumber.portNumber;
34 -import static org.slf4j.LoggerFactory.getLogger;
35 -
36 /** 36 /**
37 * Provider which uses an OpenFlow controller to detect network 37 * Provider which uses an OpenFlow controller to detect network
38 * end-station hosts. 38 * end-station hosts.
39 */ 39 */
40 @Component(immediate = true) 40 @Component(immediate = true)
41 +@Deprecated
41 public class OpenFlowHostProvider extends AbstractProvider implements HostProvider { 42 public class OpenFlowHostProvider extends AbstractProvider implements HostProvider {
42 43
43 private final Logger log = getLogger(getClass()); 44 private final Logger log = getLogger(getClass());
...@@ -109,14 +110,16 @@ public class OpenFlowHostProvider extends AbstractProvider implements HostProvid ...@@ -109,14 +110,16 @@ public class OpenFlowHostProvider extends AbstractProvider implements HostProvid
109 // Potentially a new or moved host 110 // Potentially a new or moved host
110 if (eth.getEtherType() == Ethernet.TYPE_ARP) { 111 if (eth.getEtherType() == Ethernet.TYPE_ARP) {
111 ARP arp = (ARP) eth.getPayload(); 112 ARP arp = (ARP) eth.getPayload();
112 - IpPrefix ip = IpPrefix.valueOf(arp.getSenderProtocolAddress()); 113 + IpPrefix ip = IpPrefix.valueOf(arp.getSenderProtocolAddress(),
114 + IpPrefix.MAX_INET_MASK);
113 HostDescription hdescr = 115 HostDescription hdescr =
114 new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ip); 116 new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ip);
115 providerService.hostDetected(hid, hdescr); 117 providerService.hostDetected(hid, hdescr);
116 118
117 } else if (ipLearn && eth.getEtherType() == Ethernet.TYPE_IPV4) { 119 } else if (ipLearn && eth.getEtherType() == Ethernet.TYPE_IPV4) {
118 IPv4 pip = (IPv4) eth.getPayload(); 120 IPv4 pip = (IPv4) eth.getPayload();
119 - IpPrefix ip = IpPrefix.valueOf(pip.getSourceAddress()); 121 + IpPrefix ip = IpPrefix.valueOf(pip.getSourceAddress(),
122 + IpPrefix.MAX_INET_MASK);
120 HostDescription hdescr = 123 HostDescription hdescr =
121 new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ip); 124 new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ip);
122 providerService.hostDetected(hid, hdescr); 125 providerService.hostDetected(hid, hdescr);
......
...@@ -66,6 +66,7 @@ import org.slf4j.Logger; ...@@ -66,6 +66,7 @@ import org.slf4j.Logger;
66 * TODO: add 'fast discovery' mode: drop LLDPs in destination switch but listen 66 * TODO: add 'fast discovery' mode: drop LLDPs in destination switch but listen
67 * for flow_removed messages 67 * for flow_removed messages
68 */ 68 */
69 +@Deprecated
69 public class LinkDiscovery implements TimerTask { 70 public class LinkDiscovery implements TimerTask {
70 71
71 private final OpenFlowSwitch sw; 72 private final OpenFlowSwitch sw;
......
...@@ -35,6 +35,7 @@ import org.slf4j.Logger; ...@@ -35,6 +35,7 @@ import org.slf4j.Logger;
35 * infrastructure links. 35 * infrastructure links.
36 */ 36 */
37 @Component(immediate = true) 37 @Component(immediate = true)
38 +@Deprecated
38 public class OpenFlowLinkProvider extends AbstractProvider implements LinkProvider { 39 public class OpenFlowLinkProvider extends AbstractProvider implements LinkProvider {
39 40
40 private final Logger log = getLogger(getClass()); 41 private final Logger log = getLogger(getClass());
......
...@@ -28,7 +28,6 @@ import org.onlab.onos.openflow.controller.OpenFlowController; ...@@ -28,7 +28,6 @@ import org.onlab.onos.openflow.controller.OpenFlowController;
28 import org.onlab.onos.openflow.controller.OpenFlowPacketContext; 28 import org.onlab.onos.openflow.controller.OpenFlowPacketContext;
29 import org.onlab.onos.openflow.controller.OpenFlowSwitch; 29 import org.onlab.onos.openflow.controller.OpenFlowSwitch;
30 import org.onlab.onos.openflow.controller.PacketListener; 30 import org.onlab.onos.openflow.controller.PacketListener;
31 -import org.onlab.packet.Ethernet;
32 import org.projectfloodlight.openflow.protocol.OFPacketOut; 31 import org.projectfloodlight.openflow.protocol.OFPacketOut;
33 import org.projectfloodlight.openflow.protocol.OFPortDesc; 32 import org.projectfloodlight.openflow.protocol.OFPortDesc;
34 import org.projectfloodlight.openflow.protocol.action.OFAction; 33 import org.projectfloodlight.openflow.protocol.action.OFAction;
...@@ -96,13 +95,13 @@ public class OpenFlowPacketProvider extends AbstractProvider implements PacketPr ...@@ -96,13 +95,13 @@ public class OpenFlowPacketProvider extends AbstractProvider implements PacketPr
96 return; 95 return;
97 } 96 }
98 97
99 - Ethernet eth = new Ethernet(); 98 + //Ethernet eth = new Ethernet();
100 - eth.deserialize(packet.data().array(), 0, packet.data().array().length); 99 + //eth.deserialize(packet.data().array(), 0, packet.data().array().length);
101 OFPortDesc p = null; 100 OFPortDesc p = null;
102 for (Instruction inst : packet.treatment().instructions()) { 101 for (Instruction inst : packet.treatment().instructions()) {
103 if (inst.type().equals(Instruction.Type.OUTPUT)) { 102 if (inst.type().equals(Instruction.Type.OUTPUT)) {
104 p = portDesc(((OutputInstruction) inst).port()); 103 p = portDesc(((OutputInstruction) inst).port());
105 - OFPacketOut po = packetOut(sw, eth, p.getPortNo()); 104 + OFPacketOut po = packetOut(sw, packet.data().array(), p.getPortNo());
106 sw.sendMsg(po); 105 sw.sendMsg(po);
107 } 106 }
108 } 107 }
...@@ -116,7 +115,7 @@ public class OpenFlowPacketProvider extends AbstractProvider implements PacketPr ...@@ -116,7 +115,7 @@ public class OpenFlowPacketProvider extends AbstractProvider implements PacketPr
116 return builder.build(); 115 return builder.build();
117 } 116 }
118 117
119 - private OFPacketOut packetOut(OpenFlowSwitch sw, Ethernet eth, OFPort out) { 118 + private OFPacketOut packetOut(OpenFlowSwitch sw, byte[] eth, OFPort out) {
120 OFPacketOut.Builder builder = sw.factory().buildPacketOut(); 119 OFPacketOut.Builder builder = sw.factory().buildPacketOut();
121 OFAction act = sw.factory().actions() 120 OFAction act = sw.factory().actions()
122 .buildOutput() 121 .buildOutput()
...@@ -126,7 +125,7 @@ public class OpenFlowPacketProvider extends AbstractProvider implements PacketPr ...@@ -126,7 +125,7 @@ public class OpenFlowPacketProvider extends AbstractProvider implements PacketPr
126 .setBufferId(OFBufferId.NO_BUFFER) 125 .setBufferId(OFBufferId.NO_BUFFER)
127 .setInPort(OFPort.NO_MASK) 126 .setInPort(OFPort.NO_MASK)
128 .setActions(Collections.singletonList(act)) 127 .setActions(Collections.singletonList(act))
129 - .setData(eth.serialize()) 128 + .setData(eth)
130 .build(); 129 .build();
131 } 130 }
132 131
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
18 18
19 <modules> 19 <modules>
20 <module>openflow</module> 20 <module>openflow</module>
21 + <module>lldp</module>
22 + <module>host</module>
21 </modules> 23 </modules>
22 24
23 <dependencies> 25 <dependencies>
......
...@@ -45,6 +45,7 @@ alias pub='onos-push-update-bundle' ...@@ -45,6 +45,7 @@ alias pub='onos-push-update-bundle'
45 # Short-hand for tailing the ONOS (karaf) log 45 # Short-hand for tailing the ONOS (karaf) log
46 alias tl='$ONOS_ROOT/tools/dev/bin/onos-local-log' 46 alias tl='$ONOS_ROOT/tools/dev/bin/onos-local-log'
47 alias tlo='tl | grep --colour=always org.onlab' 47 alias tlo='tl | grep --colour=always org.onlab'
48 +alias ll='less $KARAF_LOG'
48 49
49 # Pretty-print JSON output 50 # Pretty-print JSON output
50 alias pp='python -m json.tool' 51 alias pp='python -m json.tool'
...@@ -67,13 +68,14 @@ function cell { ...@@ -67,13 +68,14 @@ function cell {
67 [ ! -f $ONOS_ROOT/tools/test/cells/$1 ] && \ 68 [ ! -f $ONOS_ROOT/tools/test/cells/$1 ] && \
68 echo "No such cell: $1" >&2 && return 1 69 echo "No such cell: $1" >&2 && return 1
69 unset ONOS_CELL ONOS_NIC ONOS_FEATURES 70 unset ONOS_CELL ONOS_NIC ONOS_FEATURES
70 - unset OC1 OC2 OC3 OC4 OC5 OC6 OC7 OC8 OC9 OCN OCI 71 + unset OC0 OC1 OC2 OC3 OC4 OC5 OC6 OC7 OC8 OC9 OCN OCI
72 + export ONOS_CELL=$1
71 . $ONOS_ROOT/tools/test/cells/$1 73 . $ONOS_ROOT/tools/test/cells/$1
72 cell 74 cell
73 else 75 else
74 env | egrep "ONOS_CELL" 76 env | egrep "ONOS_CELL"
75 env | egrep "OCI" 77 env | egrep "OCI"
76 - env | egrep "OC[1-9]+" | sort 78 + env | egrep "OC[0-9]+" | sort
77 env | egrep "OCN" 79 env | egrep "OCN"
78 env | egrep "ONOS_" | egrep -v 'ONOS_ROOT|ONOS_CELL' 80 env | egrep "ONOS_" | egrep -v 'ONOS_ROOT|ONOS_CELL'
79 fi 81 fi
......
1 +#!/bin/tcsh
2 +# ONOS developer csh/tcsh profile conveniences
3 +# Simply include in your own $HOME/.cshrc file. E.g.:
4 +#
5 +# setenv ONOS_ROOT $HOME/onos
6 +# if ( -f $ONOS_ROOT/tools/dev/onos.cshrc ) then
7 +# source $ONOS_ROOT/tools/dev/onos.cshrc
8 +# endif
9 +#
10 +
11 +# Root of the ONOS source tree
12 +if ( ! $?ONOS_ROOT ) then
13 + setenv ONOS_ROOT $HOME/onos
14 +endif
15 +
16 +# Setup some environmental context for developers
17 +if ( ! $?JAVA_HOME ) then
18 + if ( -x /usr/libexec/java_home ) then
19 + setenv JAVA_HOME `/usr/libexec/java_home -v 1.7`
20 + else if ( -d /usr/lib/jvm/java-7-openjdk-amd64 ) then
21 + setenv JAVA_HOME /usr/lib/jvm/java-7-openjdk-amd64
22 + endif
23 +endif
24 +if ( ! $?MAVEN ) then
25 + setenv MAVEN $HOME/Applications/apache-maven-3.2.2
26 +endif
27 +if ( ! $?KARAF ) then
28 + setenv KARAF $HOME/Applications/apache-karaf-3.0.1
29 +endif
30 +setenv KARAF_LOG $KARAF/data/log/karaf.log
31 +
32 +alias onos-setup-cell ' ( $ONOS_ROOT/tools/test/bin/onos-show-cell \!^ ) && setenv ONOS_CELL \!^'
33 +
34 +set path=( $path $ONOS_ROOT/tools/dev/bin $ONOS_ROOT/tools/test/bin )
35 +set path=( $path $ONOS_ROOT/tools/build )
36 +set path=( $path $KARAF/bin )
...@@ -6,4 +6,39 @@ ...@@ -6,4 +6,39 @@
6 [ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1 6 [ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
7 . $ONOS_ROOT/tools/build/envDefaults 7 . $ONOS_ROOT/tools/build/envDefaults
8 8
9 -ssh $ONOS_USER@${1:-$OCI} "sudo service onos ${2:-status}" 9 +function print_usage {
10 + command_name=`basename $0`
11 + echo "Remotely administer the ONOS service on a single node or the current ONOS cell."
12 + echo
13 + echo "Usage: $command_name <TARGET> [COMMAND]"
14 + echo " $command_name [-h | --help]"
15 + echo "Options:"
16 + echo " TARGET The target of the command"
17 + echo " COMMAND The command to execute. Default value is 'status'"
18 + echo " [-h | --help] Print this help"
19 + echo ""
20 + echo "TARGET: <hostname | --cell>"
21 + echo " hostname Execute on the specified host name"
22 + echo " --cell Execute on the current ONOS cell"
23 + echo ""
24 + echo "COMMAND: [start|stop|restart|status]"
25 + echo ""
26 +}
27 +
28 +# Print usage
29 +if [ "${1}" = "-h" -o "${1}" = "--help" ]; then
30 + print_usage
31 + exit 0
32 +fi
33 +
34 +# Select the target
35 +if [ "${1}" = "--cell" ]; then
36 + nodes=$(env | sort | egrep "OC[0-9]+" | cut -d= -f2)
37 +else
38 + nodes=${1:-$OCI}
39 +fi
40 +
41 +# Execute the remote commands
42 +for node in $nodes; do
43 + ssh $ONOS_USER@${node} "sudo service onos ${2:-status}"
44 +done
......
...@@ -42,7 +42,7 @@ fi ...@@ -42,7 +42,7 @@ fi
42 42
43 echo "ONOS_CELL=${ONOS_CELL}" 43 echo "ONOS_CELL=${ONOS_CELL}"
44 echo "ONOS_NIC=${ONOS_NIC}" 44 echo "ONOS_NIC=${ONOS_NIC}"
45 -for n in {1..9}; do 45 +for n in {0..9}; do
46 ocn="OC${n}" 46 ocn="OC${n}"
47 if [ -n "${!ocn}" ]; then 47 if [ -n "${!ocn}" ]; then
48 echo "$ocn=${!ocn}" 48 echo "$ocn=${!ocn}"
......
...@@ -8,4 +8,4 @@ export OC2="192.168.56.102" ...@@ -8,4 +8,4 @@ export OC2="192.168.56.102"
8 export OCN="192.168.56.103" 8 export OCN="192.168.56.103"
9 export OCI="${OC1}" 9 export OCI="${OC1}"
10 10
11 -export ONOS_FEATURES="" 11 +export ONOS_FEATURES="${ONOS_FEATURES:-webconsole,onos-api,onos-core,onos-cli,onos-openflow,onos-app-fwd,onos-app-proxyarp,onos-app-tvue}"
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
2 2
3 export ONOS_CELL="office" 3 export ONOS_CELL="office"
4 4
5 -export ONOS_NIC="10.128.4.*" 5 +export ONOS_NIC="10.1.10.*"
6 -export OC1="10.128.4.60" 6 +export OC1="10.1.10.223"
7 export OCI="${OC1}" 7 export OCI="${OC1}"
8 8
9 export ONOS_FEATURES="webconsole,onos-api,onos-core-trivial,onos-cli,onos-openflow,onos-app-fwd,onos-app-mobility,onos-app-tvue,onos-app-proxyarp" 9 export ONOS_FEATURES="webconsole,onos-api,onos-core-trivial,onos-cli,onos-openflow,onos-app-fwd,onos-app-mobility,onos-app-tvue,onos-app-proxyarp"
......
...@@ -7,4 +7,4 @@ export OC1="192.168.56.101" ...@@ -7,4 +7,4 @@ export OC1="192.168.56.101"
7 export OCN="192.168.56.103" 7 export OCN="192.168.56.103"
8 export OCI="${OC1}" 8 export OCI="${OC1}"
9 9
10 -export ONOS_FEATURES="" 10 +export ONOS_FEATURES="${ONOS_FEATURES:-webconsole,onos-api,onos-core-trivial,onos-cli,onos-openflow,onos-app-fwd,onos-app-proxyarp,onos-app-tvue}"
......
1 +# Local VirtualBox-based single ONOS instance & ONOS mininet box
2 +
3 +export ONOS_NIC=192.168.56.*
4 +export OC1="192.168.56.101"
5 +export OCN="192.168.56.103"
6 +
7 +export ONOS_FEATURES=webconsole,onos-api,onos-core-trivial,onos-cli,onos-openflow,onos-app-fwd,onos-app-mobility,onos-app-tvue,onos-app-optical
1 +package org.onlab.packet;
2 +
3 +/**
4 + * The class representing a network device chassisId.
5 + * This class is immutable.
6 + */
7 +// TODO: Move this to a reasonable place.
8 +public final class ChassisId {
9 +
10 + private static final long UNKNOWN = 0;
11 + private final long value;
12 +
13 + /**
14 + * Default constructor.
15 + */
16 + public ChassisId() {
17 + this.value = ChassisId.UNKNOWN;
18 + }
19 +
20 + /**
21 + * Constructor from a long value.
22 + *
23 + * @param value the value to use.
24 + */
25 + public ChassisId(long value) {
26 + this.value = value;
27 + }
28 +
29 + /**
30 + * Constructor from a string.
31 + *
32 + * @param value the value to use.
33 + */
34 + public ChassisId(String value) {
35 + this.value = Long.valueOf(value);
36 + }
37 +
38 + /**
39 + * Get the value of the chassis id.
40 + *
41 + * @return the value of the chassis id.
42 + */
43 + public long value() {
44 + return value;
45 + }
46 +
47 + /**
48 + * Convert the Chassis Id value to a ':' separated hexadecimal string.
49 + *
50 + * @return the Chassis Id value as a ':' separated hexadecimal string.
51 + */
52 + @Override
53 + public String toString() {
54 + return Long.toHexString(this.value);
55 + }
56 +
57 + @Override
58 + public boolean equals(Object other) {
59 + if (!(other instanceof ChassisId)) {
60 + return false;
61 + }
62 +
63 + ChassisId otherChassisId = (ChassisId) other;
64 +
65 + return value == otherChassisId.value;
66 + }
67 +
68 + @Override
69 + public int hashCode() {
70 + int hash = 17;
71 + hash += 31 * hash + (int) (value ^ value >>> 32);
72 + return hash;
73 + }
74 +}
...@@ -58,6 +58,7 @@ public class Ethernet extends BasePacket { ...@@ -58,6 +58,7 @@ public class Ethernet extends BasePacket {
58 Ethernet.etherTypeClassMap.put(Ethernet.TYPE_RARP, ARP.class); 58 Ethernet.etherTypeClassMap.put(Ethernet.TYPE_RARP, ARP.class);
59 Ethernet.etherTypeClassMap.put(Ethernet.TYPE_IPV4, IPv4.class); 59 Ethernet.etherTypeClassMap.put(Ethernet.TYPE_IPV4, IPv4.class);
60 Ethernet.etherTypeClassMap.put(Ethernet.TYPE_LLDP, LLDP.class); 60 Ethernet.etherTypeClassMap.put(Ethernet.TYPE_LLDP, LLDP.class);
61 + Ethernet.etherTypeClassMap.put(Ethernet.TYPE_BSN, LLDP.class);
61 } 62 }
62 63
63 protected MacAddress destinationMACAddress; 64 protected MacAddress destinationMACAddress;
......
...@@ -150,7 +150,7 @@ public class LLDP extends BasePacket { ...@@ -150,7 +150,7 @@ public class LLDP extends BasePacket {
150 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); 150 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
151 LLDPTLV tlv; 151 LLDPTLV tlv;
152 do { 152 do {
153 - tlv = new LLDPTLV().deserialize(bb); 153 + tlv = new LLDPOrganizationalTLV().deserialize(bb);
154 154
155 // if there was a failure to deserialize stop processing TLVs 155 // if there was a failure to deserialize stop processing TLVs
156 if (tlv == null) { 156 if (tlv == null) {
...@@ -169,6 +169,7 @@ public class LLDP extends BasePacket { ...@@ -169,6 +169,7 @@ public class LLDP extends BasePacket {
169 case 0x3: 169 case 0x3:
170 this.ttl = tlv; 170 this.ttl = tlv;
171 break; 171 break;
172 +
172 default: 173 default:
173 this.optionalTLVList.add(tlv); 174 this.optionalTLVList.add(tlv);
174 break; 175 break;
......
...@@ -140,6 +140,9 @@ public class LLDPOrganizationalTLV extends LLDPTLV { ...@@ -140,6 +140,9 @@ public class LLDPOrganizationalTLV extends LLDPTLV {
140 140
141 @Override 141 @Override
142 public byte[] serialize() { 142 public byte[] serialize() {
143 + if (this.type != LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) {
144 + return super.serialize();
145 + }
143 final int valueLength = LLDPOrganizationalTLV.OUI_LENGTH 146 final int valueLength = LLDPOrganizationalTLV.OUI_LENGTH
144 + LLDPOrganizationalTLV.SUBTYPE_LENGTH + this.infoString.length; 147 + LLDPOrganizationalTLV.SUBTYPE_LENGTH + this.infoString.length;
145 this.value = new byte[valueLength]; 148 this.value = new byte[valueLength];
...@@ -152,7 +155,11 @@ public class LLDPOrganizationalTLV extends LLDPTLV { ...@@ -152,7 +155,11 @@ public class LLDPOrganizationalTLV extends LLDPTLV {
152 155
153 @Override 156 @Override
154 public LLDPTLV deserialize(final ByteBuffer bb) { 157 public LLDPTLV deserialize(final ByteBuffer bb) {
155 - super.deserialize(bb); 158 + LLDPTLV tlv = super.deserialize(bb);
159 + if (tlv.getType() != LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) {
160 + return tlv;
161 + }
162 +
156 final ByteBuffer optionalField = ByteBuffer.wrap(this.value); 163 final ByteBuffer optionalField = ByteBuffer.wrap(this.value);
157 164
158 final byte[] oui = new byte[LLDPOrganizationalTLV.OUI_LENGTH]; 165 final byte[] oui = new byte[LLDPOrganizationalTLV.OUI_LENGTH];
......
...@@ -111,6 +111,7 @@ public class LLDPTLV { ...@@ -111,6 +111,7 @@ public class LLDPTLV {
111 sscratch = bb.getShort(); 111 sscratch = bb.getShort();
112 this.type = (byte) (sscratch >> 9 & 0x7f); 112 this.type = (byte) (sscratch >> 9 & 0x7f);
113 this.length = (short) (sscratch & 0x1ff); 113 this.length = (short) (sscratch & 0x1ff);
114 +
114 if (this.length > 0) { 115 if (this.length > 0) {
115 this.value = new byte[this.length]; 116 this.value = new byte[this.length];
116 117
...@@ -120,6 +121,7 @@ public class LLDPTLV { ...@@ -120,6 +121,7 @@ public class LLDPTLV {
120 } 121 }
121 bb.get(this.value); 122 bb.get(this.value);
122 } 123 }
124 +
123 return this; 125 return this;
124 } 126 }
125 127
......
...@@ -30,6 +30,7 @@ import org.slf4j.LoggerFactory; ...@@ -30,6 +30,7 @@ import org.slf4j.LoggerFactory;
30 * Refer to IEEE Std 802.1ABTM-2009 for more information. 30 * Refer to IEEE Std 802.1ABTM-2009 for more information.
31 * 31 *
32 */ 32 */
33 +@Deprecated
33 public class ONLabLddp extends LLDP { 34 public class ONLabLddp extends LLDP {
34 35
35 private static final Logger LOG = LoggerFactory.getLogger(ONLabLddp.class); 36 private static final Logger LOG = LoggerFactory.getLogger(ONLabLddp.class);
......
1 +package org.onlab.packet;
2 +
3 +import com.google.common.collect.Lists;
4 +import org.apache.commons.lang.ArrayUtils;
5 +
6 +import java.nio.ByteBuffer;
7 +
8 +/**
9 + * ONOS LLDP containing organizational TLV for ONOS device dicovery.
10 + */
11 +public class ONOSLLDP extends LLDP {
12 +
13 + public static final byte[] ONLAB_OUI = {(byte) 0xa4, 0x23, 0x05};
14 + public static final String DEFAULT_DEVICE = "INVALID";
15 + public static final String DEFAULT_NAME = "ONOS Discovery";
16 +
17 + public static final byte[] LLDP_NICIRA = {0x01, 0x23, 0x20, 0x00, 0x00,
18 + 0x01};
19 + public static final byte[] LLDP_MULTICAST = {0x01, (byte) 0x80,
20 + (byte) 0xc2, 0x00, 0x00, 0x0e};
21 + public static final byte[] BDDP_MULTICAST = {(byte) 0xff, (byte) 0xff,
22 + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
23 +
24 + private static final byte NAME_SUBTYPE = 1;
25 + private static final byte DEVICE_SUBTYPE = 2;
26 + private static final short NAME_LENGTH = 4; //1 for subtype + 3 for OUI
27 + private static final short DEVICE_LENGTH = 4; //1 for subtype + 3 for OUI
28 + private final LLDPOrganizationalTLV nameTLV = new LLDPOrganizationalTLV();
29 + private final LLDPOrganizationalTLV deviceTLV = new LLDPOrganizationalTLV();
30 +
31 + // TLV constants: type, size and subtype
32 + // Organizationally specific TLV also have packet offset and contents of TLV
33 + // header
34 + private static final byte CHASSIS_TLV_TYPE = 1;
35 + private static final byte CHASSIS_TLV_SIZE = 7;
36 + private static final byte CHASSIS_TLV_SUBTYPE = 4;
37 +
38 + private static final byte PORT_TLV_TYPE = 2;
39 + private static final byte PORT_TLV_SIZE = 5;
40 + private static final byte PORT_TLV_SUBTYPE = 2;
41 +
42 + private static final byte TTL_TLV_TYPE = 3;
43 +
44 +
45 + private final byte[] ttlValue = new byte[] {0, 0x78};
46 +
47 + public ONOSLLDP() {
48 + super();
49 + setName(DEFAULT_NAME);
50 + setDevice(DEFAULT_DEVICE);
51 + setOptionalTLVList(Lists.<LLDPTLV>newArrayList(nameTLV, deviceTLV));
52 + setTtl(new LLDPTLV().setType((byte) TTL_TLV_TYPE)
53 + .setLength((short) ttlValue.length)
54 + .setValue(ttlValue));
55 +
56 + }
57 +
58 + private ONOSLLDP(LLDP lldp) {
59 + this.portId = lldp.getPortId();
60 + this.chassisId = lldp.getChassisId();
61 + this.ttl = lldp.getTtl();
62 + this.optionalTLVList = lldp.getOptionalTLVList();
63 + }
64 +
65 + public void setName(String name) {
66 + nameTLV.setLength((short) (name.length() + NAME_LENGTH));
67 + nameTLV.setInfoString(name);
68 + nameTLV.setSubType(NAME_SUBTYPE);
69 + nameTLV.setOUI(ONLAB_OUI);
70 + }
71 +
72 + public void setDevice(String device) {
73 + deviceTLV.setInfoString(device);
74 + deviceTLV.setLength((short) (device.length() + DEVICE_LENGTH));
75 + deviceTLV.setSubType(DEVICE_SUBTYPE);
76 + deviceTLV.setOUI(ONLAB_OUI);
77 + }
78 +
79 + public void setChassisId(final ChassisId chassisId) {
80 + MacAddress chassisMac = MacAddress.valueOf(chassisId.value());
81 + byte[] chassis = ArrayUtils.addAll(new byte[] {CHASSIS_TLV_SUBTYPE},
82 + chassisMac.getAddress());
83 +
84 + LLDPTLV chassisTLV = new LLDPTLV();
85 + chassisTLV.setLength(CHASSIS_TLV_SIZE);
86 + chassisTLV.setType(CHASSIS_TLV_TYPE);
87 + chassisTLV.setValue(chassis);
88 + this.setChassisId(chassisTLV);
89 + }
90 +
91 + public void setPortId(final int portNumber) {
92 + byte[] port = ArrayUtils.addAll(new byte[] {PORT_TLV_SUBTYPE},
93 + ByteBuffer.allocate(4).putInt(portNumber).array());
94 +
95 + LLDPTLV portTLV = new LLDPTLV();
96 + portTLV.setLength(PORT_TLV_SIZE);
97 + portTLV.setType(PORT_TLV_TYPE);
98 + portTLV.setValue(port);
99 + this.setPortId(portTLV);
100 + }
101 +
102 + public LLDPOrganizationalTLV getNameTLV() {
103 + for (LLDPTLV tlv : this.getOptionalTLVList()) {
104 + if (tlv.getType() == LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) {
105 + LLDPOrganizationalTLV orgTLV = (LLDPOrganizationalTLV) tlv;
106 + if (orgTLV.getSubType() == NAME_SUBTYPE) {
107 + return orgTLV;
108 + }
109 + }
110 + }
111 + return null;
112 + }
113 +
114 + public LLDPOrganizationalTLV getDeviceTLV() {
115 + for (LLDPTLV tlv : this.getOptionalTLVList()) {
116 + if (tlv.getType() == LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) {
117 + LLDPOrganizationalTLV orgTLV = (LLDPOrganizationalTLV) tlv;
118 + if (orgTLV.getSubType() == DEVICE_SUBTYPE) {
119 + return orgTLV;
120 + }
121 + }
122 + }
123 + return null;
124 + }
125 +
126 + public String getNameString() {
127 + LLDPOrganizationalTLV tlv = getNameTLV();
128 + if (tlv != null) {
129 + return new String(tlv.getInfoString());
130 + }
131 + return null;
132 + }
133 +
134 + public String getDeviceString() {
135 + LLDPOrganizationalTLV tlv = getDeviceTLV();
136 + if (tlv != null) {
137 + return new String(tlv.getInfoString());
138 + }
139 + return null;
140 + }
141 +
142 + public Integer getPort() {
143 + ByteBuffer portBB = ByteBuffer.wrap(this.getPortId().getValue());
144 + portBB.position(1);
145 + return portBB.getInt();
146 + }
147 +
148 + /**
149 + * Given an ethernet packet, determines if this is an LLDP from
150 + * ONOS and returns the device the LLDP came from.
151 + * @param eth an ethernet packet
152 + * @return a the lldp packet or null
153 + */
154 + public static ONOSLLDP parseONOSLLDP(Ethernet eth) {
155 + if (eth.getEtherType() == Ethernet.TYPE_LLDP ||
156 + eth.getEtherType() == Ethernet.TYPE_BSN) {
157 + ONOSLLDP onosLldp = new ONOSLLDP((LLDP) eth.getPayload()); //(ONOSLLDP) eth.getPayload();
158 + if (ONOSLLDP.DEFAULT_NAME.equals(onosLldp.getNameString())) {
159 + return onosLldp;
160 + }
161 + }
162 + return null;
163 + }
164 +
165 +
166 +
167 +
168 +
169 +}
1 +package org.onlab.util;
2 +
3 +public final class HexString {
4 +
5 + private HexString() {
6 +
7 + }
8 +
9 + /**
10 + * Convert a string of bytes to a ':' separated hex string.
11 + *
12 + * @param bytes
13 + * @return "0f:ca:fe:de:ad:be:ef"
14 + */
15 + public static String toHexString(final byte[] bytes) {
16 + int i;
17 + StringBuilder ret = new StringBuilder();
18 + String tmp;
19 + for (i = 0; i < bytes.length; i++) {
20 + if (i > 0) {
21 + ret.append(':');
22 + }
23 + tmp = Integer.toHexString((bytes[i] & 0xff));
24 + if (tmp.length() == 1) {
25 + ret.append('0');
26 + }
27 + ret.append(tmp);
28 + }
29 + return ret.toString();
30 + }
31 +
32 + public static String toHexString(final long val, final int padTo) {
33 + char[] arr = Long.toHexString(val).toCharArray();
34 + String ret = "";
35 + // prepend the right number of leading zeros
36 + int i = 0;
37 + for (; i < (padTo * 2 - arr.length); i++) {
38 + ret += "0";
39 + if ((i % 2) != 0) {
40 + ret += ":";
41 + }
42 + }
43 + for (int j = 0; j < arr.length; j++) {
44 + ret += arr[j];
45 + if ((((i + j) % 2) != 0) && (j < (arr.length - 1))) {
46 + ret += ":";
47 + }
48 + }
49 + return ret;
50 + }
51 +
52 + public static String toHexString(final long val) {
53 + return toHexString(val, 8);
54 + }
55 +
56 + /**
57 + * Convert a string of hex values into a string of bytes.
58 + *
59 + * @param values
60 + * "0f:ca:fe:de:ad:be:ef"
61 + * @return [15, 5 ,2, 5, 17]
62 + * @throws NumberFormatException
63 + * If the string can not be parsed
64 + */
65 + public static byte[] fromHexString(final String values) {
66 + String[] octets = values.split(":");
67 + byte[] ret = new byte[octets.length];
68 +
69 + for (int i = 0; i < octets.length; i++) {
70 + if (octets[i].length() > 2) {
71 + throw new NumberFormatException("Invalid octet length");
72 + }
73 + ret[i] = Integer.valueOf(octets[i], 16).byteValue();
74 + }
75 + return ret;
76 + }
77 +
78 + public static long toLong(String value) {
79 + String[] octets = value.split(":");
80 + if (octets.length > 8) {
81 + throw new NumberFormatException("Input string is too big to fit in long: " + value);
82 + }
83 + long l = 0;
84 + for (String octet: octets) {
85 + if (octet.length() > 2) {
86 + throw new NumberFormatException(
87 + "Each colon-separated byte component must consist of 1 or 2 hex digits: " + value);
88 + }
89 + short s = Short.parseShort(octet, 16);
90 + l = (l << 8) + s;
91 + }
92 + return l;
93 + }
94 +}
1 +package org.onlab.util;
2 +
3 +import java.lang.reflect.Constructor;
4 +import java.lang.reflect.Field;
5 +import java.lang.reflect.InvocationTargetException;
6 +import java.lang.reflect.Method;
7 +
8 +
9 +/**
10 + * Utilities for testing.
11 + */
12 +public final class TestUtils {
13 +
14 + /**
15 + * Sets the field, bypassing scope restriction.
16 + *
17 + * @param subject Object where the field belongs
18 + * @param fieldName name of the field to set
19 + * @param value value to set to the field.
20 + * @param <T> subject type
21 + * @param <U> value type
22 + * @throws TestUtilsException if there are reflection errors while setting
23 + * the field
24 + */
25 + public static <T, U> void setField(T subject, String fieldName, U value)
26 + throws TestUtilsException {
27 + @SuppressWarnings("unchecked")
28 + Class<T> clazz = (Class<T>) subject.getClass();
29 + try {
30 + Field field = clazz.getDeclaredField(fieldName);
31 + field.setAccessible(true);
32 + field.set(subject, value);
33 + } catch (NoSuchFieldException | SecurityException |
34 + IllegalArgumentException | IllegalAccessException e) {
35 + throw new TestUtilsException("setField failed", e);
36 + }
37 + }
38 +
39 + /**
40 + * Gets the field, bypassing scope restriction.
41 + *
42 + * @param subject Object where the field belongs
43 + * @param fieldName name of the field to get
44 + * @return value of the field.
45 + * @param <T> subject type
46 + * @param <U> field value type
47 + * @throws TestUtilsException if there are reflection errors while getting
48 + * the field
49 + */
50 + public static <T, U> U getField(T subject, String fieldName)
51 + throws TestUtilsException {
52 + try {
53 + @SuppressWarnings("unchecked")
54 + Class<T> clazz = (Class<T>) subject.getClass();
55 + Field field = clazz.getDeclaredField(fieldName);
56 + field.setAccessible(true);
57 +
58 + @SuppressWarnings("unchecked")
59 + U result = (U) field.get(subject);
60 + return result;
61 + } catch (NoSuchFieldException | SecurityException |
62 + IllegalArgumentException | IllegalAccessException e) {
63 + throw new TestUtilsException("getField failed", e);
64 + }
65 + }
66 +
67 + /**
68 + * Calls the method, bypassing scope restriction.
69 + *
70 + * @param subject Object where the method belongs
71 + * @param methodName name of the method to call
72 + * @param paramTypes formal parameter type array
73 + * @param args arguments
74 + * @return return value or null if void
75 + * @param <T> subject type
76 + * @param <U> return value type
77 + * @throws TestUtilsException if there are reflection errors while calling
78 + * the method
79 + */
80 + public static <T, U> U callMethod(T subject, String methodName,
81 + Class<?>[] paramTypes, Object...args) throws TestUtilsException {
82 +
83 + try {
84 + @SuppressWarnings("unchecked")
85 + Class<T> clazz = (Class<T>) subject.getClass();
86 + final Method method;
87 + if (paramTypes == null || paramTypes.length == 0) {
88 + method = clazz.getDeclaredMethod(methodName);
89 + } else {
90 + method = clazz.getDeclaredMethod(methodName, paramTypes);
91 + }
92 + method.setAccessible(true);
93 +
94 + @SuppressWarnings("unchecked")
95 + U result = (U) method.invoke(subject, args);
96 + return result;
97 + } catch (NoSuchMethodException | SecurityException |
98 + IllegalAccessException | IllegalArgumentException |
99 + InvocationTargetException e) {
100 + throw new TestUtilsException("callMethod failed", e);
101 + }
102 + }
103 +
104 + /**
105 + * Calls the method, bypassing scope restriction.
106 + *
107 + * @param subject Object where the method belongs
108 + * @param methodName name of the method to call
109 + * @param paramType formal parameter type
110 + * @param arg argument
111 + * @return return value or null if void
112 + * @param <T> subject type
113 + * @param <U> return value type
114 + * @throws TestUtilsException if there are reflection errors while calling
115 + * the method
116 + */
117 + public static <T, U> U callMethod(T subject, String methodName,
118 + Class<?> paramType, Object arg) throws TestUtilsException {
119 + return callMethod(subject, methodName, new Class<?>[]{paramType}, arg);
120 + }
121 +
122 + /**
123 + * Triggers an allocation of an object of type <T> and forces a call to
124 + * the private constructor.
125 + *
126 + * @param constructor Constructor to call
127 + * @param <T> type of the object to create
128 + * @return created object of type <T>
129 + * @throws TestUtilsException if there are reflection errors while calling
130 + * the constructor
131 + */
132 + public static <T> T callConstructor(Constructor<T> constructor)
133 + throws TestUtilsException {
134 + try {
135 + constructor.setAccessible(true);
136 + return constructor.newInstance();
137 + } catch (InstantiationException | IllegalAccessException |
138 + InvocationTargetException error) {
139 + throw new TestUtilsException("callConstructor failed", error);
140 + }
141 + }
142 +
143 + /**
144 + * Avoid instantiation.
145 + */
146 + private TestUtils() {}
147 +
148 + /**
149 + * Exception that can be thrown if problems are encountered while executing
150 + * the utility method. These are usually problems accessing fields/methods
151 + * through reflection. The original exception can be found by examining the
152 + * cause.
153 + */
154 + public static class TestUtilsException extends Exception {
155 +
156 + private static final long serialVersionUID = 1L;
157 +
158 + /**
159 + * Constructs a new exception with the specified detail message and
160 + * cause.
161 + *
162 + * @param message the detail message
163 + * @param cause the original cause of this exception
164 + */
165 + public TestUtilsException(String message, Throwable cause) {
166 + super(message, cause);
167 + }
168 + }
169 +}
1 +package org.onlab.util;
2 +
3 +import org.junit.Test;
4 +
5 +import com.esotericsoftware.minlog.Log;
6 +
7 +import junit.framework.TestCase;
8 +
9 +/**
10 + * Test of the Hexstring.
11 + *
12 + */
13 +
14 +public class HexStringTest extends TestCase {
15 +
16 + @Test
17 + public void testMarshalling() throws Exception {
18 + String dpidStr = "00:00:00:23:20:2d:16:71";
19 + long dpid = HexString.toLong(dpidStr);
20 + String testStr = HexString.toHexString(dpid);
21 + TestCase.assertEquals(dpidStr, testStr);
22 + }
23 +
24 + @Test
25 + public void testToLong() {
26 + String dpidStr = "3e:1f:01:fc:72:8c:63:31";
27 + long valid = 0x3e1f01fc728c6331L;
28 + long testLong = HexString.toLong(dpidStr);
29 + TestCase.assertEquals(valid, testLong);
30 + }
31 +
32 + @Test
33 + public void testToLongMSB() {
34 + String dpidStr = "ca:7c:5e:d1:64:7a:95:9b";
35 + long valid = -3856102927509056101L;
36 + long testLong = HexString.toLong(dpidStr);
37 + TestCase.assertEquals(valid, testLong);
38 + }
39 +
40 + @Test
41 + public void testToLongError() {
42 + String dpidStr = "09:08:07:06:05:04:03:02:01";
43 + try {
44 + HexString.toLong(dpidStr);
45 + fail("HexString.toLong() should have thrown a NumberFormatException");
46 + } catch (NumberFormatException expected) {
47 + Log.info("HexString.toLong() have thrown a NumberFormatException");
48 + }
49 + }
50 +
51 + @Test
52 + public void testToStringBytes() {
53 + byte[] dpid = {0, 0, 0, 0, 0, 0, 0, -1 };
54 + String valid = "00:00:00:00:00:00:00:ff";
55 + String testString = HexString.toHexString(dpid);
56 + TestCase.assertEquals(valid, testString);
57 + }
58 +
59 + @Test
60 + public void testFromHexStringError() {
61 + String invalidStr = "00:00:00:00:00:00:ffff";
62 + try {
63 + HexString.fromHexString(invalidStr);
64 + fail("HexString.fromHexString() should have thrown a NumberFormatException");
65 + } catch (NumberFormatException expected) {
66 + Log.info("HexString.toLong() have thrown a NumberFormatException");
67 + }
68 + }
69 +}
70 +
1 +package org.onlab.util;
2 +
3 +import static org.junit.Assert.assertArrayEquals;
4 +import static org.junit.Assert.assertEquals;
5 +import static org.junit.Assert.assertNull;
6 +
7 +import org.junit.Before;
8 +import org.junit.Test;
9 +import org.onlab.util.TestUtils.TestUtilsException;
10 +
11 +/**
12 + * Test and usage examples for TestUtils.
13 + */
14 +public class TestUtilsTest {
15 +
16 + /**
17 + * Test data.
18 + */
19 + private static final class TestClass {
20 +
21 + @SuppressWarnings("unused")
22 + private int privateField = 42;
23 +
24 + @SuppressWarnings("unused")
25 + protected int protectedField = 2501; // CHECKSTYLE IGNORE THIS LINE
26 +
27 + /**
28 + * Protected method with multiple argument.
29 + *
30 + * @param x simply returns
31 + * @param y not used
32 + * @return x
33 + */
34 + @SuppressWarnings("unused")
35 + private int privateMethod(Number x, Long y) {
36 + return x.intValue();
37 + }
38 +
39 + /**
40 + * Protected method with no argument.
41 + *
42 + * @return int
43 + */
44 + @SuppressWarnings("unused")
45 + protected int protectedMethod() {
46 + return 42;
47 + }
48 +
49 + /**
50 + * Method returning array.
51 + *
52 + * @param ary random array
53 + * @return ary
54 + */
55 + @SuppressWarnings("unused")
56 + private int[] arrayReturnMethod(int[] ary) {
57 + return ary;
58 + }
59 +
60 + /**
61 + * Method without return value.
62 + *
63 + * @param s ignored
64 + */
65 + @SuppressWarnings("unused")
66 + private void voidMethod(String s) {
67 + System.out.println(s);
68 + }
69 + }
70 +
71 + private TestClass test;
72 +
73 + /**
74 + * Sets up the test fixture.
75 + */
76 + @Before
77 + public void setUp() {
78 + test = new TestClass();
79 + }
80 +
81 + /**
82 + * Example to access private field.
83 + *
84 + * @throws TestUtilsException TestUtils error
85 + */
86 + @Test
87 + public void testSetGetPrivateField() throws TestUtilsException {
88 +
89 + assertEquals(42, TestUtils.getField(test, "privateField"));
90 + TestUtils.setField(test, "privateField", 0xDEAD);
91 + assertEquals(0xDEAD, TestUtils.getField(test, "privateField"));
92 + }
93 +
94 + /**
95 + * Example to access protected field.
96 + *
97 + * @throws TestUtilsException TestUtils error
98 + */
99 + @Test
100 + public void testSetGetProtectedField() throws TestUtilsException {
101 +
102 + assertEquals(2501, TestUtils.getField(test, "protectedField"));
103 + TestUtils.setField(test, "protectedField", 0xBEEF);
104 + assertEquals(0xBEEF, TestUtils.getField(test, "protectedField"));
105 + }
106 +
107 + /**
108 + * Example to call private method and multiple parameters.
109 + * <p/>
110 + * It also illustrates that paramTypes must match declared type,
111 + * not the runtime types of arguments.
112 + *
113 + * @throws TestUtilsException TestUtils error
114 + */
115 + @Test
116 + public void testCallPrivateMethod() throws TestUtilsException {
117 +
118 + int result = TestUtils.callMethod(test, "privateMethod",
119 + new Class<?>[] {Number.class, Long.class},
120 + Long.valueOf(42), Long.valueOf(32));
121 + assertEquals(42, result);
122 + }
123 +
124 + /**
125 + * Example to call protected method and no parameters.
126 + *
127 + * @throws TestUtilsException TestUtils error
128 + */
129 + @Test
130 + public void testCallProtectedMethod() throws TestUtilsException {
131 +
132 + int result = TestUtils.callMethod(test, "protectedMethod",
133 + new Class<?>[] {});
134 + assertEquals(42, result);
135 + }
136 +
137 + /**
138 + * Example to call method returning array.
139 + * <p/>
140 + * Note: It is not required to receive as Object.
141 + * Following is just verifying it is not Boxed arrays.
142 + *
143 + * @throws TestUtilsException TestUtils error
144 + */
145 + @Test
146 + public void testCallArrayReturnMethod() throws TestUtilsException {
147 +
148 + int[] array = {1, 2, 3};
149 + Object aryResult = TestUtils.callMethod(test, "arrayReturnMethod",
150 + new Class<?>[] {int[].class}, array);
151 + assertEquals(int[].class, aryResult.getClass());
152 + assertArrayEquals(array, (int[]) aryResult);
153 + }
154 +
155 +
156 + /**
157 + * Example to call void returning method.
158 + * <p/>
159 + * Note: Return value will be null for void methods.
160 + *
161 + * @throws TestUtilsException TestUtils error
162 + */
163 + @Test
164 + public void testCallVoidReturnMethod() throws TestUtilsException {
165 +
166 + Object voidResult = TestUtils.callMethod(test, "voidMethod",
167 + String.class, "foobar");
168 + assertNull(voidResult);
169 + }
170 +}