blob: 11cc0aded8b65f19c41addc86ca380ad0fa4fa13 [file] [log] [blame]
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +09003 *
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 Choi70537882016-06-24 17:24:12 +090021import org.onlab.util.KryoNamespace;
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -070022import org.onlab.util.Tools;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090023import org.onosproject.core.ApplicationId;
24import org.onosproject.core.CoreService;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +090025import org.onosproject.core.GroupId;
26import org.onosproject.net.DeviceId;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090027import org.onosproject.net.Port;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +090028import org.onosproject.net.PortNumber;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090029import org.onosproject.net.config.ConfigFactory;
30import org.onosproject.net.config.NetworkConfigEvent;
31import org.onosproject.net.config.NetworkConfigListener;
32import org.onosproject.net.config.NetworkConfigRegistry;
33import org.onosproject.net.config.NetworkConfigService;
34import org.onosproject.net.config.basics.SubjectFactories;
Kyuhwi Choi70537882016-06-24 17:24:12 +090035import org.onosproject.net.device.DeviceEvent;
36import org.onosproject.net.device.DeviceListener;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090037import org.onosproject.net.device.DeviceService;
Kyuhwi Choib0718212016-06-01 11:33:27 +090038import org.onosproject.net.driver.DriverService;
39import org.onosproject.net.group.Group;
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -070040import org.onosproject.net.group.GroupKey;
Kyuhwi Choib0718212016-06-01 11:33:27 +090041import org.onosproject.net.group.GroupService;
Hyunsun Moon71701292016-05-09 12:00:54 -070042import org.onosproject.scalablegateway.api.GatewayNode;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090043import org.onosproject.scalablegateway.api.GatewayNodeConfig;
Hyunsun Moon71701292016-05-09 12:00:54 -070044import org.onosproject.scalablegateway.api.ScalableGatewayService;
Kyuhwi Choi70537882016-06-24 17:24:12 +090045import org.onosproject.store.serializers.KryoNamespaces;
46import org.onosproject.store.service.ConsistentMap;
47import org.onosproject.store.service.Serializer;
48import org.onosproject.store.service.StorageService;
49import org.onosproject.store.service.Versioned;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070050import org.osgi.service.component.annotations.Activate;
51import org.osgi.service.component.annotations.Component;
52import org.osgi.service.component.annotations.Deactivate;
53import org.osgi.service.component.annotations.Reference;
54import org.osgi.service.component.annotations.ReferenceCardinality;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090055import org.slf4j.Logger;
56import org.slf4j.LoggerFactory;
57
sangho09a6ffe2016-08-23 16:55:38 +090058import java.util.List;
59import java.util.Objects;
60import java.util.Optional;
61
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -070062import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +090063
64/**
65 * Manages gateway node for gateway scalability.
66 */
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090067
Ray Milkeyd84f89b2018-08-17 14:54:17 -070068@Component(immediate = true, service = ScalableGatewayService.class)
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +090069public class ScalableGatewayManager implements ScalableGatewayService {
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090070 private final Logger log = LoggerFactory.getLogger(getClass());
71
72 private ApplicationId appId;
73 private static final String APP_ID = "org.onosproject.scalablegateway";
74 private static final String APP_NAME = "scalablegateway";
Kyuhwi Choi70537882016-06-24 17:24:12 +090075 private static final String GATEWAYNODE_MAP_NAME = "gatewaynode-map";
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090076
Ray Milkeyd84f89b2018-08-17 14:54:17 -070077 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090078 protected CoreService coreService;
79
Ray Milkeyd84f89b2018-08-17 14:54:17 -070080 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090081 protected NetworkConfigService configService;
82
Ray Milkeyd84f89b2018-08-17 14:54:17 -070083 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090084 protected NetworkConfigRegistry configRegistry;
85
Ray Milkeyd84f89b2018-08-17 14:54:17 -070086 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090087 protected DeviceService deviceService;
88
Ray Milkeyd84f89b2018-08-17 14:54:17 -070089 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Kyuhwi Choib0718212016-06-01 11:33:27 +090090 protected DriverService driverService;
91
Ray Milkeyd84f89b2018-08-17 14:54:17 -070092 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Kyuhwi Choib0718212016-06-01 11:33:27 +090093 protected GroupService groupService;
94
Ray Milkeyd84f89b2018-08-17 14:54:17 -070095 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Kyuhwi Choi70537882016-06-24 17:24:12 +090096 protected StorageService storageService;
97
Kyuhwi Choidc2973b2016-05-13 14:54:31 +090098 private GatewayNodeConfig config;
Kyuhwi Choib0718212016-06-01 11:33:27 +090099 private SelectGroupHandler selectGroupHandler;
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900100
101 private final NetworkConfigListener configListener = new InternalConfigListener();
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700102 private final InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900103
104 private final ConfigFactory configFactory =
105 new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, GatewayNodeConfig.class, APP_NAME) {
106 @Override
107 public GatewayNodeConfig createConfig() {
108 return new GatewayNodeConfig();
109 }
110 };
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700111
112 private ConsistentMap<DeviceId, GatewayNode> gatewayNodeMap; // Map<GatewayNode Id, GatewayNode object>
Kyuhwi Choi70537882016-06-24 17:24:12 +0900113 private static final KryoNamespace.Builder GATEWAYNODE_SERIALIZER = KryoNamespace.newBuilder()
114 .register(KryoNamespaces.API)
Kyuhwi Choi70537882016-06-24 17:24:12 +0900115 .register(GatewayNode.class);
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900116
117 @Activate
118 protected void activate() {
119 appId = coreService.registerApplication(APP_ID);
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900120
Kyuhwi Choi70537882016-06-24 17:24:12 +0900121 gatewayNodeMap = storageService.<DeviceId, GatewayNode>consistentMapBuilder()
122 .withSerializer(Serializer.using(GATEWAYNODE_SERIALIZER.build()))
123 .withName(GATEWAYNODE_MAP_NAME)
124 .withApplicationId(appId)
125 .build();
126
Daniel Parkd4d88012016-08-05 08:56:53 +0900127 configRegistry.registerConfigFactory(configFactory);
128 configService.addListener(configListener);
129 deviceService.addListener(internalDeviceListener);
130
131 selectGroupHandler = new SelectGroupHandler(groupService, deviceService, driverService, appId);
132
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900133 log.info("started");
134 }
135
136 @Deactivate
137 protected void deactivate() {
Kyuhwi Choi70537882016-06-24 17:24:12 +0900138 deviceService.removeListener(internalDeviceListener);
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900139 configService.removeListener(configListener);
140
141 log.info("stopped");
142 }
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900143
144 @Override
145 public GatewayNode getGatewayNode(DeviceId deviceId) {
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700146 GatewayNode gatewayNode = gatewayNodeMap.get(deviceId).value();
147 if (gatewayNode == null) {
148 log.warn("Gateway with device ID {} does not exist");
149 return null;
150 }
151 return gatewayNode;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900152 }
153
154 @Override
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700155 public PortNumber getUplinkPort(DeviceId deviceId) {
156 GatewayNode gatewayNode = gatewayNodeMap.get(deviceId).value();
157 if (gatewayNode == null) {
158 log.warn("Gateway with device ID {} does not exist");
sangho6032f342016-07-07 14:32:03 +0900159 return null;
160 }
161
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700162 Optional<Port> port = deviceService.getPorts(deviceId).stream()
163 .filter(p -> Objects.equals(
164 p.annotations().value(PORT_NAME),
165 gatewayNode.getUplinkIntf()))
166 .findFirst();
167 if (!port.isPresent()) {
168 log.warn("Cannot find uplink interface from gateway {}", deviceId);
169 return null;
170 }
sangho6032f342016-07-07 14:32:03 +0900171 return port.get().number();
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900172 }
173
174 @Override
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700175 public synchronized GroupId getGatewayGroupId(DeviceId srcDeviceId) {
176 GroupKey groupKey = selectGroupHandler.getGroupKey(srcDeviceId);
177 Group group = groupService.getGroup(srcDeviceId, groupKey);
178 if (group == null) {
179 log.info("Created gateway group for {}", srcDeviceId);
180 return selectGroupHandler.createGatewayGroup(srcDeviceId, getGatewayNodes());
181 } else {
182 return group.id();
183 }
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900184 }
185
186 @Override
187 public List<GatewayNode> getGatewayNodes() {
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900188 List<GatewayNode> gatewayNodeList = Lists.newArrayList();
189 gatewayNodeMap.values()
190 .stream()
Kyuhwi Choi70537882016-06-24 17:24:12 +0900191 .map(Versioned::value)
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700192 .forEach(gatewayNodeList::add);
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900193 return gatewayNodeList;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900194 }
195
196 @Override
197 public List<DeviceId> getGatewayDeviceIds() {
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900198 List<DeviceId> deviceIdList = Lists.newArrayList();
199 gatewayNodeMap.values()
200 .stream()
Kyuhwi Choi70537882016-06-24 17:24:12 +0900201 .map(Versioned::value)
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900202 .forEach(gatewayNode -> deviceIdList.add(gatewayNode.getGatewayDeviceId()));
203 return deviceIdList;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900204 }
205
206 @Override
Hyunsun Moon5aa480b2016-08-03 12:23:14 -0700207 public synchronized boolean addGatewayNode(GatewayNode gatewayNode) {
sangho09a6ffe2016-08-23 16:55:38 +0900208 Versioned<GatewayNode> existingNode = gatewayNodeMap.put(gatewayNode.getGatewayDeviceId(),
209 gatewayNode);
Hyunsun Moond331afd2016-07-20 02:19:20 -0700210 if (existingNode == null) {
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700211 updateGatewayGroup(gatewayNode, true);
sangho09a6ffe2016-08-23 16:55:38 +0900212 log.info("Gateway {} is added to Gateway pool", gatewayNode);
213 return true;
214 } else if (!existingNode.value().equals(gatewayNode)) {
215 updateGatewayGroup(existingNode.value(), false);
216 updateGatewayGroup(gatewayNode, true);
217 log.info("Gateway {} is updated", gatewayNode);
Hyunsun Moond331afd2016-07-20 02:19:20 -0700218 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}