blob: fa9c36a2a4e46bd734a17da6fc5afe9fa853b038 [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 Mooneaf75e62016-09-27 16:40:23 -070018import com.google.common.collect.ImmutableMap;
19import com.google.common.collect.ImmutableSet;
Hyunsun Moon8b530e32016-02-03 00:11:11 -080020import com.google.common.collect.Lists;
Hyunsun Moonb5f92e52016-02-17 15:02:06 -080021import com.google.common.collect.Maps;
Hyunsun Moone9d75992015-09-15 22:39:16 -070022import org.apache.felix.scr.annotations.Activate;
23import org.apache.felix.scr.annotations.Component;
24import org.apache.felix.scr.annotations.Deactivate;
25import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
27import org.apache.felix.scr.annotations.Service;
Hyunsun Moon022272f2016-01-11 15:30:42 -080028import org.onlab.packet.Ethernet;
Hyunsun Moon8b530e32016-02-03 00:11:11 -080029import org.onlab.packet.Ip4Address;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070030import org.onlab.packet.Ip4Prefix;
Hyunsun Mooneaf75e62016-09-27 16:40:23 -070031import org.onlab.util.KryoNamespace;
32import org.onosproject.cluster.ClusterService;
33import org.onosproject.cluster.LeadershipService;
34import org.onosproject.cluster.NodeId;
35import org.onosproject.store.serializers.KryoNamespaces;
36import org.onosproject.store.service.ConsistentMap;
37import org.onosproject.store.service.MapEvent;
38import org.onosproject.store.service.MapEventListener;
39import org.onosproject.store.service.Serializer;
40import org.onosproject.store.service.StorageService;
Hyunsun Moonfe31dd42016-09-30 11:34:22 -070041import org.onosproject.store.service.Versioned;
Hyunsun Moonfd5a24e2016-10-19 19:15:48 -070042import org.opencord.cordvtn.api.core.CordVtnAdminService;
43import org.opencord.cordvtn.api.node.CordVtnNode;
44import org.opencord.cordvtn.api.dependency.Dependency;
45import org.opencord.cordvtn.api.dependency.Dependency.Type;
46import org.opencord.cordvtn.api.dependency.DependencyService;
47import org.opencord.cordvtn.api.instance.Instance;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070048import org.onosproject.core.DefaultGroupId;
49import org.onosproject.core.GroupId;
50import org.onosproject.net.DeviceId;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070051import org.onosproject.net.PortNumber;
52import org.onosproject.net.flow.DefaultFlowRule;
53import org.onosproject.net.flow.DefaultTrafficSelector;
54import org.onosproject.net.flow.DefaultTrafficTreatment;
55import org.onosproject.net.flow.FlowRule;
56import org.onosproject.net.flow.TrafficSelector;
57import org.onosproject.net.flow.TrafficTreatment;
58import org.onosproject.net.flow.instructions.ExtensionTreatment;
59import org.onosproject.net.group.DefaultGroupDescription;
60import org.onosproject.net.group.DefaultGroupKey;
61import org.onosproject.net.group.Group;
62import org.onosproject.net.group.GroupBucket;
63import org.onosproject.net.group.GroupBuckets;
64import org.onosproject.net.group.GroupDescription;
65import org.onosproject.net.group.GroupKey;
Hyunsun Moonba290072015-12-16 20:53:23 -080066import org.onosproject.net.group.GroupService;
Hyunsun Moonfd5a24e2016-10-19 19:15:48 -070067import org.opencord.cordvtn.api.net.NetworkId;
68import org.opencord.cordvtn.api.net.ProviderNetwork;
69import org.opencord.cordvtn.api.net.SegmentId;
70import org.opencord.cordvtn.api.net.ServiceNetwork.ServiceNetworkType;
71import org.opencord.cordvtn.api.net.VtnNetwork;
72import org.opencord.cordvtn.api.net.VtnNetworkEvent;
73import org.opencord.cordvtn.api.net.VtnNetworkListener;
Hyunsun Mooneaf75e62016-09-27 16:40:23 -070074import org.opencord.cordvtn.impl.handler.AbstractInstanceHandler;
Hyunsun Moone9d75992015-09-15 22:39:16 -070075import org.slf4j.Logger;
76
Hyunsun Moonfe31dd42016-09-30 11:34:22 -070077import java.util.Collection;
Hyunsun Moon8b530e32016-02-03 00:11:11 -080078import java.util.List;
Hyunsun Moon7dca9b32015-10-08 22:25:30 -070079import java.util.Map;
Hyunsun Moond05b32e2016-03-02 19:27:26 -080080import java.util.Objects;
Hyunsun Moon05f528a2015-11-04 17:34:35 -080081import java.util.Set;
Hyunsun Moon05f528a2015-11-04 17:34:35 -080082import java.util.stream.Collectors;
Hyunsun Moone9d75992015-09-15 22:39:16 -070083
Hyunsun Moonfd5a24e2016-10-19 19:15:48 -070084import static org.opencord.cordvtn.api.dependency.Dependency.Type.BIDIRECTIONAL;
85import static org.opencord.cordvtn.api.net.ServiceNetwork.ServiceNetworkType.ACCESS_AGENT;
alshabibb4d31712016-06-01 18:51:03 -070086import static org.opencord.cordvtn.impl.CordVtnPipeline.*;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070087import static org.onosproject.net.group.DefaultGroupBucket.createSelectGroupBucket;
Hyunsun Moone9d75992015-09-15 22:39:16 -070088import static org.slf4j.LoggerFactory.getLogger;
89
90/**
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070091 * Provisions service dependency capabilities between network services.
Hyunsun Moone9d75992015-09-15 22:39:16 -070092 */
93@Component(immediate = true)
94@Service
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070095public class DependencyManager extends AbstractInstanceHandler implements DependencyService {
Hyunsun Moone9d75992015-09-15 22:39:16 -070096
97 protected final Logger log = getLogger(getClass());
98
Hyunsun Mooneaf75e62016-09-27 16:40:23 -070099 private static final String ERR_NET_FAIL = "Failed to get VTN network ";
100 private static final String MSG_CREATE = "Created dependency %s";
101 private static final String MSG_REMOVE = "Removed dependency %s";
102 private static final String ADDED = "Added ";
103 private static final String REMOVED = "Removed ";
104
105 private static final KryoNamespace SERIALIZER_DEPENDENCY = KryoNamespace.newBuilder()
106 .register(KryoNamespaces.API)
107 .register(VtnNetwork.class)
108 .register(NetworkId.class)
109 .register(SegmentId.class)
110 .register(ServiceNetworkType.class)
111 .register(ProviderNetwork.class)
112 .register(Dependency.class)
113 .register(Type.class)
114 .build();
115
Hyunsun Moone9d75992015-09-15 22:39:16 -0700116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonba290072015-12-16 20:53:23 -0800117 protected GroupService groupService;
118
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700120 protected LeadershipService leadershipService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected ClusterService clusterService;
124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
126 protected StorageService storageService;
127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700129 protected CordVtnPipeline pipeline;
130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
132 protected CordVtnNodeManager nodeManager;
133
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
135 protected CordVtnAdminService vtnService;
136
137 private final VtnNetworkListener vtnNetListener = new InternalVtnNetListener();
138 private final MapEventListener<NetworkId, Set<Dependency>> dependencyListener =
139 new DependencyMapListener();
140
141 private ConsistentMap<NetworkId, Set<Dependency>> dependencyStore;
142 private NodeId localNodeId;
143
Hyunsun Moone9d75992015-09-15 22:39:16 -0700144 @Activate
145 protected void activate() {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700146 super.activate();
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700147
148 dependencyStore = storageService.<NetworkId, Set<Dependency>>consistentMapBuilder()
149 .withSerializer(Serializer.using(SERIALIZER_DEPENDENCY))
150 .withName("cordvtn-dependencymap")
151 .withApplicationId(appId)
152 .build();
153 dependencyStore.addListener(dependencyListener);
154
155 localNodeId = clusterService.getLocalNode().id();
156 leadershipService.runForLeadership(appId.name());
157 vtnService.addListener(vtnNetListener);
Hyunsun Moone9d75992015-09-15 22:39:16 -0700158 }
159
160 @Deactivate
161 protected void deactivate() {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700162 super.deactivate();
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700163 dependencyStore.removeListener(dependencyListener);
164 vtnService.removeListener(vtnNetListener);
165 leadershipService.withdraw(appId.name());
Hyunsun Moonde372572016-01-14 03:42:47 -0800166 }
167
168 @Override
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700169 public void createDependency(NetworkId subNetId, NetworkId proNetId, Type type) {
170 // FIXME this is not safe
Hyunsun Moon5c143952016-10-19 18:34:46 -0700171 VtnNetwork existing = vtnService.vtnNetwork(subNetId);
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700172 if (existing == null) {
173 log.warn("Failed to create dependency between {} and {}", subNetId, proNetId);
Hyunsun Moonba290072015-12-16 20:53:23 -0800174 return;
175 }
Hyunsun Moon5c143952016-10-19 18:34:46 -0700176 vtnService.createServiceNetwork(existing);
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700177 VtnNetwork updated = VtnNetwork.builder(existing)
178 .addProvider(proNetId, type)
179 .build();
Hyunsun Moon5c143952016-10-19 18:34:46 -0700180 vtnService.updateServiceNetwork(updated);
Hyunsun Moon9274aaf2015-12-04 11:35:25 -0800181 }
182
183 @Override
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700184 public void removeDependency(NetworkId subNetId, NetworkId proNetId) {
185 // FIXME this is not safe
Hyunsun Moon5c143952016-10-19 18:34:46 -0700186 VtnNetwork subNet = vtnService.vtnNetwork(subNetId);
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700187 if (subNet == null) {
188 log.warn("No dependency exists between {} and {}", subNetId, proNetId);
Hyunsun Moonba290072015-12-16 20:53:23 -0800189 return;
190 }
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700191 VtnNetwork updated = VtnNetwork.builder(subNet)
192 .delProvider(proNetId)
193 .build();
Hyunsun Moon5c143952016-10-19 18:34:46 -0700194 vtnService.updateServiceNetwork(updated);
Hyunsun Moon9274aaf2015-12-04 11:35:25 -0800195 }
196
Hyunsun Mooncb799442016-01-15 20:03:18 -0800197 @Override
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700198 public void instanceDetected(Instance instance) {
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700199 // TODO remove this when XOS provides access agent information
200 // and handle it the same way wit the other instances
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700201 if (instance.netType() == ACCESS_AGENT) {
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700202 return;
203 }
204
Hyunsun Moon5c143952016-10-19 18:34:46 -0700205 VtnNetwork vtnNet = vtnService.vtnNetwork(instance.netId());
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700206 if (vtnNet == null) {
207 final String error = ERR_NET_FAIL + instance.netId();
208 throw new IllegalStateException(error);
Hyunsun Moon4edb0172015-11-07 22:08:43 -0800209 }
210
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700211 if (!vtnNet.providers().isEmpty()) {
212 updateSubscriberInstances(vtnNet, instance, true);
213 }
214 // TODO check if subscribers on this network
215 updateProviderInstances(vtnNet);
Hyunsun Moon4edb0172015-11-07 22:08:43 -0800216 }
217
Hyunsun Mooncb799442016-01-15 20:03:18 -0800218 @Override
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700219 public void instanceRemoved(Instance instance) {
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700220 // TODO remove this when XOS provides access agent information
221 // and handle it the same way wit the other instances
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700222 if (instance.netType() == ACCESS_AGENT) {
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700223 return;
224 }
225
Hyunsun Moon5c143952016-10-19 18:34:46 -0700226 VtnNetwork vtnNet = vtnService.vtnNetwork(instance.netId());
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700227 if (vtnNet == null) {
228 final String error = ERR_NET_FAIL + instance.netId();
229 throw new IllegalStateException(error);
Hyunsun Moon01556a52016-02-12 12:48:47 -0800230 }
231
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700232 if (!vtnNet.providers().isEmpty()) {
233 updateSubscriberInstances(vtnNet, instance, false);
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800234 }
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700235 // TODO check if subscribers on this network
236 updateProviderInstances(vtnNet);
Hyunsun Moon01556a52016-02-12 12:48:47 -0800237 }
238
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700239 private void dependencyCreated(Dependency dependency) {
240 populateDependencyRules(dependency.subscriber(), dependency.provider(),
241 dependency.type(), true);
242 log.info(String.format(MSG_CREATE, dependency));
243 }
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700244
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700245 private void dependencyRemoved(Dependency dependency) {
246 populateDependencyRules(dependency.subscriber(), dependency.provider(),
247 dependency.type(), false);
Hyunsun Moonfe31dd42016-09-30 11:34:22 -0700248 if (getSubscribers(dependency.provider().id()).isEmpty()) {
249 removeProviderGroup(dependency.provider().id());
250 }
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700251 log.info(String.format(MSG_REMOVE, dependency));
252 }
253
254 private void updateProviderInstances(VtnNetwork provider) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700255 Set<DeviceId> devices = nodeManager.completeNodes().stream()
Hyunsun Moon81a13562016-08-04 13:48:08 -0700256 .map(CordVtnNode::integrationBridgeId)
Hyunsun Mooncb799442016-01-15 20:03:18 -0800257 .collect(Collectors.toSet());
Hyunsun Moon01556a52016-02-12 12:48:47 -0800258
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700259 GroupKey groupKey = getGroupKey(provider.id());
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700260 for (DeviceId deviceId : devices) {
261 Group group = groupService.getGroup(deviceId, groupKey);
262 if (group == null) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700263 continue;
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800264 }
265
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700266 List<GroupBucket> oldBuckets = group.buckets().buckets();
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700267 List<GroupBucket> newBuckets = getProviderGroupBuckets(
268 deviceId,
269 provider.segmentId().id(),
270 getInstances(provider.id())).buckets();
Hyunsun Moon7004fcf2016-03-08 04:36:02 -0800271
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700272 if (oldBuckets.equals(newBuckets)) {
273 continue;
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800274 }
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700275
276 List<GroupBucket> bucketsToRemove = Lists.newArrayList(oldBuckets);
277 bucketsToRemove.removeAll(newBuckets);
278 if (!bucketsToRemove.isEmpty()) {
279 groupService.removeBucketsFromGroup(
280 deviceId,
281 groupKey,
282 new GroupBuckets(bucketsToRemove),
283 groupKey, appId);
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700284 log.debug("Removed buckets from provider({}) group on {}: {}",
285 provider.id(), deviceId, bucketsToRemove);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700286 }
287
288 List<GroupBucket> bucketsToAdd = Lists.newArrayList(newBuckets);
289 bucketsToAdd.removeAll(oldBuckets);
290 if (!bucketsToAdd.isEmpty()) {
291 groupService.addBucketsToGroup(
292 deviceId,
293 groupKey,
294 new GroupBuckets(bucketsToAdd),
295 groupKey, appId);
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700296 log.debug("Added buckets to provider({}) group on {}: {}",
297 provider.id(), deviceId, bucketsToAdd);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700298 }
299 }
300 }
301
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700302 private void updateSubscriberInstances(VtnNetwork subscriber, Instance instance,
303 boolean isDetected) {
304 DeviceId deviceId = instance.deviceId();
305 final String isAdded = isDetected ? ADDED : REMOVED;
306 subscriber.providers().stream().forEach(provider -> {
307 populateInPortRule(
308 ImmutableMap.of(deviceId, ImmutableSet.of(instance.portNumber())),
309 ImmutableMap.of(deviceId, getGroupId(provider.id(), deviceId)),
310 isDetected);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700311
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700312 log.info(isAdded + "subscriber instance({}) for provider({})",
313 instance.host().id(), provider.id());
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800314 });
315 }
316
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700317 private void populateDependencyRules(VtnNetwork subscriber,
318 VtnNetwork provider,
319 Type type, boolean install) {
320 Map<DeviceId, GroupId> providerGroups = Maps.newHashMap();
321 Map<DeviceId, Set<PortNumber>> subscriberPorts = Maps.newHashMap();
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700322
323 nodeManager.completeNodes().stream().forEach(node -> {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700324 DeviceId deviceId = node.integrationBridgeId();
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700325 GroupId groupId = getProviderGroup(provider, deviceId);
326 providerGroups.put(deviceId, groupId);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700327
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700328 Set<PortNumber> ports = getInstances(subscriber.id())
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700329 .stream()
330 .filter(instance -> instance.deviceId().equals(deviceId))
331 .map(Instance::portNumber)
332 .collect(Collectors.toSet());
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700333 subscriberPorts.put(deviceId, ports);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700334 });
335
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700336 Ip4Prefix subscriberIp = subscriber.subnet().getIp4Prefix();
337 Ip4Prefix providerIp = provider.subnet().getIp4Prefix();
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700338
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700339 populateInPortRule(subscriberPorts, providerGroups, install);
340 populateIndirectAccessRule(
341 subscriberIp,
342 provider.serviceIp().getIp4Address(),
343 providerGroups,
344 install);
345 populateDirectAccessRule(subscriberIp, providerIp, install);
346 if (type == BIDIRECTIONAL) {
347 populateDirectAccessRule(providerIp, subscriberIp, install);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700348 }
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800349 }
350
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700351 private void populateIndirectAccessRule(Ip4Prefix srcIp, Ip4Address serviceIp,
352 Map<DeviceId, GroupId> outGroups,
353 boolean install) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700354 TrafficSelector selector = DefaultTrafficSelector.builder()
355 .matchEthType(Ethernet.TYPE_IPV4)
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700356 .matchIPSrc(srcIp)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700357 .matchIPDst(serviceIp.toIpPrefix())
358 .build();
359
360 for (Map.Entry<DeviceId, GroupId> outGroup : outGroups.entrySet()) {
361 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
362 .group(outGroup.getValue())
363 .build();
364
365 FlowRule flowRule = DefaultFlowRule.builder()
366 .fromApp(appId)
367 .withSelector(selector)
368 .withTreatment(treatment)
369 .withPriority(PRIORITY_HIGH)
370 .forDevice(outGroup.getKey())
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700371 .forTable(TABLE_ACCESS)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700372 .makePermanent()
373 .build();
374
375 pipeline.processFlowRule(install, flowRule);
376 }
377 }
378
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700379 private void populateDirectAccessRule(Ip4Prefix srcIp, Ip4Prefix dstIp, boolean install) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700380 TrafficSelector selector = DefaultTrafficSelector.builder()
381 .matchEthType(Ethernet.TYPE_IPV4)
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700382 .matchIPSrc(srcIp)
383 .matchIPDst(dstIp)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700384 .build();
385
386 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700387 .transition(TABLE_DST)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700388 .build();
389
390 nodeManager.completeNodes().stream().forEach(node -> {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700391 DeviceId deviceId = node.integrationBridgeId();
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700392 FlowRule flowRuleDirect = DefaultFlowRule.builder()
393 .fromApp(appId)
394 .withSelector(selector)
395 .withTreatment(treatment)
396 .withPriority(PRIORITY_DEFAULT)
397 .forDevice(deviceId)
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700398 .forTable(TABLE_ACCESS)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700399 .makePermanent()
400 .build();
401
402 pipeline.processFlowRule(install, flowRuleDirect);
403 });
404 }
405
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700406 private void populateInPortRule(Map<DeviceId, Set<PortNumber>> subscriberPorts,
407 Map<DeviceId, GroupId> providerGroups,
408 boolean install) {
409 for (Map.Entry<DeviceId, Set<PortNumber>> entry : subscriberPorts.entrySet()) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700410 Set<PortNumber> ports = entry.getValue();
411 DeviceId deviceId = entry.getKey();
412
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700413 GroupId groupId = providerGroups.get(deviceId);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700414 if (groupId == null) {
415 continue;
416 }
417
418 ports.stream().forEach(port -> {
419 TrafficSelector selector = DefaultTrafficSelector.builder()
420 .matchInPort(port)
421 .build();
422
423 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
424 .group(groupId)
425 .build();
426
427 FlowRule flowRule = DefaultFlowRule.builder()
428 .fromApp(appId)
429 .withSelector(selector)
430 .withTreatment(treatment)
431 .withPriority(PRIORITY_DEFAULT)
432 .forDevice(deviceId)
433 .forTable(TABLE_IN_SERVICE)
434 .makePermanent()
435 .build();
436
437 pipeline.processFlowRule(install, flowRule);
438 });
439 }
440 }
441
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700442 private GroupId getGroupId(NetworkId netId, DeviceId deviceId) {
443 return new DefaultGroupId(Objects.hash(netId, deviceId));
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700444 }
445
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700446 private GroupKey getGroupKey(NetworkId netId) {
447 return new DefaultGroupKey(netId.id().getBytes());
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700448 }
449
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700450 private GroupId getProviderGroup(VtnNetwork provider, DeviceId deviceId) {
451 GroupKey groupKey = getGroupKey(provider.id());
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700452 Group group = groupService.getGroup(deviceId, groupKey);
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700453 GroupId groupId = getGroupId(provider.id(), deviceId);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700454
455 if (group != null) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700456 return groupId;
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800457 }
458
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700459 GroupBuckets buckets = getProviderGroupBuckets(
460 deviceId, provider.segmentId().id(), getInstances(provider.id()));
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700461 GroupDescription groupDescription = new DefaultGroupDescription(
462 deviceId,
463 GroupDescription.Type.SELECT,
464 buckets,
465 groupKey,
466 groupId.id(),
467 appId);
Hyunsun Moon486ed1b2016-05-13 18:58:35 -0700468
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700469 groupService.addGroup(groupDescription);
470 return groupId;
471 }
472
Hyunsun Moonfe31dd42016-09-30 11:34:22 -0700473 private Set<Dependency> getSubscribers(NetworkId netId) {
474 return dependencyStore.values().stream().map(Versioned::value)
475 .flatMap(Collection::stream)
476 .filter(dependency -> dependency.provider().id().equals(netId))
477 .collect(Collectors.toSet());
478 }
479
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700480 private void removeProviderGroup(NetworkId netId) {
481 GroupKey groupKey = getGroupKey(netId);
482 nodeManager.completeNodes().stream()
483 .forEach(node -> {
484 DeviceId deviceId = node.integrationBridgeId();
485 Group group = groupService.getGroup(deviceId, groupKey);
486 if (group != null) {
487 groupService.removeGroup(deviceId, groupKey, appId);
488 }
489 });
490 log.debug("Removed group for network {}", netId);
491 }
492
493 private GroupBuckets getProviderGroupBuckets(DeviceId deviceId,
494 long tunnelId,
495 Set<Instance> instances) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700496 List<GroupBucket> buckets = Lists.newArrayList();
497 instances.stream().forEach(instance -> {
Hyunsun Moon81a13562016-08-04 13:48:08 -0700498 Ip4Address tunnelIp = nodeManager.dataIp(instance.deviceId()).getIp4Address();
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700499
500 if (deviceId.equals(instance.deviceId())) {
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700501 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
502 .setEthDst(instance.mac())
503 .setOutput(instance.portNumber())
504 .build();
505 buckets.add(createSelectGroupBucket(treatment));
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700506 } else {
507 ExtensionTreatment tunnelDst =
508 pipeline.tunnelDstTreatment(deviceId, tunnelIp);
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700509 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
510 .setEthDst(instance.mac())
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700511 .extension(tunnelDst, deviceId)
512 .setTunnelId(tunnelId)
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700513 .setOutput(nodeManager.tunnelPort(instance.deviceId()))
514 .build();
515 buckets.add(createSelectGroupBucket(treatment));
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700516 }
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700517 });
518 return new GroupBuckets(buckets);
Hyunsun Moon61e79ee2016-04-14 19:04:23 -0700519 }
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700520
521 private class InternalVtnNetListener implements VtnNetworkListener {
522
523 @Override
524 public void event(VtnNetworkEvent event) {
525 NodeId leader = leadershipService.getLeader(appId.name());
526 if (!Objects.equals(localNodeId, leader)) {
527 // do not allow to proceed without leadership
528 return;
529 }
530
531 switch (event.type()) {
532 case VTN_NETWORK_CREATED:
533 case VTN_NETWORK_UPDATED:
534 log.debug("Processing dependency for {}", event.subject());
535 eventExecutor.execute(() -> updateDependency(event.subject()));
536 break;
537 case VTN_NETWORK_REMOVED:
538 log.debug("Removing dependency for {}", event.subject());
539 NetworkId netId = event.subject().id();
540 eventExecutor.execute(() -> dependencyStore.remove(netId));
541 break;
542 case VTN_PORT_CREATED:
543 case VTN_PORT_UPDATED:
544 case VTN_PORT_REMOVED:
545 default:
546 // do nothing for the other events
547 break;
548 }
549 }
550
551 private void updateDependency(VtnNetwork subscriber) {
552 Set<Dependency> dependencies = subscriber.providers().stream()
553 .map(provider -> Dependency.builder()
554 .subscriber(subscriber)
Hyunsun Moon5c143952016-10-19 18:34:46 -0700555 .provider(vtnService.vtnNetwork(provider.id()))
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700556 .type(provider.type())
557 .build())
558 .collect(Collectors.toSet());
559 dependencyStore.put(subscriber.id(), dependencies);
560 }
561 }
562
563 private class DependencyMapListener implements MapEventListener<NetworkId, Set<Dependency>> {
564
565 @Override
566 public void event(MapEvent<NetworkId, Set<Dependency>> event) {
567 NodeId leader = leadershipService.getLeader(appId.name());
568 if (!Objects.equals(localNodeId, leader)) {
569 // do not allow to proceed without leadership
570 return;
571 }
572
573 switch (event.type()) {
574 case UPDATE:
575 log.debug("Subscriber {} updated", event.key());
576 eventExecutor.execute(() -> dependencyUpdated(
577 event.oldValue().value(),
578 event.newValue().value()
579 ));
580 break;
581 case INSERT:
582 log.debug("Subscriber {} inserted", event.key());
583 eventExecutor.execute(() -> dependencyUpdated(
584 ImmutableSet.of(),
585 event.newValue().value()
586 ));
587 break;
588 case REMOVE:
589 log.debug("Subscriber {} removed", event.key());
590 eventExecutor.execute(() -> dependencyUpdated(
591 event.oldValue().value(),
592 ImmutableSet.of()
593 ));
594 break;
595 default:
596 log.error("Unsupported event type");
597 break;
598 }
599 }
600
601 private void dependencyUpdated(Set<Dependency> oldDeps, Set<Dependency> newDeps) {
602 oldDeps.stream().filter(oldDep -> !newDeps.contains(oldDep))
603 .forEach(DependencyManager.this::dependencyRemoved);
604
605 newDeps.stream().filter(newDep -> !oldDeps.contains(newDep))
606 .forEach(DependencyManager.this::dependencyCreated);
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700607 }
608 }
Hyunsun Moone9d75992015-09-15 22:39:16 -0700609}