blob: faa8ea546c100a747aa572f858c068dc33cbab40 [file] [log] [blame]
Ray Milkey140e4782015-04-24 11:25:13 -07001/*
2 * Copyright 2014-2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.xosintegration;
17
Jonathan Hart5e9a63d2015-05-19 16:21:46 -070018import com.eclipsesource.json.JsonArray;
19import com.eclipsesource.json.JsonObject;
alshabib60562282015-06-01 16:45:04 -070020import com.google.common.collect.Maps;
Jonathan Hart5e9a63d2015-05-19 16:21:46 -070021import com.sun.jersey.api.client.Client;
Jonathan Hartb4558032015-05-20 16:32:04 -070022import com.sun.jersey.api.client.ClientHandlerException;
Jonathan Hart5e9a63d2015-05-19 16:21:46 -070023import com.sun.jersey.api.client.ClientResponse;
24import com.sun.jersey.api.client.WebResource;
25import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
Ray Milkey140e4782015-04-24 11:25:13 -070026import org.apache.felix.scr.annotations.Activate;
27import org.apache.felix.scr.annotations.Component;
28import org.apache.felix.scr.annotations.Deactivate;
29import org.apache.felix.scr.annotations.Modified;
30import org.apache.felix.scr.annotations.Property;
31import org.apache.felix.scr.annotations.Reference;
32import org.apache.felix.scr.annotations.ReferenceCardinality;
33import org.apache.felix.scr.annotations.Service;
Jonathan Hart5e9a63d2015-05-19 16:21:46 -070034import org.onlab.packet.VlanId;
Ray Milkey140e4782015-04-24 11:25:13 -070035import org.onlab.util.Tools;
36import org.onosproject.cfg.ComponentConfigService;
37import org.onosproject.core.ApplicationId;
38import org.onosproject.core.CoreService;
Jonathan Hart5e9a63d2015-05-19 16:21:46 -070039import org.onosproject.net.ConnectPoint;
40import org.onosproject.net.DeviceId;
41import org.onosproject.net.PortNumber;
42import org.onosproject.net.flow.DefaultTrafficSelector;
43import org.onosproject.net.flow.DefaultTrafficTreatment;
44import org.onosproject.net.flow.TrafficSelector;
45import org.onosproject.net.flow.TrafficTreatment;
46import org.onosproject.net.flowobjective.DefaultForwardingObjective;
47import org.onosproject.net.flowobjective.FlowObjectiveService;
48import org.onosproject.net.flowobjective.ForwardingObjective;
Ray Milkey140e4782015-04-24 11:25:13 -070049import org.osgi.service.component.ComponentContext;
50import org.slf4j.Logger;
51
Jonathan Hart5e9a63d2015-05-19 16:21:46 -070052import java.util.Dictionary;
alshabib60562282015-06-01 16:45:04 -070053import java.util.Map;
Jonathan Hart5e9a63d2015-05-19 16:21:46 -070054import java.util.Set;
55import java.util.stream.Collectors;
56import java.util.stream.IntStream;
Ray Milkey140e4782015-04-24 11:25:13 -070057
58import static com.google.common.base.Strings.isNullOrEmpty;
59import static com.google.common.net.MediaType.JSON_UTF_8;
alshabib60562282015-06-01 16:45:04 -070060import static java.net.HttpURLConnection.*;
Ray Milkey140e4782015-04-24 11:25:13 -070061import static org.slf4j.LoggerFactory.getLogger;
62
63
64/**
65 * XOS interface application.
66 */
67@Component(immediate = true)
68@Service
69public class OnosXOSIntegrationManager implements VoltTenantService {
Ray Milkeydea98172015-05-18 10:39:39 -070070 private static final String XOS_SERVER_ADDRESS_PROPERTY_NAME =
71 "xosServerAddress";
72 private static final String XOS_SERVER_PORT_PROPERTY_NAME =
73 "xosServerPort";
74 private static final String XOS_PROVIDER_SERVICE_PROPERTY_NAME =
75 "xosProviderService";
Ray Milkey140e4782015-04-24 11:25:13 -070076
77 private static final String TEST_XOS_SERVER_ADDRESS = "10.254.1.22";
78 private static final int TEST_XOS_SERVER_PORT = 8000;
79 private static final String XOS_TENANT_BASE_URI = "/xoslib/volttenant/";
Ray Milkeydea98172015-05-18 10:39:39 -070080 private static final int TEST_XOS_PROVIDER_SERVICE = 1;
Ray Milkey140e4782015-04-24 11:25:13 -070081
Jonathan Hartb4558032015-05-20 16:32:04 -070082 private static final int PRIORITY = 50000;
Jonathan Hart5e9a63d2015-05-19 16:21:46 -070083 private static final DeviceId FABRIC_DEVICE_ID = DeviceId.deviceId("of:5e3e486e73000187");
84 private static final PortNumber FABRIC_OLT_CONNECT_POINT = PortNumber.portNumber(2);
85 private static final PortNumber FABRIC_VCPE_CONNECT_POINT = PortNumber.portNumber(3);
86 private static final String FABRIC_CONTROLLER_ADDRESS = "10.0.3.136";
87 private static final int FABRIC_SERVER_PORT = 8181;
88 private static final String FABRIC_BASE_URI = "/onos/cordfabric/vlans/add";
89
90 private static final ConnectPoint FABRIC_PORT = new ConnectPoint(
91 DeviceId.deviceId("of:000090e2ba82f974"),
92 PortNumber.portNumber(2));
93
Ray Milkey140e4782015-04-24 11:25:13 -070094 private final Logger log = getLogger(getClass());
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected CoreService coreService;
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected ComponentConfigService cfgService;
Ray Milkeydea98172015-05-18 10:39:39 -070099
Jonathan Hart5e9a63d2015-05-19 16:21:46 -0700100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected FlowObjectiveService flowObjectiveService;
102
Ray Milkeydea98172015-05-18 10:39:39 -0700103 @Property(name = XOS_SERVER_ADDRESS_PROPERTY_NAME,
Ray Milkey140e4782015-04-24 11:25:13 -0700104 value = TEST_XOS_SERVER_ADDRESS,
105 label = "XOS Server address")
106 protected String xosServerAddress = TEST_XOS_SERVER_ADDRESS;
Ray Milkeydea98172015-05-18 10:39:39 -0700107
108 @Property(name = XOS_SERVER_PORT_PROPERTY_NAME,
Ray Milkey140e4782015-04-24 11:25:13 -0700109 intValue = TEST_XOS_SERVER_PORT,
110 label = "XOS Server port")
111 protected int xosServerPort = TEST_XOS_SERVER_PORT;
Ray Milkeydea98172015-05-18 10:39:39 -0700112
113 @Property(name = XOS_PROVIDER_SERVICE_PROPERTY_NAME,
114 intValue = TEST_XOS_PROVIDER_SERVICE,
115 label = "XOS Provider Service")
116 protected int xosProviderService = TEST_XOS_PROVIDER_SERVICE;
117
Ray Milkey140e4782015-04-24 11:25:13 -0700118 private ApplicationId appId;
alshabib60562282015-06-01 16:45:04 -0700119 private Map<String, ConnectPoint> nodeToPort;
Ray Milkey140e4782015-04-24 11:25:13 -0700120
121 @Activate
122 public void activate(ComponentContext context) {
123 log.info("XOS app is starting");
124 cfgService.registerProperties(getClass());
125 appId = coreService.registerApplication("org.onosproject.xosintegration");
alshabib60562282015-06-01 16:45:04 -0700126
127 setupMap();
128
Ray Milkey140e4782015-04-24 11:25:13 -0700129 readComponentConfiguration(context);
130
131 log.info("XOS({}) started", appId.id());
132 }
133
134 @Deactivate
135 public void deactivate() {
136 cfgService.unregisterProperties(getClass(), false);
137 log.info("XOS({}) stopped", appId.id());
138 }
139
140 @Modified
141 public void modified(ComponentContext context) {
142 readComponentConfiguration(context);
143 }
144
alshabib60562282015-06-01 16:45:04 -0700145 private void setupMap() {
146 nodeToPort = Maps.newHashMap();
147
148 nodeToPort.put("cordcompute01.onlab.us", new ConnectPoint(FABRIC_DEVICE_ID,
149 PortNumber.portNumber(4)));
150
151 nodeToPort.put("cordcompute02.onlab.us", new ConnectPoint(FABRIC_DEVICE_ID,
152 PortNumber.portNumber(3)));
153 }
154
Ray Milkey140e4782015-04-24 11:25:13 -0700155 /**
156 * Converts a JSON representation of a tenant into a tenant object.
157 *
158 * @param jsonTenant JSON object representing the tenant
159 * @return volt tenant object
160 */
161 private VoltTenant jsonToTenant(JsonObject jsonTenant) {
162 return VoltTenant.builder()
163 .withHumanReadableName(jsonTenant.get("humanReadableName").asString())
164 .withId(jsonTenant.get("id").asInt())
165 .withProviderService(jsonTenant.get("provider_service").asInt())
166 .withServiceSpecificId(jsonTenant.get("service_specific_id").asString())
167 .withVlanId(jsonTenant.get("vlan_id").asString())
168 .build();
169 }
170
171 /**
172 * Converts a tenant object into a JSON string.
173 *
174 * @param tenant volt tenant object to convert
175 * @return JSON string for the tenant
176 */
177 private String tenantToJson(VoltTenant tenant) {
178 return "{"
179 + "\"humanReadableName\": \"" + tenant.humanReadableName() + "\","
180 + "\"id\": \"" + tenant.id() + "\","
181 + "\"provider_service\": \"" + tenant.providerService() + "\","
182 + "\"service_specific_id\": \"" + tenant.serviceSpecificId() + "\","
183 + "\"vlan_id\": \"" + tenant.vlanId() + "\""
184 + "}";
185 }
186
187 /**
188 * Gets a client web resource builder for the base XOS REST API
189 * with no additional URI.
190 *
191 * @return web resource builder
192 */
Simon Hunt8483e9d2015-05-26 18:22:07 -0700193 @Deprecated
Ray Milkey140e4782015-04-24 11:25:13 -0700194 private WebResource.Builder getClientBuilder() {
195 return getClientBuilder("");
196 }
197
198 /**
199 * Gets a client web resource builder for the base XOS REST API
200 * with an optional additional URI.
201 *
202 * @return web resource builder
203 */
Simon Hunt8483e9d2015-05-26 18:22:07 -0700204 @Deprecated
Ray Milkey140e4782015-04-24 11:25:13 -0700205 private WebResource.Builder getClientBuilder(String uri) {
206 String baseUrl = "http://" + xosServerAddress + ":"
207 + Integer.toString(xosServerPort);
208 Client client = Client.create();
209 client.addFilter(new HTTPBasicAuthFilter("padmin@vicci.org", "letmein"));
210 WebResource resource = client.resource(baseUrl
211 + XOS_TENANT_BASE_URI + uri);
212 return resource.accept(JSON_UTF_8.toString())
213 .type(JSON_UTF_8.toString());
214 }
215
216 /**
217 * Performs a REST GET operation on the base XOS REST URI.
218 *
219 * @return JSON string fetched by the GET operation
220 */
Simon Hunt8483e9d2015-05-26 18:22:07 -0700221 @Deprecated
Ray Milkey140e4782015-04-24 11:25:13 -0700222 private String getRest() {
223 return getRest("");
224 }
225
226 /**
227 * Performs a REST GET operation on the base XOS REST URI with
228 * an optional additional URI.
229 *
230 * @return JSON string fetched by the GET operation
231 */
Simon Hunt8483e9d2015-05-26 18:22:07 -0700232 @Deprecated
Ray Milkey140e4782015-04-24 11:25:13 -0700233 private String getRest(String uri) {
234 WebResource.Builder builder = getClientBuilder(uri);
235 ClientResponse response = builder.get(ClientResponse.class);
236
237 if (response.getStatus() != HTTP_OK) {
238 log.info("REST GET request returned error code {}",
239 response.getStatus());
240 }
241 String jsonString = response.getEntity(String.class);
242 log.info("JSON read:\n{}", jsonString);
243
244 return jsonString;
245 }
246
247 /**
248 * Performs a REST POST operation of a json string on the base
249 * XOS REST URI with an optional additional URI.
250 *
251 * @param json JSON string to post
252 */
Simon Hunt8483e9d2015-05-26 18:22:07 -0700253 @Deprecated
alshabib60562282015-06-01 16:45:04 -0700254 private String postRest(String json) {
Ray Milkey140e4782015-04-24 11:25:13 -0700255 WebResource.Builder builder = getClientBuilder();
Jonathan Hartb4558032015-05-20 16:32:04 -0700256 ClientResponse response;
257
258 try {
259 response = builder.post(ClientResponse.class, json);
260 } catch (ClientHandlerException e) {
261 log.warn("Unable to contact REST server: {}", e.getMessage());
alshabib60562282015-06-01 16:45:04 -0700262 return "{ 'error' : 'oops no one home' }";
Jonathan Hartb4558032015-05-20 16:32:04 -0700263 }
Ray Milkey140e4782015-04-24 11:25:13 -0700264
265 if (response.getStatus() != HTTP_CREATED) {
266 log.info("REST POST request returned error code {}",
267 response.getStatus());
268 }
alshabib60562282015-06-01 16:45:04 -0700269 return response.getEntity(String.class);
Ray Milkey140e4782015-04-24 11:25:13 -0700270 }
271
272 /**
273 * Performs a REST DELETE operation on the base
274 * XOS REST URI with an optional additional URI.
275 *
276 * @param uri optional additional URI
277 */
Simon Hunt8483e9d2015-05-26 18:22:07 -0700278 @Deprecated
Ray Milkey140e4782015-04-24 11:25:13 -0700279 private void deleteRest(String uri) {
280 WebResource.Builder builder = getClientBuilder(uri);
281 ClientResponse response = builder.delete(ClientResponse.class);
282
283 if (response.getStatus() != HTTP_NO_CONTENT) {
284 log.info("REST DELETE request returned error code {}",
285 response.getStatus());
286 }
287 }
288
289 /**
290 * Deletes the tenant with the given ID.
291 *
292 * @param tenantId ID of tenant to delete
293 */
294 private void deleteTenant(long tenantId) {
295 deleteRest(Long.toString(tenantId));
296 }
297
298 @Override
299 public Set<VoltTenant> getAllTenants() {
300 String jsonString = getRest();
301
302 JsonArray voltTenantItems = JsonArray.readFrom(jsonString);
303
304 return IntStream.range(0, voltTenantItems.size())
305 .mapToObj(index -> jsonToTenant(voltTenantItems.get(index).asObject()))
306 .collect(Collectors.toSet());
307 }
308
309 @Override
310 public void removeTenant(long id) {
311 deleteTenant(id);
312 }
313
314 @Override
315 public VoltTenant addTenant(VoltTenant newTenant) {
Ray Milkeydea98172015-05-18 10:39:39 -0700316 long providerServiceId = newTenant.providerService();
317 if (providerServiceId == -1) {
318 providerServiceId = xosProviderService;
319 }
320 VoltTenant tenantToCreate = VoltTenant.builder()
321 .withProviderService(providerServiceId)
322 .withServiceSpecificId(newTenant.serviceSpecificId())
323 .withVlanId(newTenant.vlanId())
Jonathan Hart5e9a63d2015-05-19 16:21:46 -0700324 .withPort(newTenant.port())
Ray Milkeydea98172015-05-18 10:39:39 -0700325 .build();
326 String json = tenantToJson(tenantToCreate);
Jonathan Hart5e9a63d2015-05-19 16:21:46 -0700327
alshabib60562282015-06-01 16:45:04 -0700328 //provisionDataPlane(tenantToCreate);
Jonathan Hart5e9a63d2015-05-19 16:21:46 -0700329
alshabib60562282015-06-01 16:45:04 -0700330 String retJson = postRest(json);
Jonathan Hart5e9a63d2015-05-19 16:21:46 -0700331
alshabib60562282015-06-01 16:45:04 -0700332 fetchCPELocation(newTenant, retJson);
Jonathan Hart5e9a63d2015-05-19 16:21:46 -0700333
Ray Milkey140e4782015-04-24 11:25:13 -0700334 return newTenant;
335 }
336
alshabib60562282015-06-01 16:45:04 -0700337 private void fetchCPELocation(VoltTenant newTenant, String jsonString) {
338 JsonObject json = JsonObject.readFrom(jsonString);
339
340 if (json.get("computeNodeName") != null) {
341 ConnectPoint point = nodeToPort.get(json.get("computeNodeName"));
342
343 provisionFabric(VlanId.vlanId(Short.parseShort(newTenant.vlanId())),
344 point);
345 }
346
347 }
348
Ray Milkey140e4782015-04-24 11:25:13 -0700349 @Override
350 public VoltTenant getTenant(long id) {
351 String jsonString = getRest(Long.toString(id));
352 JsonObject jsonTenant = JsonObject.readFrom(jsonString);
353 if (jsonTenant.get("id") != null) {
354 return jsonToTenant(jsonTenant);
355 } else {
356 return null;
357 }
358 }
359
Jonathan Hart5e9a63d2015-05-19 16:21:46 -0700360 private void provisionDataPlane(VoltTenant tenant) {
361 VlanId vlan = VlanId.vlanId(Short.parseShort(tenant.vlanId()));
362
363 TrafficSelector fromGateway = DefaultTrafficSelector.builder()
364 .matchInPhyPort(tenant.port().port())
365 .build();
366
367 TrafficSelector fromFabric = DefaultTrafficSelector.builder()
368 .matchInPhyPort(FABRIC_PORT.port())
369 .matchVlanId(vlan)
370 .build();
371
372 TrafficTreatment toFabric = DefaultTrafficTreatment.builder()
373 .pushVlan()
374 .setVlanId(vlan)
375 .setOutput(FABRIC_PORT.port())
376 .build();
377
378 TrafficTreatment toGateway = DefaultTrafficTreatment.builder()
379 .popVlan()
380 .setOutput(tenant.port().port())
381 .build();
382
383 ForwardingObjective forwardToFabric = DefaultForwardingObjective.builder()
384 .withFlag(ForwardingObjective.Flag.VERSATILE)
Jonathan Hartb4558032015-05-20 16:32:04 -0700385 .withPriority(PRIORITY)
Jonathan Hart5e9a63d2015-05-19 16:21:46 -0700386 .makePermanent()
387 .fromApp(appId)
388 .withSelector(fromGateway)
389 .withTreatment(toFabric)
390 .add();
391
392 ForwardingObjective forwardToGateway = DefaultForwardingObjective.builder()
393 .withFlag(ForwardingObjective.Flag.VERSATILE)
Jonathan Hartb4558032015-05-20 16:32:04 -0700394 .withPriority(PRIORITY)
Jonathan Hart5e9a63d2015-05-19 16:21:46 -0700395 .makePermanent()
396 .fromApp(appId)
397 .withSelector(fromFabric)
398 .withTreatment(toGateway)
399 .add();
400
401 flowObjectiveService.forward(FABRIC_PORT.deviceId(), forwardToFabric);
402 flowObjectiveService.forward(FABRIC_PORT.deviceId(), forwardToGateway);
403 }
404
alshabib60562282015-06-01 16:45:04 -0700405 private void provisionFabric(VlanId vlanId, ConnectPoint point) {
406 //String json = "{\"vlan\":" + vlanId + ",\"ports\":[";
407 //json += "{\"device\":\"" + FABRIC_DEVICE_ID.toString() + "\",\"port\":\""
408 // + FABRIC_OLT_CONNECT_POINT.toString() + "\"},";
409 //json += "{\"device\":\"" + FABRIC_DEVICE_ID.toString() + "\",\"port\":\""
410 // + FABRIC_VCPE_CONNECT_POINT.toString() + "\"}";
411 //json += "]}";
412
413 JsonObject node = new JsonObject();
414 node.add("vlan", vlanId.toShort());
415 JsonArray array = new JsonArray();
416 JsonObject cp1 = new JsonObject();
417 JsonObject cp2 = new JsonObject();
418 cp1.add("device", point.deviceId().toString());
419 cp1.add("port", point.port().toLong());
420 cp2.add("device", FABRIC_DEVICE_ID.toString());
421 cp2.add("port", FABRIC_OLT_CONNECT_POINT.toString());
422 array.add(cp1);
423 array.add(cp2);
424 node.add("ports", array);
425
Jonathan Hart5e9a63d2015-05-19 16:21:46 -0700426
427 String baseUrl = "http://" + FABRIC_CONTROLLER_ADDRESS + ":"
428 + Integer.toString(FABRIC_SERVER_PORT);
429 Client client = Client.create();
Jonathan Hartb4558032015-05-20 16:32:04 -0700430 WebResource resource = client.resource(baseUrl + FABRIC_BASE_URI);
Jonathan Hart5e9a63d2015-05-19 16:21:46 -0700431 WebResource.Builder builder = resource.accept(JSON_UTF_8.toString())
432 .type(JSON_UTF_8.toString());
433
Jonathan Hartb4558032015-05-20 16:32:04 -0700434 try {
alshabib60562282015-06-01 16:45:04 -0700435 builder.post(ClientResponse.class, node);
Jonathan Hartb4558032015-05-20 16:32:04 -0700436 } catch (ClientHandlerException e) {
437 log.warn("Unable to contact fabric REST server:", e.getMessage());
438 return;
439 }
Jonathan Hart5e9a63d2015-05-19 16:21:46 -0700440 }
441
Ray Milkey140e4782015-04-24 11:25:13 -0700442 /**
443 * Extracts properties from the component configuration context.
444 *
445 * @param context the component context
446 */
447 private void readComponentConfiguration(ComponentContext context) {
448 Dictionary<?, ?> properties = context.getProperties();
449
Ray Milkeydea98172015-05-18 10:39:39 -0700450 String newXosServerAddress =
451 Tools.get(properties, XOS_SERVER_ADDRESS_PROPERTY_NAME);
Ray Milkey140e4782015-04-24 11:25:13 -0700452 if (!isNullOrEmpty(newXosServerAddress)) {
453 xosServerAddress = newXosServerAddress;
454 }
455
Ray Milkeydea98172015-05-18 10:39:39 -0700456 String newXosServerPortString =
457 Tools.get(properties, XOS_SERVER_PORT_PROPERTY_NAME);
Ray Milkey140e4782015-04-24 11:25:13 -0700458 if (!isNullOrEmpty(newXosServerPortString)) {
459 xosServerPort = Integer.parseInt(newXosServerPortString);
460 }
Ray Milkeydea98172015-05-18 10:39:39 -0700461
462 String newXosProviderServiceString =
463 Tools.get(properties, XOS_PROVIDER_SERVICE_PROPERTY_NAME);
464 if (!isNullOrEmpty(newXosProviderServiceString)) {
465 xosProviderService = Integer.parseInt(newXosProviderServiceString);
466 }
Ray Milkey140e4782015-04-24 11:25:13 -0700467 }
468}
469
470