blob: 5e1d2b09d07658cd6369151f9af2eebcae96fac2 [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);
125 configRegistry.registerConfigFactory(configFactory);
126 configService.addListener(configListener);
Kyuhwi Choi70537882016-06-24 17:24:12 +0900127 deviceService.addListener(internalDeviceListener);
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900128
Kyuhwi Choib0718212016-06-01 11:33:27 +0900129 selectGroupHandler = new SelectGroupHandler(groupService, deviceService, driverService, appId);
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900130
Kyuhwi Choi70537882016-06-24 17:24:12 +0900131 gatewayNodeMap = storageService.<DeviceId, GatewayNode>consistentMapBuilder()
132 .withSerializer(Serializer.using(GATEWAYNODE_SERIALIZER.build()))
133 .withName(GATEWAYNODE_MAP_NAME)
134 .withApplicationId(appId)
135 .build();
136
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900137 log.info("started");
138 }
139
140 @Deactivate
141 protected void deactivate() {
Kyuhwi Choi70537882016-06-24 17:24:12 +0900142 deviceService.removeListener(internalDeviceListener);
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900143 configService.removeListener(configListener);
144
145 log.info("stopped");
146 }
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900147
148 @Override
149 public GatewayNode getGatewayNode(DeviceId deviceId) {
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700150 GatewayNode gatewayNode = gatewayNodeMap.get(deviceId).value();
151 if (gatewayNode == null) {
152 log.warn("Gateway with device ID {} does not exist");
153 return null;
154 }
155 return gatewayNode;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900156 }
157
158 @Override
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700159 public PortNumber getUplinkPort(DeviceId deviceId) {
160 GatewayNode gatewayNode = gatewayNodeMap.get(deviceId).value();
161 if (gatewayNode == null) {
162 log.warn("Gateway with device ID {} does not exist");
sangho6032f342016-07-07 14:32:03 +0900163 return null;
164 }
165
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700166 Optional<Port> port = deviceService.getPorts(deviceId).stream()
167 .filter(p -> Objects.equals(
168 p.annotations().value(PORT_NAME),
169 gatewayNode.getUplinkIntf()))
170 .findFirst();
171 if (!port.isPresent()) {
172 log.warn("Cannot find uplink interface from gateway {}", deviceId);
173 return null;
174 }
sangho6032f342016-07-07 14:32:03 +0900175 return port.get().number();
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900176 }
177
178 @Override
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700179 public synchronized GroupId getGatewayGroupId(DeviceId srcDeviceId) {
180 GroupKey groupKey = selectGroupHandler.getGroupKey(srcDeviceId);
181 Group group = groupService.getGroup(srcDeviceId, groupKey);
182 if (group == null) {
183 log.info("Created gateway group for {}", srcDeviceId);
184 return selectGroupHandler.createGatewayGroup(srcDeviceId, getGatewayNodes());
185 } else {
186 return group.id();
187 }
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900188 }
189
190 @Override
191 public List<GatewayNode> getGatewayNodes() {
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900192 List<GatewayNode> gatewayNodeList = Lists.newArrayList();
193 gatewayNodeMap.values()
194 .stream()
Kyuhwi Choi70537882016-06-24 17:24:12 +0900195 .map(Versioned::value)
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700196 .forEach(gatewayNodeList::add);
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900197 return gatewayNodeList;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900198 }
199
200 @Override
201 public List<DeviceId> getGatewayDeviceIds() {
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900202 List<DeviceId> deviceIdList = Lists.newArrayList();
203 gatewayNodeMap.values()
204 .stream()
Kyuhwi Choi70537882016-06-24 17:24:12 +0900205 .map(Versioned::value)
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900206 .forEach(gatewayNode -> deviceIdList.add(gatewayNode.getGatewayDeviceId()));
207 return deviceIdList;
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900208 }
209
210 @Override
211 public boolean addGatewayNode(GatewayNode gatewayNode) {
Hyunsun Moond331afd2016-07-20 02:19:20 -0700212 Versioned<GatewayNode> existingNode = gatewayNodeMap.putIfAbsent(
213 gatewayNode.getGatewayDeviceId(), gatewayNode);
214 if (existingNode == null) {
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700215 updateGatewayGroup(gatewayNode, true);
Hyunsun Moond331afd2016-07-20 02:19:20 -0700216 log.info("Added {} to gateway pool", gatewayNode);
217 return true;
218 } else {
219 return false;
220 }
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900221 }
222
223 @Override
224 public boolean deleteGatewayNode(GatewayNode gatewayNode) {
Kyuhwi Choi70537882016-06-24 17:24:12 +0900225 boolean result = gatewayNodeMap.remove(gatewayNode.getGatewayDeviceId(), gatewayNode);
226 if (result) {
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700227 updateGatewayGroup(gatewayNode, false);
228 log.info("Deleted gateway with device ID {}", gatewayNode.getGatewayDeviceId());
Kyuhwi Choi70537882016-06-24 17:24:12 +0900229 }
230 return result;
231 }
232
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700233 private void updateGatewayGroup(GatewayNode gatewayNode, boolean isInsert) {
234 Tools.stream(deviceService.getAvailableDevices()).forEach(device -> {
235 Tools.stream(groupService.getGroups(device.id(), appId)).forEach(group -> {
236 selectGroupHandler.updateGatewayGroupBuckets(
237 device.id(),
238 ImmutableList.of(gatewayNode),
239 isInsert);
240 log.trace("Updated gateway group on {}", device.id());
241 });
242 });
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900243 }
244
245 private class InternalConfigListener implements NetworkConfigListener {
246 @Override
247 public void event(NetworkConfigEvent event) {
248 if (!event.configClass().equals(GatewayNodeConfig.class)) {
249 return;
250 }
251 switch (event.type()) {
252 case CONFIG_UPDATED:
253 gatewayNodeMap.clear();
254 readConfiguration();
255 break;
256 case CONFIG_ADDED:
257 readConfiguration();
258 break;
259 default:
260 log.debug("Unsupportable event type is occurred");
261 break;
262 }
263 }
264 }
265
Kyuhwi Choi70537882016-06-24 17:24:12 +0900266 private class InternalDeviceListener implements DeviceListener {
267
268 @Override
269 public void event(DeviceEvent deviceEvent) {
270 if (deviceEvent.type() == DeviceEvent.Type.DEVICE_SUSPENDED ||
271 deviceEvent.type() == DeviceEvent.Type.DEVICE_REMOVED) {
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700272 DeviceId deviceId = deviceEvent.subject().id();
273 deleteGatewayNode(getGatewayNode(deviceId));
274 log.warn("Gateway with device ID {} is disconnected", deviceId);
Kyuhwi Choi70537882016-06-24 17:24:12 +0900275 }
276 }
277 }
278
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900279 private void readConfiguration() {
280 config = configService.getConfig(appId, GatewayNodeConfig.class);
281 if (config == null) {
282 log.error("No configuration found");
283 return;
284 }
285
Hyunsun Moonf9a16ed2016-07-20 21:59:48 -0700286 config.gatewayNodes().forEach(this::addGatewayNode);
Kyuhwi Choidc2973b2016-05-13 14:54:31 +0900287 log.info("ScalableGateway configured");
Kyuhwi Choic5b33ea2016-04-26 11:45:32 +0900288 }
289}