blob: dccbd4e253923f340becb664b492f6e0a9bbf47e [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;
20import com.sun.jersey.api.client.Client;
21import com.sun.jersey.api.client.ClientResponse;
22import com.sun.jersey.api.client.WebResource;
23import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
Ray Milkey140e4782015-04-24 11:25:13 -070024import org.apache.felix.scr.annotations.Activate;
25import org.apache.felix.scr.annotations.Component;
26import org.apache.felix.scr.annotations.Deactivate;
27import org.apache.felix.scr.annotations.Modified;
28import org.apache.felix.scr.annotations.Property;
29import org.apache.felix.scr.annotations.Reference;
30import org.apache.felix.scr.annotations.ReferenceCardinality;
31import org.apache.felix.scr.annotations.Service;
Jonathan Hart5e9a63d2015-05-19 16:21:46 -070032import org.onlab.packet.VlanId;
Ray Milkey140e4782015-04-24 11:25:13 -070033import org.onlab.util.Tools;
34import org.onosproject.cfg.ComponentConfigService;
35import org.onosproject.core.ApplicationId;
36import org.onosproject.core.CoreService;
Jonathan Hart5e9a63d2015-05-19 16:21:46 -070037import org.onosproject.net.ConnectPoint;
38import org.onosproject.net.DeviceId;
39import org.onosproject.net.PortNumber;
40import org.onosproject.net.flow.DefaultTrafficSelector;
41import org.onosproject.net.flow.DefaultTrafficTreatment;
42import org.onosproject.net.flow.TrafficSelector;
43import org.onosproject.net.flow.TrafficTreatment;
44import org.onosproject.net.flowobjective.DefaultForwardingObjective;
45import org.onosproject.net.flowobjective.FlowObjectiveService;
46import org.onosproject.net.flowobjective.ForwardingObjective;
Ray Milkey140e4782015-04-24 11:25:13 -070047import org.osgi.service.component.ComponentContext;
48import org.slf4j.Logger;
49
Jonathan Hart5e9a63d2015-05-19 16:21:46 -070050import java.util.Dictionary;
51import java.util.Set;
52import java.util.stream.Collectors;
53import java.util.stream.IntStream;
Ray Milkey140e4782015-04-24 11:25:13 -070054
55import static com.google.common.base.Strings.isNullOrEmpty;
56import static com.google.common.net.MediaType.JSON_UTF_8;
57import static java.net.HttpURLConnection.HTTP_CREATED;
58import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
59import static java.net.HttpURLConnection.HTTP_OK;
60import static org.slf4j.LoggerFactory.getLogger;
61
62
63/**
64 * XOS interface application.
65 */
66@Component(immediate = true)
67@Service
68public class OnosXOSIntegrationManager implements VoltTenantService {
Ray Milkeydea98172015-05-18 10:39:39 -070069 private static final String XOS_SERVER_ADDRESS_PROPERTY_NAME =
70 "xosServerAddress";
71 private static final String XOS_SERVER_PORT_PROPERTY_NAME =
72 "xosServerPort";
73 private static final String XOS_PROVIDER_SERVICE_PROPERTY_NAME =
74 "xosProviderService";
Ray Milkey140e4782015-04-24 11:25:13 -070075
76 private static final String TEST_XOS_SERVER_ADDRESS = "10.254.1.22";
77 private static final int TEST_XOS_SERVER_PORT = 8000;
78 private static final String XOS_TENANT_BASE_URI = "/xoslib/volttenant/";
Ray Milkeydea98172015-05-18 10:39:39 -070079 private static final int TEST_XOS_PROVIDER_SERVICE = 1;
Ray Milkey140e4782015-04-24 11:25:13 -070080
Jonathan Hart5e9a63d2015-05-19 16:21:46 -070081 private static final DeviceId FABRIC_DEVICE_ID = DeviceId.deviceId("of:5e3e486e73000187");
82 private static final PortNumber FABRIC_OLT_CONNECT_POINT = PortNumber.portNumber(2);
83 private static final PortNumber FABRIC_VCPE_CONNECT_POINT = PortNumber.portNumber(3);
84 private static final String FABRIC_CONTROLLER_ADDRESS = "10.0.3.136";
85 private static final int FABRIC_SERVER_PORT = 8181;
86 private static final String FABRIC_BASE_URI = "/onos/cordfabric/vlans/add";
87
88 private static final ConnectPoint FABRIC_PORT = new ConnectPoint(
89 DeviceId.deviceId("of:000090e2ba82f974"),
90 PortNumber.portNumber(2));
91
Ray Milkey140e4782015-04-24 11:25:13 -070092 private final Logger log = getLogger(getClass());
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected CoreService coreService;
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected ComponentConfigService cfgService;
Ray Milkeydea98172015-05-18 10:39:39 -070097
Jonathan Hart5e9a63d2015-05-19 16:21:46 -070098 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 protected FlowObjectiveService flowObjectiveService;
100
Ray Milkeydea98172015-05-18 10:39:39 -0700101 @Property(name = XOS_SERVER_ADDRESS_PROPERTY_NAME,
Ray Milkey140e4782015-04-24 11:25:13 -0700102 value = TEST_XOS_SERVER_ADDRESS,
103 label = "XOS Server address")
104 protected String xosServerAddress = TEST_XOS_SERVER_ADDRESS;
Ray Milkeydea98172015-05-18 10:39:39 -0700105
106 @Property(name = XOS_SERVER_PORT_PROPERTY_NAME,
Ray Milkey140e4782015-04-24 11:25:13 -0700107 intValue = TEST_XOS_SERVER_PORT,
108 label = "XOS Server port")
109 protected int xosServerPort = TEST_XOS_SERVER_PORT;
Ray Milkeydea98172015-05-18 10:39:39 -0700110
111 @Property(name = XOS_PROVIDER_SERVICE_PROPERTY_NAME,
112 intValue = TEST_XOS_PROVIDER_SERVICE,
113 label = "XOS Provider Service")
114 protected int xosProviderService = TEST_XOS_PROVIDER_SERVICE;
115
Ray Milkey140e4782015-04-24 11:25:13 -0700116 private ApplicationId appId;
117
118 @Activate
119 public void activate(ComponentContext context) {
120 log.info("XOS app is starting");
121 cfgService.registerProperties(getClass());
122 appId = coreService.registerApplication("org.onosproject.xosintegration");
123 readComponentConfiguration(context);
124
125 log.info("XOS({}) started", appId.id());
126 }
127
128 @Deactivate
129 public void deactivate() {
130 cfgService.unregisterProperties(getClass(), false);
131 log.info("XOS({}) stopped", appId.id());
132 }
133
134 @Modified
135 public void modified(ComponentContext context) {
136 readComponentConfiguration(context);
137 }
138
139 /**
140 * Converts a JSON representation of a tenant into a tenant object.
141 *
142 * @param jsonTenant JSON object representing the tenant
143 * @return volt tenant object
144 */
145 private VoltTenant jsonToTenant(JsonObject jsonTenant) {
146 return VoltTenant.builder()
147 .withHumanReadableName(jsonTenant.get("humanReadableName").asString())
148 .withId(jsonTenant.get("id").asInt())
149 .withProviderService(jsonTenant.get("provider_service").asInt())
150 .withServiceSpecificId(jsonTenant.get("service_specific_id").asString())
151 .withVlanId(jsonTenant.get("vlan_id").asString())
152 .build();
153 }
154
155 /**
156 * Converts a tenant object into a JSON string.
157 *
158 * @param tenant volt tenant object to convert
159 * @return JSON string for the tenant
160 */
161 private String tenantToJson(VoltTenant tenant) {
162 return "{"
163 + "\"humanReadableName\": \"" + tenant.humanReadableName() + "\","
164 + "\"id\": \"" + tenant.id() + "\","
165 + "\"provider_service\": \"" + tenant.providerService() + "\","
166 + "\"service_specific_id\": \"" + tenant.serviceSpecificId() + "\","
167 + "\"vlan_id\": \"" + tenant.vlanId() + "\""
168 + "}";
169 }
170
171 /**
172 * Gets a client web resource builder for the base XOS REST API
173 * with no additional URI.
174 *
175 * @return web resource builder
176 */
177 private WebResource.Builder getClientBuilder() {
178 return getClientBuilder("");
179 }
180
181 /**
182 * Gets a client web resource builder for the base XOS REST API
183 * with an optional additional URI.
184 *
185 * @return web resource builder
186 */
187 private WebResource.Builder getClientBuilder(String uri) {
188 String baseUrl = "http://" + xosServerAddress + ":"
189 + Integer.toString(xosServerPort);
190 Client client = Client.create();
191 client.addFilter(new HTTPBasicAuthFilter("padmin@vicci.org", "letmein"));
192 WebResource resource = client.resource(baseUrl
193 + XOS_TENANT_BASE_URI + uri);
194 return resource.accept(JSON_UTF_8.toString())
195 .type(JSON_UTF_8.toString());
196 }
197
198 /**
199 * Performs a REST GET operation on the base XOS REST URI.
200 *
201 * @return JSON string fetched by the GET operation
202 */
203 private String getRest() {
204 return getRest("");
205 }
206
207 /**
208 * Performs a REST GET operation on the base XOS REST URI with
209 * an optional additional URI.
210 *
211 * @return JSON string fetched by the GET operation
212 */
213 private String getRest(String uri) {
214 WebResource.Builder builder = getClientBuilder(uri);
215 ClientResponse response = builder.get(ClientResponse.class);
216
217 if (response.getStatus() != HTTP_OK) {
218 log.info("REST GET request returned error code {}",
219 response.getStatus());
220 }
221 String jsonString = response.getEntity(String.class);
222 log.info("JSON read:\n{}", jsonString);
223
224 return jsonString;
225 }
226
227 /**
228 * Performs a REST POST operation of a json string on the base
229 * XOS REST URI with an optional additional URI.
230 *
231 * @param json JSON string to post
232 */
233 private void postRest(String json) {
234 WebResource.Builder builder = getClientBuilder();
235 ClientResponse response = builder.post(ClientResponse.class, json);
236
237 if (response.getStatus() != HTTP_CREATED) {
238 log.info("REST POST request returned error code {}",
239 response.getStatus());
240 }
241 }
242
243 /**
244 * Performs a REST DELETE operation on the base
245 * XOS REST URI with an optional additional URI.
246 *
247 * @param uri optional additional URI
248 */
249 private void deleteRest(String uri) {
250 WebResource.Builder builder = getClientBuilder(uri);
251 ClientResponse response = builder.delete(ClientResponse.class);
252
253 if (response.getStatus() != HTTP_NO_CONTENT) {
254 log.info("REST DELETE request returned error code {}",
255 response.getStatus());
256 }
257 }
258
259 /**
260 * Deletes the tenant with the given ID.
261 *
262 * @param tenantId ID of tenant to delete
263 */
264 private void deleteTenant(long tenantId) {
265 deleteRest(Long.toString(tenantId));
266 }
267
268 @Override
269 public Set<VoltTenant> getAllTenants() {
270 String jsonString = getRest();
271
272 JsonArray voltTenantItems = JsonArray.readFrom(jsonString);
273
274 return IntStream.range(0, voltTenantItems.size())
275 .mapToObj(index -> jsonToTenant(voltTenantItems.get(index).asObject()))
276 .collect(Collectors.toSet());
277 }
278
279 @Override
280 public void removeTenant(long id) {
281 deleteTenant(id);
282 }
283
284 @Override
285 public VoltTenant addTenant(VoltTenant newTenant) {
Ray Milkeydea98172015-05-18 10:39:39 -0700286 long providerServiceId = newTenant.providerService();
287 if (providerServiceId == -1) {
288 providerServiceId = xosProviderService;
289 }
290 VoltTenant tenantToCreate = VoltTenant.builder()
291 .withProviderService(providerServiceId)
292 .withServiceSpecificId(newTenant.serviceSpecificId())
293 .withVlanId(newTenant.vlanId())
Jonathan Hart5e9a63d2015-05-19 16:21:46 -0700294 .withPort(newTenant.port())
Ray Milkeydea98172015-05-18 10:39:39 -0700295 .build();
296 String json = tenantToJson(tenantToCreate);
Jonathan Hart5e9a63d2015-05-19 16:21:46 -0700297
298 provisionDataPlane(tenantToCreate);
299
Ray Milkey140e4782015-04-24 11:25:13 -0700300 postRest(json);
Jonathan Hart5e9a63d2015-05-19 16:21:46 -0700301
302 provisionFabric(VlanId.vlanId(Short.parseShort(newTenant.vlanId())));
303
Ray Milkey140e4782015-04-24 11:25:13 -0700304 return newTenant;
305 }
306
307 @Override
308 public VoltTenant getTenant(long id) {
309 String jsonString = getRest(Long.toString(id));
310 JsonObject jsonTenant = JsonObject.readFrom(jsonString);
311 if (jsonTenant.get("id") != null) {
312 return jsonToTenant(jsonTenant);
313 } else {
314 return null;
315 }
316 }
317
Jonathan Hart5e9a63d2015-05-19 16:21:46 -0700318 private void provisionDataPlane(VoltTenant tenant) {
319 VlanId vlan = VlanId.vlanId(Short.parseShort(tenant.vlanId()));
320
321 TrafficSelector fromGateway = DefaultTrafficSelector.builder()
322 .matchInPhyPort(tenant.port().port())
323 .build();
324
325 TrafficSelector fromFabric = DefaultTrafficSelector.builder()
326 .matchInPhyPort(FABRIC_PORT.port())
327 .matchVlanId(vlan)
328 .build();
329
330 TrafficTreatment toFabric = DefaultTrafficTreatment.builder()
331 .pushVlan()
332 .setVlanId(vlan)
333 .setOutput(FABRIC_PORT.port())
334 .build();
335
336 TrafficTreatment toGateway = DefaultTrafficTreatment.builder()
337 .popVlan()
338 .setOutput(tenant.port().port())
339 .build();
340
341 ForwardingObjective forwardToFabric = DefaultForwardingObjective.builder()
342 .withFlag(ForwardingObjective.Flag.VERSATILE)
343 .withPriority(1000)
344 .makePermanent()
345 .fromApp(appId)
346 .withSelector(fromGateway)
347 .withTreatment(toFabric)
348 .add();
349
350 ForwardingObjective forwardToGateway = DefaultForwardingObjective.builder()
351 .withFlag(ForwardingObjective.Flag.VERSATILE)
352 .withPriority(1000)
353 .makePermanent()
354 .fromApp(appId)
355 .withSelector(fromFabric)
356 .withTreatment(toGateway)
357 .add();
358
359 flowObjectiveService.forward(FABRIC_PORT.deviceId(), forwardToFabric);
360 flowObjectiveService.forward(FABRIC_PORT.deviceId(), forwardToGateway);
361 }
362
363 private void provisionFabric(VlanId vlanId) {
364 String json = "{\"vlan\":" + vlanId + ",\"ports\":[";
365 json += "{\"device\":\"" + FABRIC_DEVICE_ID.toString() + "\",\"port\":\""
366 + FABRIC_OLT_CONNECT_POINT.toString() + "\"},";
367 json += "{\"device\":\"" + FABRIC_DEVICE_ID.toString() + "\",\"port\":\""
368 + FABRIC_VCPE_CONNECT_POINT.toString() + "\"}";
369 json += "]}";
370
371 String baseUrl = "http://" + FABRIC_CONTROLLER_ADDRESS + ":"
372 + Integer.toString(FABRIC_SERVER_PORT);
373 Client client = Client.create();
374 client.addFilter(new HTTPBasicAuthFilter("padmin@vicci.org", "letmein"));
375 WebResource resource = client.resource(baseUrl
376 + FABRIC_BASE_URI);
377 WebResource.Builder builder = resource.accept(JSON_UTF_8.toString())
378 .type(JSON_UTF_8.toString());
379
380 ClientResponse response = builder.post(ClientResponse.class, json);
381
382 }
383
Ray Milkey140e4782015-04-24 11:25:13 -0700384 /**
385 * Extracts properties from the component configuration context.
386 *
387 * @param context the component context
388 */
389 private void readComponentConfiguration(ComponentContext context) {
390 Dictionary<?, ?> properties = context.getProperties();
391
Ray Milkeydea98172015-05-18 10:39:39 -0700392 String newXosServerAddress =
393 Tools.get(properties, XOS_SERVER_ADDRESS_PROPERTY_NAME);
Ray Milkey140e4782015-04-24 11:25:13 -0700394 if (!isNullOrEmpty(newXosServerAddress)) {
395 xosServerAddress = newXosServerAddress;
396 }
397
Ray Milkeydea98172015-05-18 10:39:39 -0700398 String newXosServerPortString =
399 Tools.get(properties, XOS_SERVER_PORT_PROPERTY_NAME);
Ray Milkey140e4782015-04-24 11:25:13 -0700400 if (!isNullOrEmpty(newXosServerPortString)) {
401 xosServerPort = Integer.parseInt(newXosServerPortString);
402 }
Ray Milkeydea98172015-05-18 10:39:39 -0700403
404 String newXosProviderServiceString =
405 Tools.get(properties, XOS_PROVIDER_SERVICE_PROPERTY_NAME);
406 if (!isNullOrEmpty(newXosProviderServiceString)) {
407 xosProviderService = Integer.parseInt(newXosProviderServiceString);
408 }
Ray Milkey140e4782015-04-24 11:25:13 -0700409 }
410}
411
412