blob: eaebb6972ea8cfc4a4186bd90c57a266eaeccc98 [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;
alshabibb4d31712016-06-01 18:51:03 -070030import org.opencord.cordvtn.api.CordVtnNode;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070031import org.opencord.cordvtn.api.DependencyService;
alshabibb4d31712016-06-01 18:51:03 -070032import org.opencord.cordvtn.api.Instance;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070033import org.onosproject.core.DefaultGroupId;
34import org.onosproject.core.GroupId;
35import org.onosproject.net.DeviceId;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070036import org.onosproject.net.PortNumber;
37import org.onosproject.net.flow.DefaultFlowRule;
38import org.onosproject.net.flow.DefaultTrafficSelector;
39import org.onosproject.net.flow.DefaultTrafficTreatment;
40import org.onosproject.net.flow.FlowRule;
41import org.onosproject.net.flow.TrafficSelector;
42import org.onosproject.net.flow.TrafficTreatment;
43import org.onosproject.net.flow.instructions.ExtensionTreatment;
44import org.onosproject.net.group.DefaultGroupDescription;
45import org.onosproject.net.group.DefaultGroupKey;
46import org.onosproject.net.group.Group;
47import org.onosproject.net.group.GroupBucket;
48import org.onosproject.net.group.GroupBuckets;
49import org.onosproject.net.group.GroupDescription;
50import org.onosproject.net.group.GroupKey;
Hyunsun Moonba290072015-12-16 20:53:23 -080051import org.onosproject.net.group.GroupService;
Hyunsun Moon486ed1b2016-05-13 18:58:35 -070052import org.onosproject.xosclient.api.VtnService;
Hyunsun Moon5f51f622016-05-13 04:17:53 -070053import org.onosproject.xosclient.api.VtnServiceId;
Hyunsun Moone9d75992015-09-15 22:39:16 -070054import org.slf4j.Logger;
55
Hyunsun Moon8b530e32016-02-03 00:11:11 -080056import java.util.List;
Hyunsun Moon7dca9b32015-10-08 22:25:30 -070057import java.util.Map;
Hyunsun Moond05b32e2016-03-02 19:27:26 -080058import java.util.Objects;
Hyunsun Moon05f528a2015-11-04 17:34:35 -080059import java.util.Set;
Hyunsun Moon05f528a2015-11-04 17:34:35 -080060import java.util.stream.Collectors;
Hyunsun Moone9d75992015-09-15 22:39:16 -070061
alshabibb4d31712016-06-01 18:51:03 -070062import static org.opencord.cordvtn.impl.CordVtnPipeline.*;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070063import static org.onosproject.net.group.DefaultGroupBucket.createSelectGroupBucket;
Hyunsun Moone9d75992015-09-15 22:39:16 -070064import static org.slf4j.LoggerFactory.getLogger;
65
66/**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070067 * Provisions service dependency capabilities between network services.
Hyunsun Moone9d75992015-09-15 22:39:16 -070068 */
69@Component(immediate = true)
70@Service
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070071public class DependencyManager extends AbstractInstanceHandler implements DependencyService {
Hyunsun Moone9d75992015-09-15 22:39:16 -070072
73 protected final Logger log = getLogger(getClass());
74
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonba290072015-12-16 20:53:23 -080076 protected GroupService groupService;
77
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070078 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected CordVtnPipeline pipeline;
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected CordVtnNodeManager nodeManager;
83
Hyunsun Moone9d75992015-09-15 22:39:16 -070084 @Activate
85 protected void activate() {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070086 super.activate();
Hyunsun Moone9d75992015-09-15 22:39:16 -070087 }
88
89 @Deactivate
90 protected void deactivate() {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070091 super.deactivate();
Hyunsun Moonde372572016-01-14 03:42:47 -080092 }
93
94 @Override
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070095 public void createDependency(VtnServiceId tServiceId, VtnServiceId pServiceId,
Hyunsun Moon5f7ed8a2016-02-10 17:02:37 -080096 boolean isBidirectional) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070097 VtnService tService = getVtnService(tServiceId);
98 VtnService pService = getVtnService(pServiceId);
Hyunsun Moon97eaf502015-12-07 14:06:28 -080099
Hyunsun Moonba290072015-12-16 20:53:23 -0800100 if (tService == null || pService == null) {
Hyunsun Moon486ed1b2016-05-13 18:58:35 -0700101 log.error("Failed to create dependency between {} and {}",
102 tServiceId, pServiceId);
Hyunsun Moonba290072015-12-16 20:53:23 -0800103 return;
104 }
105
Hyunsun Moon486ed1b2016-05-13 18:58:35 -0700106 log.info("Created dependency between {} and {}", tService.name(), pService.name());
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700107 serviceDependencyRules(tService, pService, isBidirectional, true);
Hyunsun Moon9274aaf2015-12-04 11:35:25 -0800108 }
109
110 @Override
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700111 public void removeDependency(VtnServiceId tServiceId, VtnServiceId pServiceId) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700112 VtnService tService = getVtnService(tServiceId);
113 VtnService pService = getVtnService(pServiceId);
Hyunsun Moon97eaf502015-12-07 14:06:28 -0800114
Hyunsun Moonba290072015-12-16 20:53:23 -0800115 if (tService == null || pService == null) {
Hyunsun Moon486ed1b2016-05-13 18:58:35 -0700116 log.error("Failed to remove dependency between {} and {}",
117 tServiceId, pServiceId);
Hyunsun Moonba290072015-12-16 20:53:23 -0800118 return;
119 }
120
Hyunsun Moon486ed1b2016-05-13 18:58:35 -0700121 log.info("Removed dependency between {} and {}", tService.name(), pService.name());
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700122 serviceDependencyRules(tService, pService, true, false);
Hyunsun Moon9274aaf2015-12-04 11:35:25 -0800123 }
124
Hyunsun Mooncb799442016-01-15 20:03:18 -0800125 @Override
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700126 public void instanceDetected(Instance instance) {
127 VtnService service = getVtnService(instance.serviceId());
128 if (service == null) {
Hyunsun Moon4edb0172015-11-07 22:08:43 -0800129 return;
130 }
131
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700132 // TODO get bidirectional information from XOS once XOS supports
133 service.tenantServices().stream().forEach(
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700134 tServiceId -> createDependency(tServiceId, service.id(), true));
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700135 service.providerServices().stream().forEach(
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700136 pServiceId -> createDependency(service.id(), pServiceId, true));
Hyunsun Moon01556a52016-02-12 12:48:47 -0800137
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700138 updateProviderServiceInstances(service);
Hyunsun Moon4edb0172015-11-07 22:08:43 -0800139 }
140
Hyunsun Mooncb799442016-01-15 20:03:18 -0800141 @Override
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700142 public void instanceRemoved(Instance instance) {
143 VtnService service = getVtnService(instance.serviceId());
144 if (service == null) {
Hyunsun Moon01556a52016-02-12 12:48:47 -0800145 return;
146 }
147
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700148 if (!service.providerServices().isEmpty()) {
149 removeInstanceFromTenantService(instance, service);
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800150 }
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700151 if (!service.tenantServices().isEmpty()) {
152 updateProviderServiceInstances(service);
Hyunsun Moon01556a52016-02-12 12:48:47 -0800153 }
154 }
155
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700156 private void updateProviderServiceInstances(VtnService service) {
157 GroupKey groupKey = getGroupKey(service.id());
158
159 Set<DeviceId> devices = nodeManager.completeNodes().stream()
Hyunsun Moon81a13562016-08-04 13:48:08 -0700160 .map(CordVtnNode::integrationBridgeId)
Hyunsun Mooncb799442016-01-15 20:03:18 -0800161 .collect(Collectors.toSet());
Hyunsun Moon01556a52016-02-12 12:48:47 -0800162
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700163 for (DeviceId deviceId : devices) {
164 Group group = groupService.getGroup(deviceId, groupKey);
165 if (group == null) {
166 log.trace("No group exists for service {} in {}", service.id(), deviceId);
167 continue;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800168 }
169
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700170 List<GroupBucket> oldBuckets = group.buckets().buckets();
171 List<GroupBucket> newBuckets = getServiceGroupBuckets(
172 deviceId, service.vni(), getInstances(service.id())).buckets();
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800173
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700174 if (oldBuckets.equals(newBuckets)) {
175 continue;
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800176 }
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700177
178 List<GroupBucket> bucketsToRemove = Lists.newArrayList(oldBuckets);
179 bucketsToRemove.removeAll(newBuckets);
180 if (!bucketsToRemove.isEmpty()) {
181 groupService.removeBucketsFromGroup(
182 deviceId,
183 groupKey,
184 new GroupBuckets(bucketsToRemove),
185 groupKey, appId);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700186 log.debug("Removes instances from {} : {}", service.name(), bucketsToRemove);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700187 }
188
189 List<GroupBucket> bucketsToAdd = Lists.newArrayList(newBuckets);
190 bucketsToAdd.removeAll(oldBuckets);
191 if (!bucketsToAdd.isEmpty()) {
192 groupService.addBucketsToGroup(
193 deviceId,
194 groupKey,
195 new GroupBuckets(bucketsToAdd),
196 groupKey, appId);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700197 log.debug("Adds instances to {} : {}", service.name(), bucketsToRemove);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700198 }
199 }
200 }
201
202 private void removeInstanceFromTenantService(Instance instance, VtnService service) {
203 service.providerServices().stream().forEach(pServiceId -> {
204 Map<DeviceId, Set<PortNumber>> inPorts = Maps.newHashMap();
205 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
206
207 inPorts.put(instance.deviceId(), Sets.newHashSet(instance.portNumber()));
208 outGroups.put(instance.deviceId(), getGroupId(pServiceId, instance.deviceId()));
209
210 inServiceRule(inPorts, outGroups, false);
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800211 });
212 }
213
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700214 private void serviceDependencyRules(VtnService tService, VtnService pService,
215 boolean isBidirectional, boolean install) {
216 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
217 Map<DeviceId, Set<PortNumber>> inPorts = Maps.newHashMap();
218
219 nodeManager.completeNodes().stream().forEach(node -> {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700220 DeviceId deviceId = node.integrationBridgeId();
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700221 GroupId groupId = createServiceGroup(deviceId, pService);
222 outGroups.put(deviceId, groupId);
223
224 Set<PortNumber> tServiceInstances = getInstances(tService.id())
225 .stream()
226 .filter(instance -> instance.deviceId().equals(deviceId))
227 .map(Instance::portNumber)
228 .collect(Collectors.toSet());
229 inPorts.put(deviceId, tServiceInstances);
230 });
231
232 Ip4Prefix srcRange = tService.subnet().getIp4Prefix();
233 Ip4Prefix dstRange = pService.subnet().getIp4Prefix();
234
235 indirectAccessRule(srcRange, pService.serviceIp().getIp4Address(), outGroups, install);
236 directAccessRule(srcRange, dstRange, install);
237 if (isBidirectional) {
238 directAccessRule(dstRange, srcRange, install);
239 }
240 inServiceRule(inPorts, outGroups, install);
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800241 }
242
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700243 private void indirectAccessRule(Ip4Prefix srcRange, Ip4Address serviceIp,
244 Map<DeviceId, GroupId> outGroups, boolean install) {
245 TrafficSelector selector = DefaultTrafficSelector.builder()
246 .matchEthType(Ethernet.TYPE_IPV4)
247 .matchIPSrc(srcRange)
248 .matchIPDst(serviceIp.toIpPrefix())
249 .build();
250
251 for (Map.Entry<DeviceId, GroupId> outGroup : outGroups.entrySet()) {
252 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
253 .group(outGroup.getValue())
254 .build();
255
256 FlowRule flowRule = DefaultFlowRule.builder()
257 .fromApp(appId)
258 .withSelector(selector)
259 .withTreatment(treatment)
260 .withPriority(PRIORITY_HIGH)
261 .forDevice(outGroup.getKey())
Hyunsun Moonfb417942016-06-23 14:48:20 -0700262 .forTable(TABLE_ACCESS_TYPE)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700263 .makePermanent()
264 .build();
265
266 pipeline.processFlowRule(install, flowRule);
267 }
268 }
269
270 private void directAccessRule(Ip4Prefix srcRange, Ip4Prefix dstRange, boolean install) {
271 TrafficSelector selector = DefaultTrafficSelector.builder()
272 .matchEthType(Ethernet.TYPE_IPV4)
273 .matchIPSrc(srcRange)
274 .matchIPDst(dstRange)
275 .build();
276
277 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moonfb417942016-06-23 14:48:20 -0700278 .transition(TABLE_DST_IP)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700279 .build();
280
281 nodeManager.completeNodes().stream().forEach(node -> {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700282 DeviceId deviceId = node.integrationBridgeId();
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700283 FlowRule flowRuleDirect = DefaultFlowRule.builder()
284 .fromApp(appId)
285 .withSelector(selector)
286 .withTreatment(treatment)
287 .withPriority(PRIORITY_DEFAULT)
288 .forDevice(deviceId)
Hyunsun Moonfb417942016-06-23 14:48:20 -0700289 .forTable(TABLE_ACCESS_TYPE)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700290 .makePermanent()
291 .build();
292
293 pipeline.processFlowRule(install, flowRuleDirect);
294 });
295 }
296
297 private void inServiceRule(Map<DeviceId, Set<PortNumber>> inPorts,
298 Map<DeviceId, GroupId> outGroups, boolean install) {
299 for (Map.Entry<DeviceId, Set<PortNumber>> entry : inPorts.entrySet()) {
300 Set<PortNumber> ports = entry.getValue();
301 DeviceId deviceId = entry.getKey();
302
303 GroupId groupId = outGroups.get(deviceId);
304 if (groupId == null) {
305 continue;
306 }
307
308 ports.stream().forEach(port -> {
309 TrafficSelector selector = DefaultTrafficSelector.builder()
310 .matchInPort(port)
311 .build();
312
313 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
314 .group(groupId)
315 .build();
316
317 FlowRule flowRule = DefaultFlowRule.builder()
318 .fromApp(appId)
319 .withSelector(selector)
320 .withTreatment(treatment)
321 .withPriority(PRIORITY_DEFAULT)
322 .forDevice(deviceId)
323 .forTable(TABLE_IN_SERVICE)
324 .makePermanent()
325 .build();
326
327 pipeline.processFlowRule(install, flowRule);
328 });
329 }
330 }
331
332 private GroupId getGroupId(VtnServiceId serviceId, DeviceId deviceId) {
333 return new DefaultGroupId(Objects.hash(serviceId, deviceId));
334 }
335
336 private GroupKey getGroupKey(VtnServiceId serviceId) {
337 return new DefaultGroupKey(serviceId.id().getBytes());
338 }
339
340 private GroupId createServiceGroup(DeviceId deviceId, VtnService service) {
341 GroupKey groupKey = getGroupKey(service.id());
342 Group group = groupService.getGroup(deviceId, groupKey);
343 GroupId groupId = getGroupId(service.id(), deviceId);
344
345 if (group != null) {
346 log.debug("Group {} is already exist in {}", service.id(), deviceId);
347 return groupId;
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800348 }
349
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700350 GroupBuckets buckets = getServiceGroupBuckets(
351 deviceId, service.vni(), getInstances(service.id()));
352 GroupDescription groupDescription = new DefaultGroupDescription(
353 deviceId,
354 GroupDescription.Type.SELECT,
355 buckets,
356 groupKey,
357 groupId.id(),
358 appId);
Hyunsun Moon486ed1b2016-05-13 18:58:35 -0700359
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700360 groupService.addGroup(groupDescription);
361 return groupId;
362 }
363
364 private GroupBuckets getServiceGroupBuckets(DeviceId deviceId, long tunnelId,
365 Set<Instance> instances) {
366 List<GroupBucket> buckets = Lists.newArrayList();
367 instances.stream().forEach(instance -> {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700368 Ip4Address tunnelIp = nodeManager.dataIp(instance.deviceId()).getIp4Address();
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700369 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
370
371 if (deviceId.equals(instance.deviceId())) {
372 tBuilder.setEthDst(instance.mac())
373 .setOutput(instance.portNumber());
374 } else {
375 ExtensionTreatment tunnelDst =
376 pipeline.tunnelDstTreatment(deviceId, tunnelIp);
377 tBuilder.setEthDst(instance.mac())
378 .extension(tunnelDst, deviceId)
379 .setTunnelId(tunnelId)
380 .setOutput(nodeManager.tunnelPort(instance.deviceId()));
381 }
382 buckets.add(createSelectGroupBucket(tBuilder.build()));
383 });
384 return new GroupBuckets(buckets);
Hyunsun Moon61e79ee2016-04-14 19:04:23 -0700385 }
Hyunsun Moone9d75992015-09-15 22:39:16 -0700386}