blob: 0e491490829dce5a3601222e60647106888be76a [file] [log] [blame]
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +09001/*
2 * Copyright 2016-present 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 */
16
Hyunsun Moon71701292016-05-09 12:00:54 -070017package org.onosproject.scalablegateway.impl;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +090018
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -070019import com.google.common.collect.ImmutableList;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090020import com.google.common.collect.Lists;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090024import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.felix.scr.annotations.Service;
Kyuhwi Choi70537882016-06-24 17:24:12 +090027import org.onlab.util.KryoNamespace;
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -070028import org.onlab.util.Tools;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090029import org.onosproject.core.ApplicationId;
30import org.onosproject.core.CoreService;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +090031import org.onosproject.core.GroupId;
32import org.onosproject.net.DeviceId;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090033import org.onosproject.net.Port;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +090034import org.onosproject.net.PortNumber;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090035import org.onosproject.net.config.ConfigFactory;
36import org.onosproject.net.config.NetworkConfigEvent;
37import org.onosproject.net.config.NetworkConfigListener;
38import org.onosproject.net.config.NetworkConfigRegistry;
39import org.onosproject.net.config.NetworkConfigService;
40import org.onosproject.net.config.basics.SubjectFactories;
Kyuhwi Choi70537882016-06-24 17:24:12 +090041import org.onosproject.net.device.DeviceEvent;
42import org.onosproject.net.device.DeviceListener;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090043import org.onosproject.net.device.DeviceService;
Kyuhwi Choib0718212016-06-01 11:33:27 +090044import org.onosproject.net.driver.DriverService;
45import org.onosproject.net.group.Group;
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -070046import org.onosproject.net.group.GroupKey;
Kyuhwi Choib0718212016-06-01 11:33:27 +090047import org.onosproject.net.group.GroupService;
Hyunsun Moon71701292016-05-09 12:00:54 -070048import org.onosproject.scalablegateway.api.GatewayNode;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090049import org.onosproject.scalablegateway.api.GatewayNodeConfig;
Hyunsun Moon71701292016-05-09 12:00:54 -070050import org.onosproject.scalablegateway.api.ScalableGatewayService;
Kyuhwi Choi70537882016-06-24 17:24:12 +090051import org.onosproject.store.serializers.KryoNamespaces;
52import org.onosproject.store.service.ConsistentMap;
53import org.onosproject.store.service.Serializer;
54import org.onosproject.store.service.StorageService;
55import org.onosproject.store.service.Versioned;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090056import org.slf4j.Logger;
57import org.slf4j.LoggerFactory;
58
sangho09a6ffe2016-08-23 16:55:38 +090059import java.util.List;
60import java.util.Objects;
61import java.util.Optional;
62
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -070063import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +090064
65/**
66 * Manages gateway node for gateway scalability.
67 */
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090068
69@Service
70@Component(immediate = true)
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +090071public class ScalableGatewayManager implements ScalableGatewayService {
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090072 private final Logger log = LoggerFactory.getLogger(getClass());
73
74 private ApplicationId appId;
75 private static final String APP_ID = "org.onosproject.scalablegateway";
76 private static final String APP_NAME = "scalablegateway";
Kyuhwi Choi70537882016-06-24 17:24:12 +090077 private static final String GATEWAYNODE_MAP_NAME = "gatewaynode-map";
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090078
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected CoreService coreService;
81
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected NetworkConfigService configService;
84
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected NetworkConfigRegistry configRegistry;
87
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 protected DeviceService deviceService;
90
Kyuhwi Choib0718212016-06-01 11:33:27 +090091 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected DriverService driverService;
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected GroupService groupService;
96
Kyuhwi Choi70537882016-06-24 17:24:12 +090097 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected StorageService storageService;
99
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900100 private GatewayNodeConfig config;
Kyuhwi Choib0718212016-06-01 11:33:27 +0900101 private SelectGroupHandler selectGroupHandler;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900102
103 private final NetworkConfigListener configListener = new InternalConfigListener();
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700104 private final InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900105
106 private final ConfigFactory configFactory =
107 new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, GatewayNodeConfig.class, APP_NAME) {
108 @Override
109 public GatewayNodeConfig createConfig() {
110 return new GatewayNodeConfig();
111 }
112 };
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700113
114 private ConsistentMap<DeviceId, GatewayNode> gatewayNodeMap; // Map<GatewayNode Id, GatewayNode object>
Kyuhwi Choi70537882016-06-24 17:24:12 +0900115 private static final KryoNamespace.Builder GATEWAYNODE_SERIALIZER = KryoNamespace.newBuilder()
116 .register(KryoNamespaces.API)
Kyuhwi Choi70537882016-06-24 17:24:12 +0900117 .register(GatewayNode.class);
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900118
119 @Activate
120 protected void activate() {
121 appId = coreService.registerApplication(APP_ID);
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900122
Kyuhwi Choi70537882016-06-24 17:24:12 +0900123 gatewayNodeMap = storageService.<DeviceId, GatewayNode>consistentMapBuilder()
124 .withSerializer(Serializer.using(GATEWAYNODE_SERIALIZER.build()))
125 .withName(GATEWAYNODE_MAP_NAME)
126 .withApplicationId(appId)
127 .build();
128
Daniel Parkd4d88012016-08-05 08:56:53 +0900129 configRegistry.registerConfigFactory(configFactory);
130 configService.addListener(configListener);
131 deviceService.addListener(internalDeviceListener);
132
133 selectGroupHandler = new SelectGroupHandler(groupService, deviceService, driverService, appId);
134
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900135 log.info("started");
136 }
137
138 @Deactivate
139 protected void deactivate() {
Kyuhwi Choi70537882016-06-24 17:24:12 +0900140 deviceService.removeListener(internalDeviceListener);
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900141 configService.removeListener(configListener);
142
143 log.info("stopped");
144 }
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900145
146 @Override
147 public GatewayNode getGatewayNode(DeviceId deviceId) {
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700148 GatewayNode gatewayNode = gatewayNodeMap.get(deviceId).value();
149 if (gatewayNode == null) {
150 log.warn("Gateway with device ID {} does not exist");
151 return null;
152 }
153 return gatewayNode;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900154 }
155
156 @Override
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700157 public PortNumber getUplinkPort(DeviceId deviceId) {
158 GatewayNode gatewayNode = gatewayNodeMap.get(deviceId).value();
159 if (gatewayNode == null) {
160 log.warn("Gateway with device ID {} does not exist");
sangho6032f342016-07-07 14:32:03 +0900161 return null;
162 }
163
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700164 Optional<Port> port = deviceService.getPorts(deviceId).stream()
165 .filter(p -> Objects.equals(
166 p.annotations().value(PORT_NAME),
167 gatewayNode.getUplinkIntf()))
168 .findFirst();
169 if (!port.isPresent()) {
170 log.warn("Cannot find uplink interface from gateway {}", deviceId);
171 return null;
172 }
sangho6032f342016-07-07 14:32:03 +0900173 return port.get().number();
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900174 }
175
176 @Override
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700177 public synchronized GroupId getGatewayGroupId(DeviceId srcDeviceId) {
178 GroupKey groupKey = selectGroupHandler.getGroupKey(srcDeviceId);
179 Group group = groupService.getGroup(srcDeviceId, groupKey);
180 if (group == null) {
181 log.info("Created gateway group for {}", srcDeviceId);
182 return selectGroupHandler.createGatewayGroup(srcDeviceId, getGatewayNodes());
183 } else {
184 return group.id();
185 }
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900186 }
187
188 @Override
189 public List<GatewayNode> getGatewayNodes() {
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900190 List<GatewayNode> gatewayNodeList = Lists.newArrayList();
191 gatewayNodeMap.values()
192 .stream()
Kyuhwi Choi70537882016-06-24 17:24:12 +0900193 .map(Versioned::value)
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700194 .forEach(gatewayNodeList::add);
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900195 return gatewayNodeList;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900196 }
197
198 @Override
199 public List<DeviceId> getGatewayDeviceIds() {
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900200 List<DeviceId> deviceIdList = Lists.newArrayList();
201 gatewayNodeMap.values()
202 .stream()
Kyuhwi Choi70537882016-06-24 17:24:12 +0900203 .map(Versioned::value)
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900204 .forEach(gatewayNode -> deviceIdList.add(gatewayNode.getGatewayDeviceId()));
205 return deviceIdList;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900206 }
207
208 @Override
Hyunsun Moon5aa480b2016-08-03 12:23:14 -0700209 public synchronized boolean addGatewayNode(GatewayNode gatewayNode) {
sangho09a6ffe2016-08-23 16:55:38 +0900210 Versioned<GatewayNode> existingNode = gatewayNodeMap.put(gatewayNode.getGatewayDeviceId(),
211 gatewayNode);
Hyunsun Moond331afd2016-07-20 02:19:20 -0700212 if (existingNode == null) {
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700213 updateGatewayGroup(gatewayNode, true);
sangho09a6ffe2016-08-23 16:55:38 +0900214 log.info("Gateway {} is added to Gateway pool", gatewayNode);
215 return true;
216 } else if (!existingNode.value().equals(gatewayNode)) {
217 updateGatewayGroup(existingNode.value(), false);
218 updateGatewayGroup(gatewayNode, true);
219 log.info("Gateway {} is updated", gatewayNode);
Hyunsun Moond331afd2016-07-20 02:19:20 -0700220 return true;
221 } else {
222 return false;
223 }
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900224 }
225
226 @Override
Hyunsun Moon5aa480b2016-08-03 12:23:14 -0700227 public synchronized boolean deleteGatewayNode(GatewayNode gatewayNode) {
Kyuhwi Choi70537882016-06-24 17:24:12 +0900228 boolean result = gatewayNodeMap.remove(gatewayNode.getGatewayDeviceId(), gatewayNode);
229 if (result) {
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700230 updateGatewayGroup(gatewayNode, false);
231 log.info("Deleted gateway with device ID {}", gatewayNode.getGatewayDeviceId());
Kyuhwi Choi70537882016-06-24 17:24:12 +0900232 }
233 return result;
234 }
235
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700236 private void updateGatewayGroup(GatewayNode gatewayNode, boolean isInsert) {
237 Tools.stream(deviceService.getAvailableDevices()).forEach(device -> {
238 Tools.stream(groupService.getGroups(device.id(), appId)).forEach(group -> {
239 selectGroupHandler.updateGatewayGroupBuckets(
240 device.id(),
241 ImmutableList.of(gatewayNode),
242 isInsert);
243 log.trace("Updated gateway group on {}", device.id());
244 });
245 });
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900246 }
247
248 private class InternalConfigListener implements NetworkConfigListener {
249 @Override
250 public void event(NetworkConfigEvent event) {
251 if (!event.configClass().equals(GatewayNodeConfig.class)) {
252 return;
253 }
254 switch (event.type()) {
255 case CONFIG_UPDATED:
256 gatewayNodeMap.clear();
257 readConfiguration();
258 break;
259 case CONFIG_ADDED:
260 readConfiguration();
261 break;
262 default:
263 log.debug("Unsupportable event type is occurred");
264 break;
265 }
266 }
267 }
268
Kyuhwi Choi70537882016-06-24 17:24:12 +0900269 private class InternalDeviceListener implements DeviceListener {
270
271 @Override
272 public void event(DeviceEvent deviceEvent) {
273 if (deviceEvent.type() == DeviceEvent.Type.DEVICE_SUSPENDED ||
274 deviceEvent.type() == DeviceEvent.Type.DEVICE_REMOVED) {
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700275 DeviceId deviceId = deviceEvent.subject().id();
276 deleteGatewayNode(getGatewayNode(deviceId));
277 log.warn("Gateway with device ID {} is disconnected", deviceId);
Kyuhwi Choi70537882016-06-24 17:24:12 +0900278 }
279 }
280 }
281
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900282 private void readConfiguration() {
283 config = configService.getConfig(appId, GatewayNodeConfig.class);
284 if (config == null) {
285 log.error("No configuration found");
286 return;
287 }
288
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700289 config.gatewayNodes().forEach(this::addGatewayNode);
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900290 log.info("ScalableGateway configured");
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900291 }
292}