Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
Showing
162 changed files
with
8291 additions
and
523 deletions
apps/calendar/pom.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
5 | + <modelVersion>4.0.0</modelVersion> | ||
6 | + | ||
7 | + <parent> | ||
8 | + <groupId>org.onlab.onos</groupId> | ||
9 | + <artifactId>onos-apps</artifactId> | ||
10 | + <version>1.0.0-SNAPSHOT</version> | ||
11 | + <relativePath>../pom.xml</relativePath> | ||
12 | + </parent> | ||
13 | + | ||
14 | + <artifactId>onos-app-calendar</artifactId> | ||
15 | + <packaging>bundle</packaging> | ||
16 | + | ||
17 | + <description>ONOS simple calendaring REST interface for intents</description> | ||
18 | + | ||
19 | + <properties> | ||
20 | + <web.context>/onos/calendar</web.context> | ||
21 | + </properties> | ||
22 | + | ||
23 | + <dependencies> | ||
24 | + <dependency> | ||
25 | + <groupId>org.onlab.onos</groupId> | ||
26 | + <artifactId>onlab-rest</artifactId> | ||
27 | + <version>${project.version}</version> | ||
28 | + </dependency> | ||
29 | + | ||
30 | + <dependency> | ||
31 | + <groupId>com.sun.jersey</groupId> | ||
32 | + <artifactId>jersey-servlet</artifactId> | ||
33 | + </dependency> | ||
34 | + <dependency> | ||
35 | + <groupId>com.sun.jersey.jersey-test-framework</groupId> | ||
36 | + <artifactId>jersey-test-framework-core</artifactId> | ||
37 | + <version>1.18.1</version> | ||
38 | + <scope>test</scope> | ||
39 | + </dependency> | ||
40 | + <dependency> | ||
41 | + <groupId>com.sun.jersey.jersey-test-framework</groupId> | ||
42 | + <artifactId>jersey-test-framework-grizzly2</artifactId> | ||
43 | + <version>1.18.1</version> | ||
44 | + <scope>test</scope> | ||
45 | + </dependency> | ||
46 | + <dependency> | ||
47 | + <groupId>org.osgi</groupId> | ||
48 | + <artifactId>org.osgi.core</artifactId> | ||
49 | + </dependency> | ||
50 | + </dependencies> | ||
51 | + | ||
52 | + <build> | ||
53 | + <plugins> | ||
54 | + <plugin> | ||
55 | + <groupId>org.apache.felix</groupId> | ||
56 | + <artifactId>maven-bundle-plugin</artifactId> | ||
57 | + <extensions>true</extensions> | ||
58 | + <configuration> | ||
59 | + <instructions> | ||
60 | + <_wab>src/main/webapp/</_wab> | ||
61 | + <Bundle-SymbolicName> | ||
62 | + ${project.groupId}.${project.artifactId} | ||
63 | + </Bundle-SymbolicName> | ||
64 | + <Import-Package> | ||
65 | + org.osgi.framework, | ||
66 | + javax.ws.rs,javax.ws.rs.core, | ||
67 | + com.sun.jersey.api.core, | ||
68 | + com.sun.jersey.spi.container.servlet, | ||
69 | + com.sun.jersey.server.impl.container.servlet, | ||
70 | + org.onlab.packet.*, | ||
71 | + org.onlab.rest.*, | ||
72 | + org.onlab.onos.* | ||
73 | + </Import-Package> | ||
74 | + <Web-ContextPath>${web.context}</Web-ContextPath> | ||
75 | + </instructions> | ||
76 | + </configuration> | ||
77 | + </plugin> | ||
78 | + </plugins> | ||
79 | + </build> | ||
80 | + | ||
81 | +</project> |
1 | +package org.onlab.onos.calendar; | ||
2 | + | ||
3 | +import org.onlab.onos.net.ConnectPoint; | ||
4 | +import org.onlab.onos.net.DeviceId; | ||
5 | +import org.onlab.onos.net.intent.IntentService; | ||
6 | +import org.onlab.rest.BaseResource; | ||
7 | + | ||
8 | +import javax.ws.rs.POST; | ||
9 | +import javax.ws.rs.Path; | ||
10 | +import javax.ws.rs.PathParam; | ||
11 | +import javax.ws.rs.core.Response; | ||
12 | +import java.net.URI; | ||
13 | + | ||
14 | +import static org.onlab.onos.net.PortNumber.portNumber; | ||
15 | + | ||
16 | +/** | ||
17 | + * Web resource for triggering calendared intents. | ||
18 | + */ | ||
19 | +@Path("intent") | ||
20 | +public class BandwidthCalendarResource extends BaseResource { | ||
21 | + | ||
22 | + @POST | ||
23 | + @Path("{src}/{dst}/{srcPort}/{dstPort}/{bandwidth}") | ||
24 | + public Response createIntent(@PathParam("src") String src, | ||
25 | + @PathParam("dst") String dst, | ||
26 | + @PathParam("srcPort") String srcPort, | ||
27 | + @PathParam("dstPort") String dstPort, | ||
28 | + @PathParam("bandwidth") String bandwidth) { | ||
29 | + // TODO: implement calls to intent framework | ||
30 | + IntentService service = get(IntentService.class); | ||
31 | + | ||
32 | + ConnectPoint srcPoint = new ConnectPoint(deviceId(src), portNumber(srcPort)); | ||
33 | + ConnectPoint dstPoint = new ConnectPoint(deviceId(dst), portNumber(dstPort)); | ||
34 | + | ||
35 | + return Response.ok("Yo! We got src=" + srcPoint + "; dst=" + dstPoint + | ||
36 | + "; bw=" + bandwidth + "; intent service " + service).build(); | ||
37 | + } | ||
38 | + | ||
39 | + private DeviceId deviceId(String dpid) { | ||
40 | + return DeviceId.deviceId(URI.create("of:" + dpid)); | ||
41 | + } | ||
42 | + | ||
43 | +} |
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" | ||
3 | + xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" | ||
4 | + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" | ||
5 | + id="ONOS" version="2.5"> | ||
6 | + <display-name>ONOS GUI</display-name> | ||
7 | + | ||
8 | + <servlet> | ||
9 | + <servlet-name>JAX-RS Service</servlet-name> | ||
10 | + <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> | ||
11 | + <init-param> | ||
12 | + <param-name>com.sun.jersey.config.property.packages</param-name> | ||
13 | + <param-value>org.onlab.onos.calendar</param-value> | ||
14 | + </init-param> | ||
15 | + <load-on-startup>10</load-on-startup> | ||
16 | + </servlet> | ||
17 | + | ||
18 | + <servlet-mapping> | ||
19 | + <servlet-name>JAX-RS Service</servlet-name> | ||
20 | + <url-pattern>/rs/*</url-pattern> | ||
21 | + </servlet-mapping> | ||
22 | + | ||
23 | +</web-app> | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
apps/optical/pom.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
5 | + <modelVersion>4.0.0</modelVersion> | ||
6 | + | ||
7 | + <parent> | ||
8 | + <groupId>org.onlab.onos</groupId> | ||
9 | + <artifactId>onos-apps</artifactId> | ||
10 | + <version>1.0.0-SNAPSHOT</version> | ||
11 | + <relativePath>../pom.xml</relativePath> | ||
12 | + </parent> | ||
13 | + | ||
14 | + <artifactId>onos-app-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 | } | ... | ... |
core/api/src/main/java/org/onlab/onos/store/cluster/messaging/ClusterMessageResponse.java
0 → 100644
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() { | ... | ... |
core/json/pom.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
5 | + <modelVersion>4.0.0</modelVersion> | ||
6 | + | ||
7 | + <parent> | ||
8 | + <groupId>org.onlab.onos</groupId> | ||
9 | + <artifactId>onos-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> |
... | @@ -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 | +} |
core/net/src/test/java/org/onlab/onos/net/intent/LinksHaveEntryWithSourceDestinationPairMatcher.java
0 → 100644
1 | +package org.onlab.onos.net.intent; | ||
2 | + | ||
3 | +import java.util.Collection; | ||
4 | + | ||
5 | +import org.hamcrest.Description; | ||
6 | +import org.hamcrest.TypeSafeMatcher; | ||
7 | +import org.onlab.onos.net.Link; | ||
8 | + | ||
9 | +/** | ||
10 | + * Matcher to determine if a Collection of Links contains a path between a source | ||
11 | + * and a destination. | ||
12 | + */ | ||
13 | +public class LinksHaveEntryWithSourceDestinationPairMatcher extends | ||
14 | + TypeSafeMatcher<Collection<Link>> { | ||
15 | + private final String source; | ||
16 | + private final String destination; | ||
17 | + | ||
18 | + /** | ||
19 | + * Creates a matcher for a given path represented by a source and | ||
20 | + * a destination. | ||
21 | + * | ||
22 | + * @param source string identifier for the source of the path | ||
23 | + * @param destination string identifier for the destination of the path | ||
24 | + */ | ||
25 | + LinksHaveEntryWithSourceDestinationPairMatcher(String source, | ||
26 | + String destination) { | ||
27 | + this.source = source; | ||
28 | + this.destination = destination; | ||
29 | + } | ||
30 | + | ||
31 | + @Override | ||
32 | + public boolean matchesSafely(Collection<Link> links) { | ||
33 | + for (Link link : links) { | ||
34 | + if (link.src().elementId().toString().endsWith(source) && | ||
35 | + link.dst().elementId().toString().endsWith(destination)) { | ||
36 | + return true; | ||
37 | + } | ||
38 | + } | ||
39 | + | ||
40 | + return false; | ||
41 | + } | ||
42 | + | ||
43 | + @Override | ||
44 | + public void describeTo(Description description) { | ||
45 | + description.appendText("link lookup for source \""); | ||
46 | + description.appendText(source); | ||
47 | + description.appendText(" and destination "); | ||
48 | + description.appendText(destination); | ||
49 | + description.appendText("\""); | ||
50 | + } | ||
51 | + | ||
52 | + @Override | ||
53 | + public void describeMismatchSafely(Collection<Link> links, | ||
54 | + Description mismatchDescription) { | ||
55 | + mismatchDescription.appendText("was "). | ||
56 | + appendText(links.toString()); | ||
57 | + } | ||
58 | + | ||
59 | + /** | ||
60 | + * Creates a link has path matcher. | ||
61 | + * | ||
62 | + * @param source string identifier for the source of the path | ||
63 | + * @param destination string identifier for the destination of the path | ||
64 | + * @return matcher to match the path | ||
65 | + */ | ||
66 | + public static LinksHaveEntryWithSourceDestinationPairMatcher linksHasPath( | ||
67 | + String source, | ||
68 | + String destination) { | ||
69 | + return new LinksHaveEntryWithSourceDestinationPairMatcher(source, | ||
70 | + destination); | ||
71 | + } | ||
72 | +} | ||
73 | + |
1 | +package org.onlab.onos.net.intent; | ||
2 | + | ||
3 | +import org.junit.Test; | ||
4 | +import org.onlab.onos.net.HostId; | ||
5 | +import org.onlab.onos.net.flow.TrafficSelector; | ||
6 | +import org.onlab.onos.net.flow.TrafficTreatment; | ||
7 | + | ||
8 | +import static org.hamcrest.MatcherAssert.assertThat; | ||
9 | +import static org.hamcrest.Matchers.equalTo; | ||
10 | +import static org.hamcrest.Matchers.is; | ||
11 | +import static org.hamcrest.Matchers.not; | ||
12 | +import static org.onlab.onos.net.NetTestTools.hid; | ||
13 | + | ||
14 | +/** | ||
15 | + * Unit tests for the HostToHostIntent class. | ||
16 | + */ | ||
17 | +public class TestHostToHostIntent { | ||
18 | + | ||
19 | + private TrafficSelector selector = new IntentTestsMocks.MockSelector(); | ||
20 | + private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment(); | ||
21 | + | ||
22 | + private HostToHostIntent makeHostToHost(long id, HostId one, HostId two) { | ||
23 | + return new HostToHostIntent(new IntentId(id), | ||
24 | + one, | ||
25 | + two, | ||
26 | + selector, | ||
27 | + treatment); | ||
28 | + } | ||
29 | + | ||
30 | + /** | ||
31 | + * Tests the equals() method where two HostToHostIntents have references | ||
32 | + * to the same hosts. These should compare equal. | ||
33 | + */ | ||
34 | + @Test | ||
35 | + public void testSameEquals() { | ||
36 | + | ||
37 | + HostId one = hid("00:00:00:00:00:01/-1"); | ||
38 | + HostId two = hid("00:00:00:00:00:02/-1"); | ||
39 | + HostToHostIntent i1 = makeHostToHost(12, one, two); | ||
40 | + HostToHostIntent i2 = makeHostToHost(12, one, two); | ||
41 | + | ||
42 | + assertThat(i1, is(equalTo(i2))); | ||
43 | + } | ||
44 | + | ||
45 | + /** | ||
46 | + * Tests the equals() method where two HostToHostIntents have references | ||
47 | + * to different Hosts. These should compare not equal. | ||
48 | + */ | ||
49 | + @Test | ||
50 | + public void testLinksDifferentEquals() { | ||
51 | + | ||
52 | + HostId one = hid("00:00:00:00:00:01/-1"); | ||
53 | + HostId two = hid("00:00:00:00:00:02/-1"); | ||
54 | + HostToHostIntent i1 = makeHostToHost(12, one, two); | ||
55 | + HostToHostIntent i2 = makeHostToHost(12, two, one); | ||
56 | + | ||
57 | + assertThat(i1, is(not(equalTo(i2)))); | ||
58 | + } | ||
59 | + | ||
60 | + /** | ||
61 | + * Tests the equals() method where two HostToHostIntents have different | ||
62 | + * ids. These should compare not equal. | ||
63 | + */ | ||
64 | + | ||
65 | + @Test | ||
66 | + public void testBaseDifferentEquals() { | ||
67 | + HostId one = hid("00:00:00:00:00:01/-1"); | ||
68 | + HostId two = hid("00:00:00:00:00:02/-1"); | ||
69 | + HostToHostIntent i1 = makeHostToHost(12, one, two); | ||
70 | + HostToHostIntent i2 = makeHostToHost(11, one, two); | ||
71 | + | ||
72 | + assertThat(i1, is(not(equalTo(i2)))); | ||
73 | + } | ||
74 | + | ||
75 | + /** | ||
76 | + * Tests that the hashCode() values for two equivalent HostToHostIntent | ||
77 | + * objects are the same. | ||
78 | + */ | ||
79 | + | ||
80 | + @Test | ||
81 | + public void testHashCodeEquals() { | ||
82 | + HostId one = hid("00:00:00:00:00:01/-1"); | ||
83 | + HostId two = hid("00:00:00:00:00:02/-1"); | ||
84 | + HostToHostIntent i1 = makeHostToHost(12, one, two); | ||
85 | + HostToHostIntent i2 = makeHostToHost(12, one, two); | ||
86 | + | ||
87 | + assertThat(i1.hashCode(), is(equalTo(i2.hashCode()))); | ||
88 | + } | ||
89 | + | ||
90 | + /** | ||
91 | + * Tests that the hashCode() values for two distinct LinkCollectionIntent | ||
92 | + * objects are different. | ||
93 | + */ | ||
94 | + | ||
95 | + @Test | ||
96 | + public void testHashCodeDifferent() { | ||
97 | + HostId one = hid("00:00:00:00:00:01/-1"); | ||
98 | + HostId two = hid("00:00:00:00:00:02/-1"); | ||
99 | + HostToHostIntent i1 = makeHostToHost(12, one, two); | ||
100 | + HostToHostIntent i2 = makeHostToHost(112, one, two); | ||
101 | + | ||
102 | + assertThat(i1.hashCode(), is(not(equalTo(i2.hashCode())))); | ||
103 | + } | ||
104 | + | ||
105 | + /** | ||
106 | + * Checks that the HostToHostIntent class is immutable. | ||
107 | + */ | ||
108 | + @Test | ||
109 | + public void checkImmutability() { | ||
110 | + ImmutableClassChecker.assertThatClassIsImmutable(HostToHostIntent.class); | ||
111 | + } | ||
112 | +} |
1 | package org.onlab.onos.net.intent; | 1 | package org.onlab.onos.net.intent; |
2 | 2 | ||
3 | -import java.util.ArrayList; | ||
4 | import java.util.HashSet; | 3 | import java.util.HashSet; |
5 | -import java.util.List; | ||
6 | import java.util.Set; | 4 | import java.util.Set; |
7 | 5 | ||
6 | +import org.junit.Before; | ||
8 | import org.junit.Test; | 7 | import org.junit.Test; |
9 | import org.onlab.onos.net.Link; | 8 | import org.onlab.onos.net.Link; |
10 | import org.onlab.onos.net.flow.TrafficSelector; | 9 | import org.onlab.onos.net.flow.TrafficSelector; |
11 | import org.onlab.onos.net.flow.TrafficTreatment; | 10 | import org.onlab.onos.net.flow.TrafficTreatment; |
12 | -import org.onlab.onos.net.flow.criteria.Criterion; | ||
13 | -import org.onlab.onos.net.flow.instructions.Instruction; | ||
14 | 11 | ||
12 | +import static org.hamcrest.CoreMatchers.not; | ||
15 | import static org.hamcrest.MatcherAssert.assertThat; | 13 | import static org.hamcrest.MatcherAssert.assertThat; |
14 | +import static org.hamcrest.Matchers.equalTo; | ||
16 | import static org.hamcrest.Matchers.is; | 15 | import static org.hamcrest.Matchers.is; |
16 | +import static org.onlab.onos.net.NetTestTools.link; | ||
17 | 17 | ||
18 | +/** | ||
19 | + * Unit tests for the LinkCollectionIntent class. | ||
20 | + */ | ||
18 | public class TestLinkCollectionIntent { | 21 | public class TestLinkCollectionIntent { |
19 | 22 | ||
20 | - private static class MockSelector implements TrafficSelector { | 23 | + private Link link1 = link("dev1", 1, "dev2", 2); |
21 | - @Override | 24 | + private Link link2 = link("dev1", 1, "dev3", 2); |
22 | - public Set<Criterion> criteria() { | 25 | + private Link link3 = link("dev2", 1, "dev3", 2); |
23 | - return new HashSet<Criterion>(); | 26 | + |
27 | + private Set<Link> links1; | ||
28 | + private Set<Link> links2; | ||
29 | + | ||
30 | + private TrafficSelector selector = new IntentTestsMocks.MockSelector(); | ||
31 | + private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment(); | ||
32 | + | ||
33 | + private LinkCollectionIntent makeLinkCollection(long id, Set<Link> links) { | ||
34 | + return new LinkCollectionIntent(new IntentId(id), | ||
35 | + selector, treatment, links); | ||
24 | } | 36 | } |
37 | + | ||
38 | + @Before | ||
39 | + public void setup() { | ||
40 | + links1 = new HashSet<>(); | ||
41 | + links2 = new HashSet<>(); | ||
25 | } | 42 | } |
26 | 43 | ||
27 | - private static class MockTreatment implements TrafficTreatment { | 44 | + /** |
28 | - @Override | 45 | + * Tests the equals() method where two LinkCollectionIntents have references |
29 | - public List<Instruction> instructions() { | 46 | + * to the same Links in different orders. These should compare equal. |
30 | - return new ArrayList<>(); | 47 | + */ |
48 | + @Test | ||
49 | + public void testSameEquals() { | ||
50 | + links1.add(link1); | ||
51 | + links1.add(link2); | ||
52 | + links1.add(link3); | ||
53 | + | ||
54 | + links2.add(link3); | ||
55 | + links2.add(link2); | ||
56 | + links2.add(link1); | ||
57 | + | ||
58 | + LinkCollectionIntent i1 = makeLinkCollection(12, links1); | ||
59 | + LinkCollectionIntent i2 = makeLinkCollection(12, links2); | ||
60 | + | ||
61 | + assertThat(i1, is(equalTo(i2))); | ||
31 | } | 62 | } |
63 | + | ||
64 | + /** | ||
65 | + * Tests the equals() method where two LinkCollectionIntents have references | ||
66 | + * to different Links. These should compare not equal. | ||
67 | + */ | ||
68 | + @Test | ||
69 | + public void testLinksDifferentEquals() { | ||
70 | + links1.add(link1); | ||
71 | + links1.add(link2); | ||
72 | + | ||
73 | + links2.add(link3); | ||
74 | + links2.add(link1); | ||
75 | + | ||
76 | + LinkCollectionIntent i1 = makeLinkCollection(12, links1); | ||
77 | + LinkCollectionIntent i2 = makeLinkCollection(12, links2); | ||
78 | + | ||
79 | + assertThat(i1, is(not(equalTo(i2)))); | ||
32 | } | 80 | } |
33 | 81 | ||
82 | + /** | ||
83 | + * Tests the equals() method where two LinkCollectionIntents have different | ||
84 | + * ids. These should compare not equal. | ||
85 | + */ | ||
34 | @Test | 86 | @Test |
35 | - public void testComparison() { | 87 | + public void testBaseDifferentEquals() { |
36 | - TrafficSelector selector = new MockSelector(); | 88 | + links1.add(link1); |
37 | - TrafficTreatment treatment = new MockTreatment(); | 89 | + links1.add(link2); |
38 | - Set<Link> links = new HashSet<>(); | ||
39 | - LinkCollectionIntent i1 = new LinkCollectionIntent(new IntentId(12), | ||
40 | - selector, treatment, links); | ||
41 | - LinkCollectionIntent i2 = new LinkCollectionIntent(new IntentId(12), | ||
42 | - selector, treatment, links); | ||
43 | 90 | ||
44 | - assertThat(i1.equals(i2), is(true)); | 91 | + links2.add(link2); |
92 | + links2.add(link1); | ||
93 | + | ||
94 | + LinkCollectionIntent i1 = makeLinkCollection(1, links1); | ||
95 | + LinkCollectionIntent i2 = makeLinkCollection(2, links2); | ||
96 | + | ||
97 | + assertThat(i1, is(not(equalTo(i2)))); | ||
98 | + } | ||
99 | + | ||
100 | + /** | ||
101 | + * Tests that the hashCode() values for two equivalent LinkCollectionIntent | ||
102 | + * objects are the same. | ||
103 | + */ | ||
104 | + @Test | ||
105 | + public void testHashCodeEquals() { | ||
106 | + links1.add(link1); | ||
107 | + links1.add(link2); | ||
108 | + links1.add(link3); | ||
109 | + | ||
110 | + links2.add(link3); | ||
111 | + links2.add(link2); | ||
112 | + links2.add(link1); | ||
113 | + | ||
114 | + LinkCollectionIntent i1 = makeLinkCollection(1, links1); | ||
115 | + LinkCollectionIntent i2 = makeLinkCollection(1, links2); | ||
116 | + | ||
117 | + assertThat(i1.hashCode(), is(equalTo(i2.hashCode()))); | ||
45 | } | 118 | } |
46 | 119 | ||
120 | + /** | ||
121 | + * Tests that the hashCode() values for two distinct LinkCollectionIntent | ||
122 | + * objects are different. | ||
123 | + */ | ||
124 | + @Test | ||
125 | + public void testHashCodeDifferent() { | ||
126 | + links1.add(link1); | ||
127 | + links1.add(link2); | ||
128 | + | ||
129 | + links2.add(link1); | ||
130 | + links2.add(link3); | ||
131 | + | ||
132 | + LinkCollectionIntent i1 = makeLinkCollection(1, links1); | ||
133 | + LinkCollectionIntent i2 = makeLinkCollection(1, links2); | ||
134 | + | ||
135 | + assertThat(i1.hashCode(), is(not(equalTo(i2.hashCode())))); | ||
136 | + } | ||
137 | + | ||
138 | + /** | ||
139 | + * Checks that the HostToHostIntent class is immutable. | ||
140 | + */ | ||
141 | + @Test | ||
142 | + public void checkImmutability() { | ||
143 | + ImmutableClassChecker.assertThatClassIsImmutable(LinkCollectionIntent.class); | ||
144 | + } | ||
47 | } | 145 | } | ... | ... |
1 | +package org.onlab.onos.net.intent; | ||
2 | + | ||
3 | +import java.util.HashSet; | ||
4 | +import java.util.Set; | ||
5 | + | ||
6 | +import org.junit.Before; | ||
7 | +import org.junit.Test; | ||
8 | +import org.onlab.onos.net.ConnectPoint; | ||
9 | +import org.onlab.onos.net.flow.TrafficSelector; | ||
10 | +import org.onlab.onos.net.flow.TrafficTreatment; | ||
11 | + | ||
12 | +import static org.hamcrest.CoreMatchers.not; | ||
13 | +import static org.hamcrest.MatcherAssert.assertThat; | ||
14 | +import static org.hamcrest.Matchers.equalTo; | ||
15 | +import static org.hamcrest.Matchers.is; | ||
16 | +import static org.onlab.onos.net.NetTestTools.connectPoint; | ||
17 | + | ||
18 | +/** | ||
19 | + * Unit tests for the MultiPointToSinglePointIntent class. | ||
20 | + */ | ||
21 | +public class TestMultiPointToSinglePointIntent { | ||
22 | + | ||
23 | + private ConnectPoint point1 = connectPoint("dev1", 1); | ||
24 | + private ConnectPoint point2 = connectPoint("dev2", 1); | ||
25 | + private ConnectPoint point3 = connectPoint("dev3", 1); | ||
26 | + | ||
27 | + private TrafficSelector selector = new IntentTestsMocks.MockSelector(); | ||
28 | + private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment(); | ||
29 | + | ||
30 | + Set<ConnectPoint> ingress1; | ||
31 | + Set<ConnectPoint> ingress2; | ||
32 | + | ||
33 | + /** | ||
34 | + * Creates a MultiPointToSinglePointIntent object. | ||
35 | + * | ||
36 | + * @param id identifier to use for the new intent | ||
37 | + * @param ingress set of ingress points | ||
38 | + * @param egress egress point | ||
39 | + * @return MultiPointToSinglePoint intent | ||
40 | + */ | ||
41 | + private MultiPointToSinglePointIntent makeIntent(long id, | ||
42 | + Set<ConnectPoint> ingress, | ||
43 | + ConnectPoint egress) { | ||
44 | + return new MultiPointToSinglePointIntent(new IntentId(id), | ||
45 | + selector, | ||
46 | + treatment, | ||
47 | + ingress, | ||
48 | + egress); | ||
49 | + } | ||
50 | + | ||
51 | + /** | ||
52 | + * Initializes the ingress sets. | ||
53 | + */ | ||
54 | + @Before | ||
55 | + public void setup() { | ||
56 | + ingress1 = new HashSet<>(); | ||
57 | + ingress2 = new HashSet<>(); | ||
58 | + } | ||
59 | + | ||
60 | + /** | ||
61 | + * Tests the equals() method where two MultiPointToSinglePoint have references | ||
62 | + * to the same Links in different orders. These should compare equal. | ||
63 | + */ | ||
64 | + @Test | ||
65 | + public void testSameEquals() { | ||
66 | + | ||
67 | + Set<ConnectPoint> ingress1 = new HashSet<>(); | ||
68 | + ingress1.add(point2); | ||
69 | + ingress1.add(point3); | ||
70 | + | ||
71 | + Set<ConnectPoint> ingress2 = new HashSet<>(); | ||
72 | + ingress2.add(point3); | ||
73 | + ingress2.add(point2); | ||
74 | + | ||
75 | + Intent i1 = makeIntent(12, ingress1, point1); | ||
76 | + Intent i2 = makeIntent(12, ingress2, point1); | ||
77 | + | ||
78 | + assertThat(i1, is(equalTo(i2))); | ||
79 | + } | ||
80 | + | ||
81 | + /** | ||
82 | + * Tests the equals() method where two MultiPointToSinglePoint have references | ||
83 | + * to different Links. These should compare not equal. | ||
84 | + */ | ||
85 | + @Test | ||
86 | + public void testLinksDifferentEquals() { | ||
87 | + ingress1.add(point3); | ||
88 | + | ||
89 | + ingress2.add(point3); | ||
90 | + ingress2.add(point2); | ||
91 | + | ||
92 | + Intent i1 = makeIntent(12, ingress1, point1); | ||
93 | + Intent i2 = makeIntent(12, ingress2, point1); | ||
94 | + | ||
95 | + assertThat(i1, is(not(equalTo(i2)))); | ||
96 | + } | ||
97 | + | ||
98 | + /** | ||
99 | + * Tests the equals() method where two MultiPointToSinglePoint have different | ||
100 | + * ids. These should compare not equal. | ||
101 | + */ | ||
102 | + @Test | ||
103 | + public void testBaseDifferentEquals() { | ||
104 | + ingress1.add(point3); | ||
105 | + ingress2.add(point3); | ||
106 | + | ||
107 | + Intent i1 = makeIntent(12, ingress1, point1); | ||
108 | + Intent i2 = makeIntent(11, ingress2, point1); | ||
109 | + | ||
110 | + assertThat(i1, is(not(equalTo(i2)))); | ||
111 | + } | ||
112 | + | ||
113 | + /** | ||
114 | + * Tests that the hashCode() values for two equivalent MultiPointToSinglePoint | ||
115 | + * objects are the same. | ||
116 | + */ | ||
117 | + @Test | ||
118 | + public void testHashCodeEquals() { | ||
119 | + ingress1.add(point2); | ||
120 | + ingress1.add(point3); | ||
121 | + | ||
122 | + ingress2.add(point3); | ||
123 | + ingress2.add(point2); | ||
124 | + | ||
125 | + Intent i1 = makeIntent(12, ingress1, point1); | ||
126 | + Intent i2 = makeIntent(12, ingress2, point1); | ||
127 | + | ||
128 | + assertThat(i1.hashCode(), is(equalTo(i2.hashCode()))); | ||
129 | + } | ||
130 | + | ||
131 | + /** | ||
132 | + * Tests that the hashCode() values for two distinct MultiPointToSinglePoint | ||
133 | + * objects are different. | ||
134 | + */ | ||
135 | + @Test | ||
136 | + public void testHashCodeDifferent() { | ||
137 | + ingress1.add(point2); | ||
138 | + | ||
139 | + ingress2.add(point3); | ||
140 | + ingress2.add(point2); | ||
141 | + | ||
142 | + Intent i1 = makeIntent(12, ingress1, point1); | ||
143 | + Intent i2 = makeIntent(12, ingress2, point1); | ||
144 | + | ||
145 | + | ||
146 | + assertThat(i1.hashCode(), is(not(equalTo(i2.hashCode())))); | ||
147 | + } | ||
148 | + | ||
149 | + /** | ||
150 | + * Checks that the MultiPointToSinglePointIntent class is immutable. | ||
151 | + */ | ||
152 | + @Test | ||
153 | + public void checkImmutability() { | ||
154 | + ImmutableClassChecker. | ||
155 | + assertThatClassIsImmutable(MultiPointToSinglePointIntent.class); | ||
156 | + } | ||
157 | +} |
1 | +package org.onlab.onos.net.intent; | ||
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 | +} |
core/net/src/test/java/org/onlab/onos/net/intent/impl/TestMultiPointToSinglePointIntentCompiler.java
0 → 100644
1 | +package org.onlab.onos.net.intent.impl; | ||
2 | + | ||
3 | +import java.util.HashSet; | ||
4 | +import java.util.List; | ||
5 | +import java.util.Set; | ||
6 | + | ||
7 | +import org.hamcrest.Matchers; | ||
8 | +import org.junit.Test; | ||
9 | +import org.onlab.onos.net.ConnectPoint; | ||
10 | +import org.onlab.onos.net.ElementId; | ||
11 | +import org.onlab.onos.net.Path; | ||
12 | +import org.onlab.onos.net.flow.TrafficSelector; | ||
13 | +import org.onlab.onos.net.flow.TrafficTreatment; | ||
14 | +import org.onlab.onos.net.intent.Intent; | ||
15 | +import org.onlab.onos.net.intent.IntentId; | ||
16 | +import org.onlab.onos.net.intent.IntentTestsMocks; | ||
17 | +import org.onlab.onos.net.intent.LinkCollectionIntent; | ||
18 | +import org.onlab.onos.net.intent.MultiPointToSinglePointIntent; | ||
19 | +import org.onlab.onos.net.topology.LinkWeight; | ||
20 | +import org.onlab.onos.net.topology.PathService; | ||
21 | + | ||
22 | +import static org.hamcrest.CoreMatchers.notNullValue; | ||
23 | +import static org.hamcrest.MatcherAssert.assertThat; | ||
24 | +import static org.hamcrest.Matchers.hasSize; | ||
25 | +import static org.hamcrest.Matchers.is; | ||
26 | +import static org.onlab.onos.net.NetTestTools.connectPoint; | ||
27 | +import static org.onlab.onos.net.NetTestTools.createPath; | ||
28 | +import static org.onlab.onos.net.intent.LinksHaveEntryWithSourceDestinationPairMatcher.linksHasPath; | ||
29 | + | ||
30 | +/** | ||
31 | + * Unit tests for the MultiPointToSinglePoint intent compiler. | ||
32 | + */ | ||
33 | +public class TestMultiPointToSinglePointIntentCompiler { | ||
34 | + | ||
35 | + private TrafficSelector selector = new IntentTestsMocks.MockSelector(); | ||
36 | + private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment(); | ||
37 | + | ||
38 | + /** | ||
39 | + * Mock path service for creating paths within the test. | ||
40 | + */ | ||
41 | + private static class MockPathService implements PathService { | ||
42 | + | ||
43 | + final String[] pathHops; | ||
44 | + | ||
45 | + /** | ||
46 | + * Constructor that provides a set of hops to mock. | ||
47 | + * | ||
48 | + * @param pathHops path hops to mock | ||
49 | + */ | ||
50 | + MockPathService(String[] pathHops) { | ||
51 | + this.pathHops = pathHops; | ||
52 | + } | ||
53 | + | ||
54 | + @Override | ||
55 | + public Set<Path> getPaths(ElementId src, ElementId dst) { | ||
56 | + Set<Path> result = new HashSet<>(); | ||
57 | + | ||
58 | + String[] allHops = new String[pathHops.length + 1]; | ||
59 | + allHops[0] = src.toString(); | ||
60 | + System.arraycopy(pathHops, 0, allHops, 1, pathHops.length); | ||
61 | + | ||
62 | + result.add(createPath(allHops)); | ||
63 | + return result; | ||
64 | + } | ||
65 | + | ||
66 | + @Override | ||
67 | + public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeight weight) { | ||
68 | + return null; | ||
69 | + } | ||
70 | + } | ||
71 | + | ||
72 | + /** | ||
73 | + * Creates a MultiPointToSinglePoint intent for a group of ingress points | ||
74 | + * and an egress point. | ||
75 | + * | ||
76 | + * @param ingressIds array of ingress device ids | ||
77 | + * @param egressId device id of the egress point | ||
78 | + * @return MultiPointToSinglePoint intent | ||
79 | + */ | ||
80 | + private MultiPointToSinglePointIntent makeIntent(String[] ingressIds, String egressId) { | ||
81 | + Set<ConnectPoint> ingressPoints = new HashSet<>(); | ||
82 | + ConnectPoint egressPoint = connectPoint(egressId, 1); | ||
83 | + | ||
84 | + for (String ingressId : ingressIds) { | ||
85 | + ingressPoints.add(connectPoint(ingressId, 1)); | ||
86 | + } | ||
87 | + | ||
88 | + return new MultiPointToSinglePointIntent( | ||
89 | + new IntentId(12), | ||
90 | + selector, | ||
91 | + treatment, | ||
92 | + ingressPoints, | ||
93 | + egressPoint); | ||
94 | + } | ||
95 | + | ||
96 | + /** | ||
97 | + * Creates a compiler for MultiPointToSinglePoint intents. | ||
98 | + * | ||
99 | + * @param hops hops to use while computing paths for this intent | ||
100 | + * @return MultiPointToSinglePoint intent | ||
101 | + */ | ||
102 | + private MultiPointToSinglePointIntentCompiler makeCompiler(String[] hops) { | ||
103 | + MultiPointToSinglePointIntentCompiler compiler = | ||
104 | + new MultiPointToSinglePointIntentCompiler(); | ||
105 | + compiler.pathService = new MockPathService(hops); | ||
106 | + IdBlockAllocator idBlockAllocator = new DummyIdBlockAllocator(); | ||
107 | + compiler.intentIdGenerator = | ||
108 | + new IdBlockAllocatorBasedIntentIdGenerator(idBlockAllocator); | ||
109 | + return compiler; | ||
110 | + } | ||
111 | + | ||
112 | + /** | ||
113 | + * Tests a single ingress point with 8 hops to its egress point. | ||
114 | + */ | ||
115 | + @Test | ||
116 | + public void testSingleLongPathCompilation() { | ||
117 | + | ||
118 | + String[] ingress = {"ingress"}; | ||
119 | + String egress = "egress"; | ||
120 | + | ||
121 | + MultiPointToSinglePointIntent intent = makeIntent(ingress, egress); | ||
122 | + assertThat(intent, is(notNullValue())); | ||
123 | + | ||
124 | + String[] hops = {"h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8", | ||
125 | + egress}; | ||
126 | + MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops); | ||
127 | + assertThat(compiler, is(notNullValue())); | ||
128 | + | ||
129 | + List<Intent> result = compiler.compile(intent); | ||
130 | + assertThat(result, is(Matchers.notNullValue())); | ||
131 | + assertThat(result, hasSize(1)); | ||
132 | + Intent resultIntent = result.get(0); | ||
133 | + assertThat(resultIntent instanceof LinkCollectionIntent, is(true)); | ||
134 | + | ||
135 | + if (resultIntent instanceof LinkCollectionIntent) { | ||
136 | + LinkCollectionIntent linkIntent = (LinkCollectionIntent) resultIntent; | ||
137 | + assertThat(linkIntent.links(), hasSize(9)); | ||
138 | + assertThat(linkIntent.links(), linksHasPath("ingress", "h1")); | ||
139 | + assertThat(linkIntent.links(), linksHasPath("h1", "h2")); | ||
140 | + assertThat(linkIntent.links(), linksHasPath("h2", "h3")); | ||
141 | + assertThat(linkIntent.links(), linksHasPath("h4", "h5")); | ||
142 | + assertThat(linkIntent.links(), linksHasPath("h5", "h6")); | ||
143 | + assertThat(linkIntent.links(), linksHasPath("h7", "h8")); | ||
144 | + assertThat(linkIntent.links(), linksHasPath("h8", "egress")); | ||
145 | + } | ||
146 | + } | ||
147 | + | ||
148 | + /** | ||
149 | + * Tests a simple topology where two ingress points share some path segments | ||
150 | + * and some path segments are not shared. | ||
151 | + */ | ||
152 | + @Test | ||
153 | + public void testTwoIngressCompilation() { | ||
154 | + String[] ingress = {"ingress1", "ingress2"}; | ||
155 | + String egress = "egress"; | ||
156 | + | ||
157 | + MultiPointToSinglePointIntent intent = makeIntent(ingress, egress); | ||
158 | + assertThat(intent, is(notNullValue())); | ||
159 | + | ||
160 | + final String[] hops = {"inner1", "inner2", egress}; | ||
161 | + MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops); | ||
162 | + assertThat(compiler, is(notNullValue())); | ||
163 | + | ||
164 | + List<Intent> result = compiler.compile(intent); | ||
165 | + assertThat(result, is(notNullValue())); | ||
166 | + assertThat(result, hasSize(1)); | ||
167 | + Intent resultIntent = result.get(0); | ||
168 | + assertThat(resultIntent instanceof LinkCollectionIntent, is(true)); | ||
169 | + | ||
170 | + if (resultIntent instanceof LinkCollectionIntent) { | ||
171 | + LinkCollectionIntent linkIntent = (LinkCollectionIntent) resultIntent; | ||
172 | + assertThat(linkIntent.links(), hasSize(4)); | ||
173 | + assertThat(linkIntent.links(), linksHasPath("ingress1", "inner1")); | ||
174 | + assertThat(linkIntent.links(), linksHasPath("ingress2", "inner1")); | ||
175 | + assertThat(linkIntent.links(), linksHasPath("inner1", "inner2")); | ||
176 | + assertThat(linkIntent.links(), linksHasPath("inner2", "egress")); | ||
177 | + } | ||
178 | + } | ||
179 | + | ||
180 | + /** | ||
181 | + * Tests a large number of ingress points that share a common path to the | ||
182 | + * egress point. | ||
183 | + */ | ||
184 | + @Test | ||
185 | + public void testMultiIngressCompilation() { | ||
186 | + String[] ingress = {"i1", "i2", "i3", "i4", "i5", | ||
187 | + "i6", "i7", "i8", "i9", "i10"}; | ||
188 | + String egress = "e"; | ||
189 | + | ||
190 | + MultiPointToSinglePointIntent intent = makeIntent(ingress, egress); | ||
191 | + assertThat(intent, is(notNullValue())); | ||
192 | + | ||
193 | + final String[] hops = {"n1", egress}; | ||
194 | + MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops); | ||
195 | + assertThat(compiler, is(notNullValue())); | ||
196 | + | ||
197 | + List<Intent> result = compiler.compile(intent); | ||
198 | + assertThat(result, is(notNullValue())); | ||
199 | + assertThat(result, hasSize(1)); | ||
200 | + Intent resultIntent = result.get(0); | ||
201 | + assertThat(resultIntent instanceof LinkCollectionIntent, is(true)); | ||
202 | + | ||
203 | + if (resultIntent instanceof LinkCollectionIntent) { | ||
204 | + LinkCollectionIntent linkIntent = (LinkCollectionIntent) resultIntent; | ||
205 | + assertThat(linkIntent.links(), hasSize(ingress.length + 1)); | ||
206 | + for (String ingressToCheck : ingress) { | ||
207 | + assertThat(linkIntent.links(), | ||
208 | + linksHasPath(ingressToCheck, | ||
209 | + "n1")); | ||
210 | + } | ||
211 | + assertThat(linkIntent.links(), linksHasPath("n1", egress)); | ||
212 | + } | ||
213 | + } | ||
214 | +} |
core/net/src/test/java/org/onlab/onos/net/intent/impl/TestPointToPointIntentCompiler.java
0 → 100644
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 | +} |
... | @@ -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 | } | ... | ... |
... | @@ -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) { | ... | ... |
core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InitDeviceDescs.java
deleted
100644 → 0
1 | -package org.onlab.onos.store.device.impl; | ||
2 | - | ||
3 | -import static com.google.common.base.Preconditions.checkNotNull; | ||
4 | - | ||
5 | -import org.apache.commons.lang3.concurrent.ConcurrentException; | ||
6 | -import org.apache.commons.lang3.concurrent.ConcurrentInitializer; | ||
7 | -import org.onlab.onos.net.device.DeviceDescription; | ||
8 | -import org.onlab.onos.store.common.impl.Timestamped; | ||
9 | - | ||
10 | -// FIXME: consider removing this class | ||
11 | -public final class InitDeviceDescs | ||
12 | - implements ConcurrentInitializer<DeviceDescriptions> { | ||
13 | - | ||
14 | - private final Timestamped<DeviceDescription> deviceDesc; | ||
15 | - | ||
16 | - public InitDeviceDescs(Timestamped<DeviceDescription> deviceDesc) { | ||
17 | - this.deviceDesc = checkNotNull(deviceDesc); | ||
18 | - } | ||
19 | - @Override | ||
20 | - public DeviceDescriptions get() throws ConcurrentException { | ||
21 | - return new DeviceDescriptions(deviceDesc); | ||
22 | - } | ||
23 | -} |
... | @@ -3,7 +3,7 @@ package org.onlab.onos.store.device.impl; | ... | @@ -3,7 +3,7 @@ package org.onlab.onos.store.device.impl; |
3 | import org.onlab.onos.net.DeviceId; | 3 | import org.onlab.onos.net.DeviceId; |
4 | import org.onlab.onos.net.device.DeviceDescription; | 4 | import org.onlab.onos.net.device.DeviceDescription; |
5 | import org.onlab.onos.net.provider.ProviderId; | 5 | import org.onlab.onos.net.provider.ProviderId; |
6 | -import org.onlab.onos.store.common.impl.Timestamped; | 6 | +import org.onlab.onos.store.impl.Timestamped; |
7 | 7 | ||
8 | import com.google.common.base.MoreObjects; | 8 | import com.google.common.base.MoreObjects; |
9 | 9 | ... | ... |
... | @@ -3,7 +3,7 @@ package org.onlab.onos.store.device.impl; | ... | @@ -3,7 +3,7 @@ package org.onlab.onos.store.device.impl; |
3 | import org.onlab.onos.net.DeviceId; | 3 | import org.onlab.onos.net.DeviceId; |
4 | import org.onlab.onos.net.device.DeviceDescription; | 4 | import org.onlab.onos.net.device.DeviceDescription; |
5 | import org.onlab.onos.net.provider.ProviderId; | 5 | import org.onlab.onos.net.provider.ProviderId; |
6 | -import org.onlab.onos.store.common.impl.Timestamped; | 6 | +import org.onlab.onos.store.impl.Timestamped; |
7 | 7 | ||
8 | import com.esotericsoftware.kryo.Kryo; | 8 | import com.esotericsoftware.kryo.Kryo; |
9 | import com.esotericsoftware.kryo.Serializer; | 9 | import com.esotericsoftware.kryo.Serializer; | ... | ... |
... | @@ -5,7 +5,7 @@ import java.util.List; | ... | @@ -5,7 +5,7 @@ import java.util.List; |
5 | import org.onlab.onos.net.DeviceId; | 5 | import org.onlab.onos.net.DeviceId; |
6 | import org.onlab.onos.net.device.PortDescription; | 6 | import org.onlab.onos.net.device.PortDescription; |
7 | import org.onlab.onos.net.provider.ProviderId; | 7 | import org.onlab.onos.net.provider.ProviderId; |
8 | -import org.onlab.onos.store.common.impl.Timestamped; | 8 | +import org.onlab.onos.store.impl.Timestamped; |
9 | 9 | ||
10 | import com.google.common.base.MoreObjects; | 10 | import com.google.common.base.MoreObjects; |
11 | 11 | ... | ... |
... | @@ -5,7 +5,7 @@ import java.util.List; | ... | @@ -5,7 +5,7 @@ import java.util.List; |
5 | import org.onlab.onos.net.DeviceId; | 5 | import org.onlab.onos.net.DeviceId; |
6 | import org.onlab.onos.net.device.PortDescription; | 6 | import org.onlab.onos.net.device.PortDescription; |
7 | import org.onlab.onos.net.provider.ProviderId; | 7 | import org.onlab.onos.net.provider.ProviderId; |
8 | -import org.onlab.onos.store.common.impl.Timestamped; | 8 | +import org.onlab.onos.store.impl.Timestamped; |
9 | 9 | ||
10 | import com.esotericsoftware.kryo.Kryo; | 10 | import com.esotericsoftware.kryo.Kryo; |
11 | import com.esotericsoftware.kryo.Serializer; | 11 | import com.esotericsoftware.kryo.Serializer; | ... | ... |
... | @@ -3,7 +3,7 @@ package org.onlab.onos.store.device.impl; | ... | @@ -3,7 +3,7 @@ package org.onlab.onos.store.device.impl; |
3 | import org.onlab.onos.net.DeviceId; | 3 | import org.onlab.onos.net.DeviceId; |
4 | import org.onlab.onos.net.device.PortDescription; | 4 | import org.onlab.onos.net.device.PortDescription; |
5 | import org.onlab.onos.net.provider.ProviderId; | 5 | import org.onlab.onos.net.provider.ProviderId; |
6 | -import org.onlab.onos.store.common.impl.Timestamped; | 6 | +import org.onlab.onos.store.impl.Timestamped; |
7 | 7 | ||
8 | import com.google.common.base.MoreObjects; | 8 | import com.google.common.base.MoreObjects; |
9 | 9 | ... | ... |
... | @@ -3,7 +3,7 @@ package org.onlab.onos.store.device.impl; | ... | @@ -3,7 +3,7 @@ package org.onlab.onos.store.device.impl; |
3 | import org.onlab.onos.net.DeviceId; | 3 | import org.onlab.onos.net.DeviceId; |
4 | import org.onlab.onos.net.device.PortDescription; | 4 | import org.onlab.onos.net.device.PortDescription; |
5 | import org.onlab.onos.net.provider.ProviderId; | 5 | import org.onlab.onos.net.provider.ProviderId; |
6 | -import org.onlab.onos.store.common.impl.Timestamped; | 6 | +import org.onlab.onos.store.impl.Timestamped; |
7 | 7 | ||
8 | import com.esotericsoftware.kryo.Kryo; | 8 | import com.esotericsoftware.kryo.Kryo; |
9 | import com.esotericsoftware.kryo.Serializer; | 9 | import com.esotericsoftware.kryo.Serializer; | ... | ... |
1 | +package org.onlab.onos.store.flow; | ||
2 | + | ||
3 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
4 | + | ||
5 | +import java.util.Collection; | ||
6 | +import java.util.Collections; | ||
7 | + | ||
8 | +import org.onlab.onos.cluster.NodeId; | ||
9 | + | ||
10 | +import com.google.common.base.Optional; | ||
11 | + | ||
12 | +/** | ||
13 | + * Class to represent placement information about Master/Backup copy. | ||
14 | + */ | ||
15 | +public final class ReplicaInfo { | ||
16 | + | ||
17 | + private final Optional<NodeId> master; | ||
18 | + private final Collection<NodeId> backups; | ||
19 | + | ||
20 | + /** | ||
21 | + * Creates a ReplicaInfo instance. | ||
22 | + * | ||
23 | + * @param master NodeId of the node where the master copy should be | ||
24 | + * @param backups collection of NodeId, where backup copies should be placed | ||
25 | + */ | ||
26 | + public ReplicaInfo(NodeId master, Collection<NodeId> backups) { | ||
27 | + this.master = Optional.fromNullable(master); | ||
28 | + this.backups = checkNotNull(backups); | ||
29 | + } | ||
30 | + | ||
31 | + /** | ||
32 | + * Returns the NodeId, if there is a Node where the master copy should be. | ||
33 | + * | ||
34 | + * @return NodeId, where the master copy should be placed | ||
35 | + */ | ||
36 | + public Optional<NodeId> master() { | ||
37 | + return master; | ||
38 | + } | ||
39 | + | ||
40 | + /** | ||
41 | + * Returns the collection of NodeId, where backup copies should be placed. | ||
42 | + * | ||
43 | + * @return collection of NodeId, where backup copies should be placed | ||
44 | + */ | ||
45 | + public Collection<NodeId> backups() { | ||
46 | + return backups; | ||
47 | + } | ||
48 | + | ||
49 | + // for Serializer | ||
50 | + private ReplicaInfo() { | ||
51 | + this.master = Optional.absent(); | ||
52 | + this.backups = Collections.emptyList(); | ||
53 | + } | ||
54 | +} |
1 | +package org.onlab.onos.store.flow; | ||
2 | + | ||
3 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
4 | + | ||
5 | +import org.onlab.onos.event.AbstractEvent; | ||
6 | +import org.onlab.onos.net.DeviceId; | ||
7 | + | ||
8 | +/** | ||
9 | + * Describes a device replicainfo event. | ||
10 | + */ | ||
11 | +public class ReplicaInfoEvent extends AbstractEvent<ReplicaInfoEvent.Type, DeviceId> { | ||
12 | + | ||
13 | + private final ReplicaInfo replicaInfo; | ||
14 | + | ||
15 | + /** | ||
16 | + * Types of Replica info event. | ||
17 | + */ | ||
18 | + public enum Type { | ||
19 | + /** | ||
20 | + * Event to notify that master placement should be changed. | ||
21 | + */ | ||
22 | + MASTER_CHANGED, | ||
23 | + // | ||
24 | + // BACKUPS_CHANGED? | ||
25 | + } | ||
26 | + | ||
27 | + | ||
28 | + /** | ||
29 | + * Creates an event of a given type and for the specified device, | ||
30 | + * and replica info. | ||
31 | + * | ||
32 | + * @param type replicainfo event type | ||
33 | + * @param device event device subject | ||
34 | + * @param replicaInfo replicainfo | ||
35 | + */ | ||
36 | + public ReplicaInfoEvent(Type type, DeviceId device, ReplicaInfo replicaInfo) { | ||
37 | + super(type, device); | ||
38 | + this.replicaInfo = checkNotNull(replicaInfo); | ||
39 | + } | ||
40 | + | ||
41 | + /** | ||
42 | + * Returns the current replica information for the subject. | ||
43 | + * | ||
44 | + * @return replica information for the subject | ||
45 | + */ | ||
46 | + public ReplicaInfo replicaInfo() { | ||
47 | + return replicaInfo; | ||
48 | + }; | ||
49 | +} |
1 | +package org.onlab.onos.store.flow; | ||
2 | + | ||
3 | +import org.onlab.onos.net.DeviceId; | ||
4 | + | ||
5 | +/** | ||
6 | + * Service to return where the replica should be placed. | ||
7 | + */ | ||
8 | +public interface ReplicaInfoService { | ||
9 | + | ||
10 | + // returns where it should be. | ||
11 | + /** | ||
12 | + * Returns the placement information for given Device. | ||
13 | + * | ||
14 | + * @param deviceId identifier of the device | ||
15 | + * @return placement information | ||
16 | + */ | ||
17 | + ReplicaInfo getReplicaInfoFor(DeviceId deviceId); | ||
18 | + | ||
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 | } | ... | ... |
core/store/dist/src/main/java/org/onlab/onos/store/flow/impl/FlowStoreMessageSubjects.java
0 → 100644
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 | +} |
... | @@ -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 | -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 | 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 | ... | ... |
... | @@ -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 | ... | ... |
providers/host/bin/pom.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
5 | + <modelVersion>4.0.0</modelVersion> | ||
6 | + | ||
7 | + <parent> | ||
8 | + <groupId>org.onlab.onos</groupId> | ||
9 | + <artifactId>onos-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> |
providers/host/pom.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
5 | + <modelVersion>4.0.0</modelVersion> | ||
6 | + | ||
7 | + <parent> | ||
8 | + <groupId>org.onlab.onos</groupId> | ||
9 | + <artifactId>onos-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 | +} |
providers/host/src/test/java/org.onlab.onos.provider.host.impl/HostLocationProviderTest.java
0 → 100644
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 | +} |
providers/lldp/pom.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
5 | + <modelVersion>4.0.0</modelVersion> | ||
6 | + | ||
7 | + | ||
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 | +} |
... | @@ -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: | ... | ... |
providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
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 | } | ... | ... |
providers/openflow/host/src/main/java/org/onlab/onos/provider/of/host/impl/OpenFlowHostProvider.java
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; | ... | ... |
providers/openflow/link/src/main/java/org/onlab/onos/provider/of/link/impl/OpenFlowLinkProvider.java
... | @@ -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 | ... | ... |
... | @@ -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 | ... | ... |
tools/dev/onos.cshrc
0 → 100644
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}" | ... | ... |
tools/test/cells/single_optical
0 → 100644
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 | +} |
-
Please register or login to post a comment