blob: 80b4f45218bb48524ee687814f6158260815d86b [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;
24
25import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
27import org.apache.felix.scr.annotations.Service;
Kyuhwi Choi70537882016-06-24 17:24:12 +090028import org.onlab.util.KryoNamespace;
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -070029import org.onlab.util.Tools;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090030import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
32
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +090033import org.onosproject.core.GroupId;
34import org.onosproject.net.DeviceId;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090035import org.onosproject.net.Port;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +090036import org.onosproject.net.PortNumber;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090037import org.onosproject.net.config.ConfigFactory;
38import org.onosproject.net.config.NetworkConfigEvent;
39import org.onosproject.net.config.NetworkConfigListener;
40import org.onosproject.net.config.NetworkConfigRegistry;
41import org.onosproject.net.config.NetworkConfigService;
42import org.onosproject.net.config.basics.SubjectFactories;
Kyuhwi Choi70537882016-06-24 17:24:12 +090043import org.onosproject.net.device.DeviceEvent;
44import org.onosproject.net.device.DeviceListener;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090045import org.onosproject.net.device.DeviceService;
Kyuhwi Choib0718212016-06-01 11:33:27 +090046import org.onosproject.net.driver.DriverService;
47import org.onosproject.net.group.Group;
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -070048import org.onosproject.net.group.GroupKey;
Kyuhwi Choib0718212016-06-01 11:33:27 +090049import org.onosproject.net.group.GroupService;
Hyunsun Moon71701292016-05-09 12:00:54 -070050import org.onosproject.scalablegateway.api.GatewayNode;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090051import org.onosproject.scalablegateway.api.GatewayNodeConfig;
Hyunsun Moon71701292016-05-09 12:00:54 -070052import org.onosproject.scalablegateway.api.ScalableGatewayService;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +090053
54import java.util.List;
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -070055import java.util.Objects;
sangho6032f342016-07-07 14:32:03 +090056import java.util.Optional;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090057
Kyuhwi Choi70537882016-06-24 17:24:12 +090058import org.onosproject.store.serializers.KryoNamespaces;
59import org.onosproject.store.service.ConsistentMap;
60import org.onosproject.store.service.Serializer;
61import org.onosproject.store.service.StorageService;
62import org.onosproject.store.service.Versioned;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090063import org.slf4j.Logger;
64import org.slf4j.LoggerFactory;
65
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -070066import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +090067
68/**
69 * Manages gateway node for gateway scalability.
70 */
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090071
72@Service
73@Component(immediate = true)
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +090074public class ScalableGatewayManager implements ScalableGatewayService {
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090075 private final Logger log = LoggerFactory.getLogger(getClass());
76
77 private ApplicationId appId;
78 private static final String APP_ID = "org.onosproject.scalablegateway";
79 private static final String APP_NAME = "scalablegateway";
Kyuhwi Choi70537882016-06-24 17:24:12 +090080 private static final String GATEWAYNODE_MAP_NAME = "gatewaynode-map";
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090081
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected CoreService coreService;
84
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected NetworkConfigService configService;
87
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 protected NetworkConfigRegistry configRegistry;
90
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected DeviceService deviceService;
93
Kyuhwi Choib0718212016-06-01 11:33:27 +090094 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected DriverService driverService;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected GroupService groupService;
99
Kyuhwi Choi70537882016-06-24 17:24:12 +0900100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected StorageService storageService;
102
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900103 private GatewayNodeConfig config;
Kyuhwi Choib0718212016-06-01 11:33:27 +0900104 private SelectGroupHandler selectGroupHandler;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900105
106 private final NetworkConfigListener configListener = new InternalConfigListener();
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700107 private final InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900108
109 private final ConfigFactory configFactory =
110 new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, GatewayNodeConfig.class, APP_NAME) {
111 @Override
112 public GatewayNodeConfig createConfig() {
113 return new GatewayNodeConfig();
114 }
115 };
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700116
117 private ConsistentMap<DeviceId, GatewayNode> gatewayNodeMap; // Map<GatewayNode Id, GatewayNode object>
Kyuhwi Choi70537882016-06-24 17:24:12 +0900118 private static final KryoNamespace.Builder GATEWAYNODE_SERIALIZER = KryoNamespace.newBuilder()
119 .register(KryoNamespaces.API)
Kyuhwi Choi70537882016-06-24 17:24:12 +0900120 .register(GatewayNode.class);
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900121
122 @Activate
123 protected void activate() {
124 appId = coreService.registerApplication(APP_ID);
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900125
Kyuhwi Choi70537882016-06-24 17:24:12 +0900126 gatewayNodeMap = storageService.<DeviceId, GatewayNode>consistentMapBuilder()
127 .withSerializer(Serializer.using(GATEWAYNODE_SERIALIZER.build()))
128 .withName(GATEWAYNODE_MAP_NAME)
129 .withApplicationId(appId)
130 .build();
131
Daniel Parkd4d88012016-08-05 08:56:53 +0900132 configRegistry.registerConfigFactory(configFactory);
133 configService.addListener(configListener);
134 deviceService.addListener(internalDeviceListener);
135
136 selectGroupHandler = new SelectGroupHandler(groupService, deviceService, driverService, appId);
137
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900138 log.info("started");
139 }
140
141 @Deactivate
142 protected void deactivate() {
Kyuhwi Choi70537882016-06-24 17:24:12 +0900143 deviceService.removeListener(internalDeviceListener);
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900144 configService.removeListener(configListener);
145
146 log.info("stopped");
147 }
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900148
149 @Override
150 public GatewayNode getGatewayNode(DeviceId deviceId) {
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700151 GatewayNode gatewayNode = gatewayNodeMap.get(deviceId).value();
152 if (gatewayNode == null) {
153 log.warn("Gateway with device ID {} does not exist");
154 return null;
155 }
156 return gatewayNode;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900157 }
158
159 @Override
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700160 public PortNumber getUplinkPort(DeviceId deviceId) {
161 GatewayNode gatewayNode = gatewayNodeMap.get(deviceId).value();
162 if (gatewayNode == null) {
163 log.warn("Gateway with device ID {} does not exist");
sangho6032f342016-07-07 14:32:03 +0900164 return null;
165 }
166
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700167 Optional<Port> port = deviceService.getPorts(deviceId).stream()
168 .filter(p -> Objects.equals(
169 p.annotations().value(PORT_NAME),
170 gatewayNode.getUplinkIntf()))
171 .findFirst();
172 if (!port.isPresent()) {
173 log.warn("Cannot find uplink interface from gateway {}", deviceId);
174 return null;
175 }
sangho6032f342016-07-07 14:32:03 +0900176 return port.get().number();
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900177 }
178
179 @Override
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700180 public synchronized GroupId getGatewayGroupId(DeviceId srcDeviceId) {
181 GroupKey groupKey = selectGroupHandler.getGroupKey(srcDeviceId);
182 Group group = groupService.getGroup(srcDeviceId, groupKey);
183 if (group == null) {
184 log.info("Created gateway group for {}", srcDeviceId);
185 return selectGroupHandler.createGatewayGroup(srcDeviceId, getGatewayNodes());
186 } else {
187 return group.id();
188 }
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900189 }
190
191 @Override
192 public List<GatewayNode> getGatewayNodes() {
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900193 List<GatewayNode> gatewayNodeList = Lists.newArrayList();
194 gatewayNodeMap.values()
195 .stream()
Kyuhwi Choi70537882016-06-24 17:24:12 +0900196 .map(Versioned::value)
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700197 .forEach(gatewayNodeList::add);
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900198 return gatewayNodeList;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900199 }
200
201 @Override
202 public List<DeviceId> getGatewayDeviceIds() {
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900203 List<DeviceId> deviceIdList = Lists.newArrayList();
204 gatewayNodeMap.values()
205 .stream()
Kyuhwi Choi70537882016-06-24 17:24:12 +0900206 .map(Versioned::value)
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900207 .forEach(gatewayNode -> deviceIdList.add(gatewayNode.getGatewayDeviceId()));
208 return deviceIdList;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900209 }
210
211 @Override
Hyunsun Moon5aa480b2016-08-03 12:23:14 -0700212 public synchronized boolean addGatewayNode(GatewayNode gatewayNode) {
Hyunsun Moond331afd2016-07-20 02:19:20 -0700213 Versioned<GatewayNode> existingNode = gatewayNodeMap.putIfAbsent(
214 gatewayNode.getGatewayDeviceId(), gatewayNode);
215 if (existingNode == null) {
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700216 updateGatewayGroup(gatewayNode, true);
Hyunsun Moond331afd2016-07-20 02:19:20 -0700217 log.info("Added {} to gateway pool", gatewayNode);
218 return true;
219 } else {
220 return false;
221 }
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900222 }
223
224 @Override
Hyunsun Moon5aa480b2016-08-03 12:23:14 -0700225 public synchronized boolean deleteGatewayNode(GatewayNode gatewayNode) {
Kyuhwi Choi70537882016-06-24 17:24:12 +0900226 boolean result = gatewayNodeMap.remove(gatewayNode.getGatewayDeviceId(), gatewayNode);
227 if (result) {
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700228 updateGatewayGroup(gatewayNode, false);
229 log.info("Deleted gateway with device ID {}", gatewayNode.getGatewayDeviceId());
Kyuhwi Choi70537882016-06-24 17:24:12 +0900230 }
231 return result;
232 }
233
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700234 private void updateGatewayGroup(GatewayNode gatewayNode, boolean isInsert) {
235 Tools.stream(deviceService.getAvailableDevices()).forEach(device -> {
236 Tools.stream(groupService.getGroups(device.id(), appId)).forEach(group -> {
237 selectGroupHandler.updateGatewayGroupBuckets(
238 device.id(),
239 ImmutableList.of(gatewayNode),
240 isInsert);
241 log.trace("Updated gateway group on {}", device.id());
242 });
243 });
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900244 }
245
246 private class InternalConfigListener implements NetworkConfigListener {
247 @Override
248 public void event(NetworkConfigEvent event) {
249 if (!event.configClass().equals(GatewayNodeConfig.class)) {
250 return;
251 }
252 switch (event.type()) {
253 case CONFIG_UPDATED:
254 gatewayNodeMap.clear();
255 readConfiguration();
256 break;
257 case CONFIG_ADDED:
258 readConfiguration();
259 break;
260 default:
261 log.debug("Unsupportable event type is occurred");
262 break;
263 }
264 }
265 }
266
Kyuhwi Choi70537882016-06-24 17:24:12 +0900267 private class InternalDeviceListener implements DeviceListener {
268
269 @Override
270 public void event(DeviceEvent deviceEvent) {
271 if (deviceEvent.type() == DeviceEvent.Type.DEVICE_SUSPENDED ||
272 deviceEvent.type() == DeviceEvent.Type.DEVICE_REMOVED) {
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700273 DeviceId deviceId = deviceEvent.subject().id();
274 deleteGatewayNode(getGatewayNode(deviceId));
275 log.warn("Gateway with device ID {} is disconnected", deviceId);
Kyuhwi Choi70537882016-06-24 17:24:12 +0900276 }
277 }
278 }
279
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900280 private void readConfiguration() {
281 config = configService.getConfig(appId, GatewayNodeConfig.class);
282 if (config == null) {
283 log.error("No configuration found");
284 return;
285 }
286
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700287 config.gatewayNodes().forEach(this::addGatewayNode);
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900288 log.info("ScalableGateway configured");
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900289 }
290}