Kyuhwi Choi
Committed by Gerrit Code Review

[ONOS-4482] Implement dynamic add or remove a gateway node

 - Implements command line interface for dynamic management
 - Implements dynamic gateway node management
 - Add CLIs

Change-Id: I27bb945968a262d2813d317fc79e75ee768b2825
1 COMPILE_DEPS = [ 1 COMPILE_DEPS = [
2 '//lib:CORE_DEPS', 2 '//lib:CORE_DEPS',
3 + '//lib:org.apache.karaf.shell.console',
4 + '//cli:onos-cli',
5 + '//core/store/serializers:onos-core-serializers',
3 ] 6 ]
4 7
5 osgi_jar_with_tests ( 8 osgi_jar_with_tests (
......
...@@ -53,5 +53,15 @@ ...@@ -53,5 +53,15 @@
53 <artifactId>onos-core-serializers</artifactId> 53 <artifactId>onos-core-serializers</artifactId>
54 <version>${project.version}</version> 54 <version>${project.version}</version>
55 </dependency> 55 </dependency>
56 + <dependency>
57 + <groupId>org.apache.karaf.shell</groupId>
58 + <artifactId>org.apache.karaf.shell.console</artifactId>
59 + <version>3.0.5</version>
60 + </dependency>
61 + <dependency>
62 + <groupId>org.onosproject</groupId>
63 + <artifactId>onos-cli</artifactId>
64 + <version>1.7.0-SNAPSHOT</version>
65 + </dependency>
56 </dependencies> 66 </dependencies>
57 </project> 67 </project>
......
1 +/*
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 +
17 +package org.onosproject.scalablegateway.cli;
18 +
19 +import com.google.common.collect.Lists;
20 +import org.apache.karaf.shell.commands.Argument;
21 +import org.apache.karaf.shell.commands.Command;
22 +import org.onlab.packet.Ip4Address;
23 +import org.onosproject.cli.AbstractShellCommand;
24 +import org.onosproject.net.DeviceId;
25 +import org.onosproject.scalablegateway.api.GatewayNode;
26 +import org.onosproject.scalablegateway.api.ScalableGatewayService;
27 +
28 +import java.util.Collections;
29 +import java.util.List;
30 +
31 +/**
32 + * Adds gateway node information for scalablegateway node managements.
33 + */
34 +
35 +@Command(scope = "onos", name = "gateway-add",
36 + description = "Adds gateway node information for scalablegateway node managements")
37 +public class ScalableGatewayAddCommand extends AbstractShellCommand {
38 +
39 + private static final String SUCCESS = "Process of adding gateway node is succeed";
40 + private static final String FAIL = "Process of adding gateway node is failed";
41 +
42 + @Argument(index = 0, name = "DeviceId", description = "GatewayNode device id",
43 + required = true, multiValued = false)
44 + String deviceId = null;
45 +
46 + @Argument(index = 1, name = "dataPlaneIp",
47 + description = "GatewayNode datePlane interface ip address",
48 + required = true, multiValued = false)
49 + String ipAddress = null;
50 +
51 + @Argument(index = 2, name = "extInterfaceNames",
52 + description = "GatewayNode Interface name to outgoing external network",
53 + required = true, multiValued = true)
54 + String interfaceName = null;
55 +
56 + @Override
57 + protected void execute() {
58 + ScalableGatewayService service = get(ScalableGatewayService.class);
59 +
60 + GatewayNode gatewayNode = GatewayNode.builder()
61 + .gatewayDeviceId(DeviceId.deviceId(deviceId))
62 + .dataIpAddress(Ip4Address.valueOf(ipAddress))
63 + .gatewayExternalInterfaceNames(splitNameList(interfaceName))
64 + .build();
65 + if (service.addGatewayNode(gatewayNode)) {
66 + print(SUCCESS);
67 + } else {
68 + print(FAIL);
69 + }
70 + }
71 +
72 + private List<String> splitNameList(String interfaceName) {
73 + List<String> list = Lists.newArrayList();
74 + return Collections.addAll(list, interfaceName.split(",")) ? list : null;
75 + }
76 +}
1 +/*
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 +
17 +package org.onosproject.scalablegateway.cli;
18 +
19 +import org.apache.karaf.shell.commands.Argument;
20 +import org.apache.karaf.shell.commands.Command;
21 +import org.onosproject.cli.AbstractShellCommand;
22 +import org.onosproject.net.DeviceId;
23 +import org.onosproject.scalablegateway.api.GatewayNode;
24 +import org.onosproject.scalablegateway.api.ScalableGatewayService;
25 +
26 +/**
27 + * Deletes gateway node information for scalablegateway node managements.
28 + */
29 +
30 +@Command(scope = "onos", name = "gateway-delete",
31 + description = "Deletes gateway node information for scalablegateway node managements")
32 +public class ScalableGatewayDeleteCommand extends AbstractShellCommand {
33 +
34 + private static final String SUCCESS = "Process of deleting gateway node is succeed.";
35 + private static final String FAIL = "Process of deleting gateway node is failed.";
36 + private static final String UNKNOWN = "Unknown device id is given.";
37 +
38 + @Argument(index = 0, name = "DeviceId", description = "GatewayNode device id",
39 + required = true, multiValued = false)
40 + String deviceId = null;
41 +
42 + @Override
43 + protected void execute() {
44 + ScalableGatewayService service = get(ScalableGatewayService.class);
45 +
46 + GatewayNode gatewayNode = service.getGatewayNode(DeviceId.deviceId(deviceId));
47 + if (gatewayNode == null) {
48 + print(UNKNOWN);
49 + return;
50 + }
51 +
52 + if (service.deleteGatewayNode(gatewayNode)) {
53 + print(SUCCESS);
54 + } else {
55 + print(FAIL);
56 + }
57 + }
58 +
59 +}
1 +/*
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 +
17 +package org.onosproject.scalablegateway.cli;
18 +
19 +import org.apache.karaf.shell.commands.Command;
20 +import org.onosproject.cli.AbstractShellCommand;
21 +import org.onosproject.scalablegateway.api.ScalableGatewayService;
22 +
23 +/**
24 + * Lists all gateway node information of scalablegateway.
25 + */
26 +
27 +@Command(scope = "onos", name = "gateways",
28 + description = "Lists gateway node information")
29 +public class ScalableGatewayListCommand extends AbstractShellCommand {
30 +
31 + private static final String FORMAT = "GatewayNode Id[%s]: DataPlane Ip[%s], External Interface names[%s]";
32 + @Override
33 + protected void execute() {
34 + ScalableGatewayService service = get(ScalableGatewayService.class);
35 + service.getGatewayNodes().forEach(node -> print(FORMAT,
36 + node.getGatewayDeviceId().toString(),
37 + node.getDataIpAddress().toString(),
38 + node.getGatewayExternalInterfaceNames().toString()));
39 + }
40 +}
1 +/*
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 +
17 +/**
18 + * Command line interface for Scaleable Gateway management.
19 + */
20 +package org.onosproject.scalablegateway.cli;
...\ No newline at end of file ...\ No newline at end of file
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
17 package org.onosproject.scalablegateway.impl; 17 package org.onosproject.scalablegateway.impl;
18 18
19 import com.google.common.collect.Lists; 19 import com.google.common.collect.Lists;
20 -import com.google.common.collect.Maps;
21 import org.apache.felix.scr.annotations.Activate; 20 import org.apache.felix.scr.annotations.Activate;
22 import org.apache.felix.scr.annotations.Component; 21 import org.apache.felix.scr.annotations.Component;
23 import org.apache.felix.scr.annotations.Deactivate; 22 import org.apache.felix.scr.annotations.Deactivate;
...@@ -25,6 +24,7 @@ import org.apache.felix.scr.annotations.Deactivate; ...@@ -25,6 +24,7 @@ import org.apache.felix.scr.annotations.Deactivate;
25 import org.apache.felix.scr.annotations.Reference; 24 import org.apache.felix.scr.annotations.Reference;
26 import org.apache.felix.scr.annotations.ReferenceCardinality; 25 import org.apache.felix.scr.annotations.ReferenceCardinality;
27 import org.apache.felix.scr.annotations.Service; 26 import org.apache.felix.scr.annotations.Service;
27 +import org.onlab.util.KryoNamespace;
28 import org.onosproject.core.ApplicationId; 28 import org.onosproject.core.ApplicationId;
29 import org.onosproject.core.CoreService; 29 import org.onosproject.core.CoreService;
30 30
...@@ -38,6 +38,8 @@ import org.onosproject.net.config.NetworkConfigListener; ...@@ -38,6 +38,8 @@ import org.onosproject.net.config.NetworkConfigListener;
38 import org.onosproject.net.config.NetworkConfigRegistry; 38 import org.onosproject.net.config.NetworkConfigRegistry;
39 import org.onosproject.net.config.NetworkConfigService; 39 import org.onosproject.net.config.NetworkConfigService;
40 import org.onosproject.net.config.basics.SubjectFactories; 40 import org.onosproject.net.config.basics.SubjectFactories;
41 +import org.onosproject.net.device.DeviceEvent;
42 +import org.onosproject.net.device.DeviceListener;
41 import org.onosproject.net.device.DeviceService; 43 import org.onosproject.net.device.DeviceService;
42 import org.onosproject.net.driver.DriverService; 44 import org.onosproject.net.driver.DriverService;
43 import org.onosproject.net.group.Group; 45 import org.onosproject.net.group.Group;
...@@ -48,8 +50,12 @@ import org.onosproject.scalablegateway.api.GatewayNodeConfig; ...@@ -48,8 +50,12 @@ import org.onosproject.scalablegateway.api.GatewayNodeConfig;
48 import org.onosproject.scalablegateway.api.ScalableGatewayService; 50 import org.onosproject.scalablegateway.api.ScalableGatewayService;
49 51
50 import java.util.List; 52 import java.util.List;
51 -import java.util.Map;
52 53
54 +import org.onosproject.store.serializers.KryoNamespaces;
55 +import org.onosproject.store.service.ConsistentMap;
56 +import org.onosproject.store.service.Serializer;
57 +import org.onosproject.store.service.StorageService;
58 +import org.onosproject.store.service.Versioned;
53 import org.slf4j.Logger; 59 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory; 60 import org.slf4j.LoggerFactory;
55 61
...@@ -72,6 +78,7 @@ public class ScalableGatewayManager implements ScalableGatewayService { ...@@ -72,6 +78,7 @@ public class ScalableGatewayManager implements ScalableGatewayService {
72 private static final String FAIL_ADD_GATEWAY = "Adding process is failed as existing deivce id"; 78 private static final String FAIL_ADD_GATEWAY = "Adding process is failed as existing deivce id";
73 private static final String FAIL_REMOVE_GATEWAY = "Removing process is failed as unknown deivce id"; 79 private static final String FAIL_REMOVE_GATEWAY = "Removing process is failed as unknown deivce id";
74 private static final String PORT_NAME = "portName"; 80 private static final String PORT_NAME = "portName";
81 + private static final String GATEWAYNODE_MAP_NAME = "gatewaynode-map";
75 82
76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected CoreService coreService; 84 protected CoreService coreService;
...@@ -91,10 +98,14 @@ public class ScalableGatewayManager implements ScalableGatewayService { ...@@ -91,10 +98,14 @@ public class ScalableGatewayManager implements ScalableGatewayService {
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected GroupService groupService; 99 protected GroupService groupService;
93 100
101 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 + protected StorageService storageService;
103 +
94 private GatewayNodeConfig config; 104 private GatewayNodeConfig config;
95 private SelectGroupHandler selectGroupHandler; 105 private SelectGroupHandler selectGroupHandler;
96 106
97 private final NetworkConfigListener configListener = new InternalConfigListener(); 107 private final NetworkConfigListener configListener = new InternalConfigListener();
108 + private InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
98 109
99 private final ConfigFactory configFactory = 110 private final ConfigFactory configFactory =
100 new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, GatewayNodeConfig.class, APP_NAME) { 111 new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, GatewayNodeConfig.class, APP_NAME) {
...@@ -103,17 +114,28 @@ public class ScalableGatewayManager implements ScalableGatewayService { ...@@ -103,17 +114,28 @@ public class ScalableGatewayManager implements ScalableGatewayService {
103 return new GatewayNodeConfig(); 114 return new GatewayNodeConfig();
104 } 115 }
105 }; 116 };
106 - private Map<DeviceId, GatewayNode> gatewayNodeMap = Maps.newHashMap(); // Map<GatewayNode`s Id, GatewayNode object> 117 + private ConsistentMap<DeviceId, GatewayNode> gatewayNodeMap; // Map<GatewayNode`s Id, GatewayNode object>
118 + private static final KryoNamespace.Builder GATEWAYNODE_SERIALIZER = KryoNamespace.newBuilder()
119 + .register(KryoNamespaces.API)
120 + .register(DeviceId.class)
121 + .register(GatewayNode.class);
107 122
108 @Activate 123 @Activate
109 protected void activate() { 124 protected void activate() {
110 appId = coreService.registerApplication(APP_ID); 125 appId = coreService.registerApplication(APP_ID);
111 configRegistry.registerConfigFactory(configFactory); 126 configRegistry.registerConfigFactory(configFactory);
112 configService.addListener(configListener); 127 configService.addListener(configListener);
128 + deviceService.addListener(internalDeviceListener);
113 129
114 selectGroupHandler = new SelectGroupHandler(groupService, deviceService, driverService, appId); 130 selectGroupHandler = new SelectGroupHandler(groupService, deviceService, driverService, appId);
115 readConfiguration(); 131 readConfiguration();
116 132
133 + gatewayNodeMap = storageService.<DeviceId, GatewayNode>consistentMapBuilder()
134 + .withSerializer(Serializer.using(GATEWAYNODE_SERIALIZER.build()))
135 + .withName(GATEWAYNODE_MAP_NAME)
136 + .withApplicationId(appId)
137 + .build();
138 +
117 log.info("started"); 139 log.info("started");
118 } 140 }
119 141
...@@ -121,6 +143,7 @@ public class ScalableGatewayManager implements ScalableGatewayService { ...@@ -121,6 +143,7 @@ public class ScalableGatewayManager implements ScalableGatewayService {
121 protected void deactivate() { 143 protected void deactivate() {
122 gatewayNodeMap.clear(); 144 gatewayNodeMap.clear();
123 145
146 + deviceService.removeListener(internalDeviceListener);
124 configService.removeListener(configListener); 147 configService.removeListener(configListener);
125 148
126 log.info("stopped"); 149 log.info("stopped");
...@@ -128,12 +151,12 @@ public class ScalableGatewayManager implements ScalableGatewayService { ...@@ -128,12 +151,12 @@ public class ScalableGatewayManager implements ScalableGatewayService {
128 151
129 @Override 152 @Override
130 public GatewayNode getGatewayNode(DeviceId deviceId) { 153 public GatewayNode getGatewayNode(DeviceId deviceId) {
131 - return checkNotNull(gatewayNodeMap.get(deviceId), GATEWAYNODE_CAN_NOT_BE_NULL); 154 + return checkNotNull(gatewayNodeMap.get(deviceId).value(), GATEWAYNODE_CAN_NOT_BE_NULL);
132 } 155 }
133 156
134 @Override 157 @Override
135 public List<PortNumber> getGatewayExternalPorts(DeviceId deviceId) { 158 public List<PortNumber> getGatewayExternalPorts(DeviceId deviceId) {
136 - GatewayNode gatewayNode = checkNotNull(gatewayNodeMap.get(deviceId), GATEWAYNODE_CAN_NOT_BE_NULL); 159 + GatewayNode gatewayNode = checkNotNull(gatewayNodeMap.get(deviceId).value(), GATEWAYNODE_CAN_NOT_BE_NULL);
137 List<PortNumber> portNumbers = Lists.newArrayList(); 160 List<PortNumber> portNumbers = Lists.newArrayList();
138 gatewayNode.getGatewayExternalInterfaceNames() 161 gatewayNode.getGatewayExternalInterfaceNames()
139 .stream() 162 .stream()
...@@ -164,6 +187,7 @@ public class ScalableGatewayManager implements ScalableGatewayService { ...@@ -164,6 +187,7 @@ public class ScalableGatewayManager implements ScalableGatewayService {
164 List<GatewayNode> gatewayNodeList = Lists.newArrayList(); 187 List<GatewayNode> gatewayNodeList = Lists.newArrayList();
165 gatewayNodeMap.values() 188 gatewayNodeMap.values()
166 .stream() 189 .stream()
190 + .map(Versioned::value)
167 .forEach(gatewayNode -> gatewayNodeList.add(gatewayNode)); 191 .forEach(gatewayNode -> gatewayNodeList.add(gatewayNode));
168 return gatewayNodeList; 192 return gatewayNodeList;
169 193
...@@ -174,6 +198,7 @@ public class ScalableGatewayManager implements ScalableGatewayService { ...@@ -174,6 +198,7 @@ public class ScalableGatewayManager implements ScalableGatewayService {
174 List<DeviceId> deviceIdList = Lists.newArrayList(); 198 List<DeviceId> deviceIdList = Lists.newArrayList();
175 gatewayNodeMap.values() 199 gatewayNodeMap.values()
176 .stream() 200 .stream()
201 + .map(Versioned::value)
177 .forEach(gatewayNode -> deviceIdList.add(gatewayNode.getGatewayDeviceId())); 202 .forEach(gatewayNode -> deviceIdList.add(gatewayNode.getGatewayDeviceId()));
178 return deviceIdList; 203 return deviceIdList;
179 204
...@@ -182,12 +207,24 @@ public class ScalableGatewayManager implements ScalableGatewayService { ...@@ -182,12 +207,24 @@ public class ScalableGatewayManager implements ScalableGatewayService {
182 @Override 207 @Override
183 public boolean addGatewayNode(GatewayNode gatewayNode) { 208 public boolean addGatewayNode(GatewayNode gatewayNode) {
184 gatewayNodeMap.putIfAbsent(gatewayNode.getGatewayDeviceId(), gatewayNode); 209 gatewayNodeMap.putIfAbsent(gatewayNode.getGatewayDeviceId(), gatewayNode);
210 + updateGatewayLoadBalance(gatewayNode, true);
185 return true; 211 return true;
186 } 212 }
187 213
188 @Override 214 @Override
189 public boolean deleteGatewayNode(GatewayNode gatewayNode) { 215 public boolean deleteGatewayNode(GatewayNode gatewayNode) {
190 - return gatewayNodeMap.remove(gatewayNode.getGatewayDeviceId(), gatewayNode); 216 + boolean result = gatewayNodeMap.remove(gatewayNode.getGatewayDeviceId(), gatewayNode);
217 + if (result) {
218 + updateGatewayLoadBalance(gatewayNode, false);
219 + }
220 + return result;
221 + }
222 +
223 + private void updateGatewayLoadBalance(GatewayNode gatewayNode, boolean nodeInsertion) {
224 + deviceService.getAvailableDevices().forEach(device ->
225 + groupService.getGroups(device.id(), appId).forEach(group ->
226 + selectGroupHandler.updateBucketToSelectGroupInVxlan(device.id(), group.appCookie(),
227 + Lists.newArrayList(gatewayNode), nodeInsertion)));
191 } 228 }
192 229
193 private class InternalConfigListener implements NetworkConfigListener { 230 private class InternalConfigListener implements NetworkConfigListener {
...@@ -211,6 +248,17 @@ public class ScalableGatewayManager implements ScalableGatewayService { ...@@ -211,6 +248,17 @@ public class ScalableGatewayManager implements ScalableGatewayService {
211 } 248 }
212 } 249 }
213 250
251 + private class InternalDeviceListener implements DeviceListener {
252 +
253 + @Override
254 + public void event(DeviceEvent deviceEvent) {
255 + if (deviceEvent.type() == DeviceEvent.Type.DEVICE_SUSPENDED ||
256 + deviceEvent.type() == DeviceEvent.Type.DEVICE_REMOVED) {
257 + deleteGatewayNode(getGatewayNode(deviceEvent.subject().id()));
258 + }
259 + }
260 + }
261 +
214 private void readConfiguration() { 262 private void readConfiguration() {
215 config = configService.getConfig(appId, GatewayNodeConfig.class); 263 config = configService.getConfig(appId, GatewayNodeConfig.class);
216 if (config == null) { 264 if (config == null) {
......
1 +<!--
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 +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
17 +
18 + <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
19 + <command>
20 + <action class="org.onosproject.scalablegateway.cli.ScalableGatewayListCommand"/>
21 + </command>
22 + <command>
23 + <action class="org.onosproject.scalablegateway.cli.ScalableGatewayAddCommand"/>
24 + </command>
25 + <command>
26 + <action class="org.onosproject.scalablegateway.cli.ScalableGatewayDeleteCommand"/>
27 + </command>
28 + </command-bundle>
29 +</blueprint>