blob: c22982b26ceb8c68d521533bae356c2c829f4f5f [file] [log] [blame]
Hyunsun Moone9d75992015-09-15 22:39:16 -07001/*
Brian O'Connor8e57fd52016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Hyunsun Moone9d75992015-09-15 22:39:16 -07003 *
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 */
alshabibb4d31712016-06-01 18:51:03 -070016package org.opencord.cordvtn.impl;
Hyunsun Moone9d75992015-09-15 22:39:16 -070017
Hyunsun Moon8b530e32016-02-03 00:11:11 -080018import com.google.common.collect.Lists;
Hyunsun Moonb5f92e52016-02-17 15:02:06 -080019import com.google.common.collect.Maps;
Hyunsun Moon7dca9b32015-10-08 22:25:30 -070020import com.google.common.collect.Sets;
Hyunsun Moone9d75992015-09-15 22:39:16 -070021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.felix.scr.annotations.Service;
Hyunsun Moon022272f2016-01-11 15:30:42 -080027import org.onlab.packet.Ethernet;
Hyunsun Moon8b530e32016-02-03 00:11:11 -080028import org.onlab.packet.Ip4Address;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070029import org.onlab.packet.Ip4Prefix;
Hyunsun Moon1e88fef2016-08-04 14:00:35 -070030import org.onosproject.xosclient.api.VtnServiceApi;
alshabibb4d31712016-06-01 18:51:03 -070031import org.opencord.cordvtn.api.CordVtnNode;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070032import org.opencord.cordvtn.api.DependencyService;
alshabibb4d31712016-06-01 18:51:03 -070033import org.opencord.cordvtn.api.Instance;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070034import org.onosproject.core.DefaultGroupId;
35import org.onosproject.core.GroupId;
36import org.onosproject.net.DeviceId;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070037import org.onosproject.net.PortNumber;
38import org.onosproject.net.flow.DefaultFlowRule;
39import org.onosproject.net.flow.DefaultTrafficSelector;
40import org.onosproject.net.flow.DefaultTrafficTreatment;
41import org.onosproject.net.flow.FlowRule;
42import org.onosproject.net.flow.TrafficSelector;
43import org.onosproject.net.flow.TrafficTreatment;
44import org.onosproject.net.flow.instructions.ExtensionTreatment;
45import org.onosproject.net.group.DefaultGroupDescription;
46import org.onosproject.net.group.DefaultGroupKey;
47import org.onosproject.net.group.Group;
48import org.onosproject.net.group.GroupBucket;
49import org.onosproject.net.group.GroupBuckets;
50import org.onosproject.net.group.GroupDescription;
51import org.onosproject.net.group.GroupKey;
Hyunsun Moonba290072015-12-16 20:53:23 -080052import org.onosproject.net.group.GroupService;
Hyunsun Moon486ed1b2016-05-13 18:58:35 -070053import org.onosproject.xosclient.api.VtnService;
Hyunsun Moon5f51f622016-05-13 04:17:53 -070054import org.onosproject.xosclient.api.VtnServiceId;
Hyunsun Moone9d75992015-09-15 22:39:16 -070055import org.slf4j.Logger;
56
Hyunsun Moon8b530e32016-02-03 00:11:11 -080057import java.util.List;
Hyunsun Moon7dca9b32015-10-08 22:25:30 -070058import java.util.Map;
Hyunsun Moond05b32e2016-03-02 19:27:26 -080059import java.util.Objects;
Hyunsun Moon05f528a2015-11-04 17:34:35 -080060import java.util.Set;
Hyunsun Moon05f528a2015-11-04 17:34:35 -080061import java.util.stream.Collectors;
Hyunsun Moone9d75992015-09-15 22:39:16 -070062
alshabibb4d31712016-06-01 18:51:03 -070063import static org.opencord.cordvtn.impl.CordVtnPipeline.*;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070064import static org.onosproject.net.group.DefaultGroupBucket.createSelectGroupBucket;
Hyunsun Moone9d75992015-09-15 22:39:16 -070065import static org.slf4j.LoggerFactory.getLogger;
66
67/**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070068 * Provisions service dependency capabilities between network services.
Hyunsun Moone9d75992015-09-15 22:39:16 -070069 */
70@Component(immediate = true)
71@Service
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070072public class DependencyManager extends AbstractInstanceHandler implements DependencyService {
Hyunsun Moone9d75992015-09-15 22:39:16 -070073
74 protected final Logger log = getLogger(getClass());
75
76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonba290072015-12-16 20:53:23 -080077 protected GroupService groupService;
78
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070079 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected CordVtnPipeline pipeline;
81
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected CordVtnNodeManager nodeManager;
84
Hyunsun Moone9d75992015-09-15 22:39:16 -070085 @Activate
86 protected void activate() {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070087 super.activate();
Hyunsun Moone9d75992015-09-15 22:39:16 -070088 }
89
90 @Deactivate
91 protected void deactivate() {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070092 super.deactivate();
Hyunsun Moonde372572016-01-14 03:42:47 -080093 }
94
95 @Override
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070096 public void createDependency(VtnServiceId tServiceId, VtnServiceId pServiceId,
Hyunsun Moon5f7ed8a2016-02-10 17:02:37 -080097 boolean isBidirectional) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070098 VtnService tService = getVtnService(tServiceId);
99 VtnService pService = getVtnService(pServiceId);
Hyunsun Moon97eaf502015-12-07 14:06:28 -0800100
Hyunsun Moonba290072015-12-16 20:53:23 -0800101 if (tService == null || pService == null) {
Hyunsun Moon486ed1b2016-05-13 18:58:35 -0700102 log.error("Failed to create dependency between {} and {}",
103 tServiceId, pServiceId);
Hyunsun Moonba290072015-12-16 20:53:23 -0800104 return;
105 }
106
Hyunsun Moon486ed1b2016-05-13 18:58:35 -0700107 log.info("Created dependency between {} and {}", tService.name(), pService.name());
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700108 serviceDependencyRules(tService, pService, isBidirectional, true);
Hyunsun Moon9274aaf2015-12-04 11:35:25 -0800109 }
110
111 @Override
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700112 public void removeDependency(VtnServiceId tServiceId, VtnServiceId pServiceId) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700113 VtnService tService = getVtnService(tServiceId);
114 VtnService pService = getVtnService(pServiceId);
Hyunsun Moon97eaf502015-12-07 14:06:28 -0800115
Hyunsun Moonba290072015-12-16 20:53:23 -0800116 if (tService == null || pService == null) {
Hyunsun Moon486ed1b2016-05-13 18:58:35 -0700117 log.error("Failed to remove dependency between {} and {}",
118 tServiceId, pServiceId);
Hyunsun Moonba290072015-12-16 20:53:23 -0800119 return;
120 }
121
Hyunsun Moon486ed1b2016-05-13 18:58:35 -0700122 log.info("Removed dependency between {} and {}", tService.name(), pService.name());
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700123 serviceDependencyRules(tService, pService, true, false);
Hyunsun Moon9274aaf2015-12-04 11:35:25 -0800124 }
125
Hyunsun Mooncb799442016-01-15 20:03:18 -0800126 @Override
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700127 public void instanceDetected(Instance instance) {
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700128 // TODO remove this when XOS provides access agent information
129 // and handle it the same way wit the other instances
130 if (instance.serviceType() == VtnServiceApi.ServiceType.ACCESS_AGENT) {
131 return;
132 }
133
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700134 VtnService service = getVtnService(instance.serviceId());
135 if (service == null) {
Hyunsun Moon4edb0172015-11-07 22:08:43 -0800136 return;
137 }
138
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700139 // TODO get bidirectional information from XOS once XOS supports
140 service.tenantServices().stream().forEach(
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700141 tServiceId -> createDependency(tServiceId, service.id(), true));
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700142 service.providerServices().stream().forEach(
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700143 pServiceId -> createDependency(service.id(), pServiceId, true));
Hyunsun Moon01556a52016-02-12 12:48:47 -0800144
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700145 updateProviderServiceInstances(service);
Hyunsun Moon4edb0172015-11-07 22:08:43 -0800146 }
147
Hyunsun Mooncb799442016-01-15 20:03:18 -0800148 @Override
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700149 public void instanceRemoved(Instance instance) {
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700150 // TODO remove this when XOS provides access agent information
151 // and handle it the same way wit the other instances
152 if (instance.serviceType() == VtnServiceApi.ServiceType.ACCESS_AGENT) {
153 return;
154 }
155
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700156 VtnService service = getVtnService(instance.serviceId());
157 if (service == null) {
Hyunsun Moon01556a52016-02-12 12:48:47 -0800158 return;
159 }
160
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700161 if (!service.providerServices().isEmpty()) {
162 removeInstanceFromTenantService(instance, service);
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800163 }
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700164 if (!service.tenantServices().isEmpty()) {
165 updateProviderServiceInstances(service);
Hyunsun Moon01556a52016-02-12 12:48:47 -0800166 }
167 }
168
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700169 private void updateProviderServiceInstances(VtnService service) {
170 GroupKey groupKey = getGroupKey(service.id());
171
172 Set<DeviceId> devices = nodeManager.completeNodes().stream()
Hyunsun Moon81a13562016-08-04 13:48:08 -0700173 .map(CordVtnNode::integrationBridgeId)
Hyunsun Mooncb799442016-01-15 20:03:18 -0800174 .collect(Collectors.toSet());
Hyunsun Moon01556a52016-02-12 12:48:47 -0800175
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700176 for (DeviceId deviceId : devices) {
177 Group group = groupService.getGroup(deviceId, groupKey);
178 if (group == null) {
179 log.trace("No group exists for service {} in {}", service.id(), deviceId);
180 continue;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800181 }
182
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700183 List<GroupBucket> oldBuckets = group.buckets().buckets();
184 List<GroupBucket> newBuckets = getServiceGroupBuckets(
185 deviceId, service.vni(), getInstances(service.id())).buckets();
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800186
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700187 if (oldBuckets.equals(newBuckets)) {
188 continue;
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800189 }
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700190
191 List<GroupBucket> bucketsToRemove = Lists.newArrayList(oldBuckets);
192 bucketsToRemove.removeAll(newBuckets);
193 if (!bucketsToRemove.isEmpty()) {
194 groupService.removeBucketsFromGroup(
195 deviceId,
196 groupKey,
197 new GroupBuckets(bucketsToRemove),
198 groupKey, appId);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700199 log.debug("Removes instances from {} : {}", service.name(), bucketsToRemove);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700200 }
201
202 List<GroupBucket> bucketsToAdd = Lists.newArrayList(newBuckets);
203 bucketsToAdd.removeAll(oldBuckets);
204 if (!bucketsToAdd.isEmpty()) {
205 groupService.addBucketsToGroup(
206 deviceId,
207 groupKey,
208 new GroupBuckets(bucketsToAdd),
209 groupKey, appId);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700210 log.debug("Adds instances to {} : {}", service.name(), bucketsToRemove);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700211 }
212 }
213 }
214
215 private void removeInstanceFromTenantService(Instance instance, VtnService service) {
216 service.providerServices().stream().forEach(pServiceId -> {
217 Map<DeviceId, Set<PortNumber>> inPorts = Maps.newHashMap();
218 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
219
220 inPorts.put(instance.deviceId(), Sets.newHashSet(instance.portNumber()));
221 outGroups.put(instance.deviceId(), getGroupId(pServiceId, instance.deviceId()));
222
223 inServiceRule(inPorts, outGroups, false);
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800224 });
225 }
226
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700227 private void serviceDependencyRules(VtnService tService, VtnService pService,
228 boolean isBidirectional, boolean install) {
229 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
230 Map<DeviceId, Set<PortNumber>> inPorts = Maps.newHashMap();
231
232 nodeManager.completeNodes().stream().forEach(node -> {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700233 DeviceId deviceId = node.integrationBridgeId();
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700234 GroupId groupId = createServiceGroup(deviceId, pService);
235 outGroups.put(deviceId, groupId);
236
237 Set<PortNumber> tServiceInstances = getInstances(tService.id())
238 .stream()
239 .filter(instance -> instance.deviceId().equals(deviceId))
240 .map(Instance::portNumber)
241 .collect(Collectors.toSet());
242 inPorts.put(deviceId, tServiceInstances);
243 });
244
245 Ip4Prefix srcRange = tService.subnet().getIp4Prefix();
246 Ip4Prefix dstRange = pService.subnet().getIp4Prefix();
247
248 indirectAccessRule(srcRange, pService.serviceIp().getIp4Address(), outGroups, install);
249 directAccessRule(srcRange, dstRange, install);
250 if (isBidirectional) {
251 directAccessRule(dstRange, srcRange, install);
252 }
253 inServiceRule(inPorts, outGroups, install);
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800254 }
255
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700256 private void indirectAccessRule(Ip4Prefix srcRange, Ip4Address serviceIp,
257 Map<DeviceId, GroupId> outGroups, boolean install) {
258 TrafficSelector selector = DefaultTrafficSelector.builder()
259 .matchEthType(Ethernet.TYPE_IPV4)
260 .matchIPSrc(srcRange)
261 .matchIPDst(serviceIp.toIpPrefix())
262 .build();
263
264 for (Map.Entry<DeviceId, GroupId> outGroup : outGroups.entrySet()) {
265 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
266 .group(outGroup.getValue())
267 .build();
268
269 FlowRule flowRule = DefaultFlowRule.builder()
270 .fromApp(appId)
271 .withSelector(selector)
272 .withTreatment(treatment)
273 .withPriority(PRIORITY_HIGH)
274 .forDevice(outGroup.getKey())
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700275 .forTable(TABLE_ACCESS)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700276 .makePermanent()
277 .build();
278
279 pipeline.processFlowRule(install, flowRule);
280 }
281 }
282
283 private void directAccessRule(Ip4Prefix srcRange, Ip4Prefix dstRange, boolean install) {
284 TrafficSelector selector = DefaultTrafficSelector.builder()
285 .matchEthType(Ethernet.TYPE_IPV4)
286 .matchIPSrc(srcRange)
287 .matchIPDst(dstRange)
288 .build();
289
290 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700291 .transition(TABLE_DST)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700292 .build();
293
294 nodeManager.completeNodes().stream().forEach(node -> {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700295 DeviceId deviceId = node.integrationBridgeId();
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700296 FlowRule flowRuleDirect = DefaultFlowRule.builder()
297 .fromApp(appId)
298 .withSelector(selector)
299 .withTreatment(treatment)
300 .withPriority(PRIORITY_DEFAULT)
301 .forDevice(deviceId)
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700302 .forTable(TABLE_ACCESS)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700303 .makePermanent()
304 .build();
305
306 pipeline.processFlowRule(install, flowRuleDirect);
307 });
308 }
309
310 private void inServiceRule(Map<DeviceId, Set<PortNumber>> inPorts,
311 Map<DeviceId, GroupId> outGroups, boolean install) {
312 for (Map.Entry<DeviceId, Set<PortNumber>> entry : inPorts.entrySet()) {
313 Set<PortNumber> ports = entry.getValue();
314 DeviceId deviceId = entry.getKey();
315
316 GroupId groupId = outGroups.get(deviceId);
317 if (groupId == null) {
318 continue;
319 }
320
321 ports.stream().forEach(port -> {
322 TrafficSelector selector = DefaultTrafficSelector.builder()
323 .matchInPort(port)
324 .build();
325
326 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
327 .group(groupId)
328 .build();
329
330 FlowRule flowRule = DefaultFlowRule.builder()
331 .fromApp(appId)
332 .withSelector(selector)
333 .withTreatment(treatment)
334 .withPriority(PRIORITY_DEFAULT)
335 .forDevice(deviceId)
336 .forTable(TABLE_IN_SERVICE)
337 .makePermanent()
338 .build();
339
340 pipeline.processFlowRule(install, flowRule);
341 });
342 }
343 }
344
345 private GroupId getGroupId(VtnServiceId serviceId, DeviceId deviceId) {
346 return new DefaultGroupId(Objects.hash(serviceId, deviceId));
347 }
348
349 private GroupKey getGroupKey(VtnServiceId serviceId) {
350 return new DefaultGroupKey(serviceId.id().getBytes());
351 }
352
353 private GroupId createServiceGroup(DeviceId deviceId, VtnService service) {
354 GroupKey groupKey = getGroupKey(service.id());
355 Group group = groupService.getGroup(deviceId, groupKey);
356 GroupId groupId = getGroupId(service.id(), deviceId);
357
358 if (group != null) {
359 log.debug("Group {} is already exist in {}", service.id(), deviceId);
360 return groupId;
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800361 }
362
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700363 GroupBuckets buckets = getServiceGroupBuckets(
364 deviceId, service.vni(), getInstances(service.id()));
365 GroupDescription groupDescription = new DefaultGroupDescription(
366 deviceId,
367 GroupDescription.Type.SELECT,
368 buckets,
369 groupKey,
370 groupId.id(),
371 appId);
Hyunsun Moon486ed1b2016-05-13 18:58:35 -0700372
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700373 groupService.addGroup(groupDescription);
374 return groupId;
375 }
376
377 private GroupBuckets getServiceGroupBuckets(DeviceId deviceId, long tunnelId,
378 Set<Instance> instances) {
379 List<GroupBucket> buckets = Lists.newArrayList();
380 instances.stream().forEach(instance -> {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700381 Ip4Address tunnelIp = nodeManager.dataIp(instance.deviceId()).getIp4Address();
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700382 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
383
384 if (deviceId.equals(instance.deviceId())) {
385 tBuilder.setEthDst(instance.mac())
386 .setOutput(instance.portNumber());
387 } else {
388 ExtensionTreatment tunnelDst =
389 pipeline.tunnelDstTreatment(deviceId, tunnelIp);
390 tBuilder.setEthDst(instance.mac())
391 .extension(tunnelDst, deviceId)
392 .setTunnelId(tunnelId)
393 .setOutput(nodeManager.tunnelPort(instance.deviceId()));
394 }
395 buckets.add(createSelectGroupBucket(tBuilder.build()));
396 });
397 return new GroupBuckets(buckets);
Hyunsun Moon61e79ee2016-04-14 19:04:23 -0700398 }
Hyunsun Moone9d75992015-09-15 22:39:16 -0700399}