blob: aa900939afdfc9b932b162dc7cfe68fbcc6a4571 [file] [log] [blame]
Hyunsun Moone9d75992015-09-15 22:39:16 -07001/*
Brian O'Connor8e57fd52016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Hyunsun Moone9d75992015-09-15 22:39:16 -07003 *
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 */
Hyunsun Moon187bf532017-01-19 10:57:40 +090016package org.opencord.cordvtn.api;
Hyunsun Moone9d75992015-09-15 22:39:16 -070017
18import com.fasterxml.jackson.databind.JsonNode;
Hyunsun Moon153db182016-08-04 14:06:40 -070019import com.fasterxml.jackson.databind.node.ObjectNode;
Hyunsun Moon81a13562016-08-04 13:48:08 -070020import com.google.common.base.Strings;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080021import com.google.common.collect.ImmutableList;
22import com.google.common.collect.Lists;
Hyunsun Moonb5f92e52016-02-17 15:02:06 -080023import com.google.common.collect.Maps;
Hyunsun Moone9d75992015-09-15 22:39:16 -070024import com.google.common.collect.Sets;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080025import org.onlab.osgi.DefaultServiceDirectory;
Hyunsun Moonb5f92e52016-02-17 15:02:06 -080026import org.onlab.packet.IpAddress;
Hyunsun Moon3fc17f72016-01-24 21:47:06 -080027import org.onlab.packet.MacAddress;
Hyunsun Moone9d75992015-09-15 22:39:16 -070028import org.onlab.packet.TpPort;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080029import org.onosproject.cluster.ClusterService;
Hyunsun Moone9d75992015-09-15 22:39:16 -070030import org.onosproject.core.ApplicationId;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080031import org.onosproject.net.behaviour.ControllerInfo;
Hyunsun Moone9d75992015-09-15 22:39:16 -070032import org.onosproject.net.config.Config;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080033import org.onosproject.net.config.InvalidFieldException;
Hyunsun Moon187bf532017-01-19 10:57:40 +090034import org.opencord.cordvtn.api.net.CidrAddr;
Hyunsun Moonfd5a24e2016-10-19 19:15:48 -070035import org.opencord.cordvtn.api.node.CordVtnNode;
Hyunsun Moonfd5a24e2016-10-19 19:15:48 -070036import org.opencord.cordvtn.api.node.SshAccessInfo;
Hyunsun Moon3fc17f72016-01-24 21:47:06 -080037import org.slf4j.Logger;
Hyunsun Moone9d75992015-09-15 22:39:16 -070038
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080039import java.util.List;
Hyunsun Moonb5f92e52016-02-17 15:02:06 -080040import java.util.Map;
Hyunsun Moone9d75992015-09-15 22:39:16 -070041import java.util.Set;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080042import java.util.stream.Collectors;
Hyunsun Moone9d75992015-09-15 22:39:16 -070043
Hyunsun Moon153db182016-08-04 14:06:40 -070044import static org.onosproject.net.config.Config.FieldPresence.MANDATORY;
45import static org.onosproject.net.config.Config.FieldPresence.OPTIONAL;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080046import static org.opencord.cordvtn.api.Constants.DEFAULT_OF_PORT;
47import static org.opencord.cordvtn.api.Constants.DEFAULT_OF_PROTOCOL;
Hyunsun Moon3fc17f72016-01-24 21:47:06 -080048import static org.slf4j.LoggerFactory.getLogger;
Hyunsun Moone9d75992015-09-15 22:39:16 -070049
50/**
Hyunsun Moon9661d642015-09-23 13:24:35 -070051 * Configuration object for CordVtn service.
Hyunsun Moone9d75992015-09-15 22:39:16 -070052 */
53public class CordVtnConfig extends Config<ApplicationId> {
54
Hyunsun Moon3fc17f72016-01-24 21:47:06 -080055 protected final Logger log = getLogger(getClass());
56
Hyunsun Moon60a10672016-06-12 17:39:12 -070057 private static final String PRIVATE_GATEWAY_MAC = "privateGatewayMac";
58 private static final String PUBLIC_GATEWAYS = "publicGateways";
59 private static final String GATEWAY_IP = "gatewayIp";
60 private static final String GATEWAY_MAC = "gatewayMac";
61 private static final String LOCAL_MANAGEMENT_IP = "localManagementIp";
62 private static final String OVSDB_PORT = "ovsdbPort";
Hyunsun Moond05b32e2016-03-02 19:27:26 -080063
Hyunsun Moon60a10672016-06-12 17:39:12 -070064 private static final String CORDVTN_NODES = "nodes";
65 private static final String HOSTNAME = "hostname";
66 private static final String HOST_MANAGEMENT_IP = "hostManagementIp";
Hyunsun Moon81a13562016-08-04 13:48:08 -070067 private static final String HOST_MANAGEMENT_IFACE = "hostManagementIface";
68 private static final String DATA_IP = "dataPlaneIp";
69 private static final String DATA_IFACE = "dataPlaneIntf";
70 private static final String INTEGRATION_BRIDGE_ID = "bridgeId";
Hyunsun Moone9d75992015-09-15 22:39:16 -070071
Hyunsun Moon60a10672016-06-12 17:39:12 -070072 private static final String SSH = "ssh";
73 private static final String SSH_PORT = "sshPort";
74 private static final String SSH_USER = "sshUser";
75 private static final String SSH_KEY_FILE = "sshKeyFile";
Hyunsun Moon61e79ee2016-04-14 19:04:23 -070076
Hyunsun Moon187bf532017-01-19 10:57:40 +090077 @Deprecated
Hyunsun Moon60a10672016-06-12 17:39:12 -070078 private static final String OPENSTACK = "openstack";
Hyunsun Moon187bf532017-01-19 10:57:40 +090079 @Deprecated
Hyunsun Moon60a10672016-06-12 17:39:12 -070080 private static final String XOS = "xos";
Hyunsun Moon61e79ee2016-04-14 19:04:23 -070081
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080082 private static final String CONTROLLERS = "controllers";
83 private static final int INDEX_IP = 0;
84 private static final int INDEX_PORT = 1;
85
86 private final ClusterService clusterService =
87 DefaultServiceDirectory.getService(ClusterService.class);
88
Hyunsun Moon153db182016-08-04 14:06:40 -070089 @Override
90 public boolean isValid() {
91 // check only allowed fields are present
92 boolean result = hasOnlyFields(
93 PRIVATE_GATEWAY_MAC,
94 PUBLIC_GATEWAYS,
95 LOCAL_MANAGEMENT_IP,
96 OVSDB_PORT,
97 SSH,
98 OPENSTACK,
99 XOS,
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800100 CORDVTN_NODES,
101 CONTROLLERS);
Hyunsun Moon153db182016-08-04 14:06:40 -0700102
103 if (object.get(CORDVTN_NODES) == null || object.get(CORDVTN_NODES).size() < 1) {
104 final String msg = "No node is present";
105 throw new IllegalArgumentException(msg);
106 }
107
108 // check all mandatory fields are present and valid
Hyunsun Moon187bf532017-01-19 10:57:40 +0900109 result = result && isMacAddress(PRIVATE_GATEWAY_MAC, MANDATORY);
110 result = result && isIpPrefix(LOCAL_MANAGEMENT_IP, MANDATORY);
Hyunsun Moon153db182016-08-04 14:06:40 -0700111
112 for (JsonNode node : object.get(CORDVTN_NODES)) {
113 ObjectNode vtnNode = (ObjectNode) node;
Hyunsun Moon187bf532017-01-19 10:57:40 +0900114 result = result && hasFields(
Hyunsun Moon153db182016-08-04 14:06:40 -0700115 vtnNode,
116 HOSTNAME,
117 HOST_MANAGEMENT_IP,
118 DATA_IP,
119 DATA_IFACE,
120 INTEGRATION_BRIDGE_ID);
Hyunsun Moon187bf532017-01-19 10:57:40 +0900121 result = result && isIpPrefix(vtnNode, HOST_MANAGEMENT_IP, MANDATORY);
122 result = result && isIpPrefix(vtnNode, DATA_IP, MANDATORY);
Hyunsun Moon153db182016-08-04 14:06:40 -0700123
Hyunsun Moon187bf532017-01-19 10:57:40 +0900124 CidrAddr localMgmt = CidrAddr.valueOf(get(LOCAL_MANAGEMENT_IP, ""));
125 CidrAddr hostsMgmt = CidrAddr.valueOf(getConfig(vtnNode, HOST_MANAGEMENT_IP));
Hyunsun Moon153db182016-08-04 14:06:40 -0700126 if (hostsMgmt.prefix().contains(localMgmt.prefix()) ||
127 localMgmt.prefix().contains(hostsMgmt.prefix())) {
128 final String msg = "Host and local management network IP conflict";
129 throw new IllegalArgumentException(msg);
130 }
131 }
132
Hyunsun Moon187bf532017-01-19 10:57:40 +0900133 result = result && hasFields(
Hyunsun Moon153db182016-08-04 14:06:40 -0700134 (ObjectNode) object.get(SSH),
135 SSH_PORT,
136 SSH_USER,
137 SSH_KEY_FILE);
Hyunsun Moon187bf532017-01-19 10:57:40 +0900138 result = result && isTpPort(
Hyunsun Moon153db182016-08-04 14:06:40 -0700139 (ObjectNode) object.get(SSH),
140 SSH_PORT,
141 MANDATORY);
142
Hyunsun Moon153db182016-08-04 14:06:40 -0700143 // check all optional fields are valid
Hyunsun Moon187bf532017-01-19 10:57:40 +0900144 result = result && isTpPort(OVSDB_PORT, OPTIONAL);
Hyunsun Moon153db182016-08-04 14:06:40 -0700145
146 if (object.get(PUBLIC_GATEWAYS) != null && object.get(PUBLIC_GATEWAYS).isArray()) {
147 for (JsonNode node : object.get(PUBLIC_GATEWAYS)) {
148 ObjectNode gateway = (ObjectNode) node;
Hyunsun Moon187bf532017-01-19 10:57:40 +0900149 result = result && isIpAddress(gateway, GATEWAY_IP, MANDATORY);
150 result = result && isMacAddress(gateway, GATEWAY_MAC, MANDATORY);
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800151 }
152 }
153
154 if (object.get(CONTROLLERS) != null) {
155 for (JsonNode jsonNode : object.get(CONTROLLERS)) {
Hyunsun Moon187bf532017-01-19 10:57:40 +0900156 result = result && isController(jsonNode);
Hyunsun Moon153db182016-08-04 14:06:40 -0700157 }
158 }
159 return result;
160 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700161
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800162 private boolean isController(JsonNode jsonNode) {
163 String[] ctrl = jsonNode.asText().split(":");
164 final String error = "Malformed controller string " + jsonNode.asText() +
165 ". Controller only takes a list of 'IP:port', 'IP', " +
166 "or just one ':port'.";
167 try {
168 if (ctrl.length == 1) {
169 IpAddress.valueOf(ctrl[INDEX_IP]);
170 return true;
171 }
172 if (ctrl.length == 2 && ctrl[INDEX_IP].isEmpty() &&
173 object.get(CONTROLLERS).size() == 1) {
174 TpPort.tpPort(Integer.valueOf(ctrl[INDEX_PORT]));
175 return true;
176 }
177 if (ctrl.length == 2 && !ctrl[INDEX_IP].isEmpty()) {
178 IpAddress.valueOf(ctrl[INDEX_IP]);
179 TpPort.tpPort(Integer.valueOf(ctrl[INDEX_PORT]));
180 return true;
181 }
182 throw new InvalidFieldException(CONTROLLERS, error);
183 } catch (IllegalArgumentException e) {
184 throw new InvalidFieldException(CONTROLLERS, error);
185 }
186 }
187
Hyunsun Moone9d75992015-09-15 22:39:16 -0700188 /**
Hyunsun Moon4edb0172015-11-07 22:08:43 -0800189 * Returns the set of nodes read from network config.
Hyunsun Moone9d75992015-09-15 22:39:16 -0700190 *
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800191 * @return set of CordVtnNodeConfig or empty set
Hyunsun Moone9d75992015-09-15 22:39:16 -0700192 */
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800193 public Set<CordVtnNode> cordVtnNodes() {
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800194 Set<CordVtnNode> nodes = Sets.newHashSet();
Hyunsun Moon61e79ee2016-04-14 19:04:23 -0700195 JsonNode sshNode = object.get(SSH);
Hyunsun Moon153db182016-08-04 14:06:40 -0700196 String ovsdbPort = getConfig(object, OVSDB_PORT);
Hyunsun Moon61e79ee2016-04-14 19:04:23 -0700197
Hyunsun Moon153db182016-08-04 14:06:40 -0700198 object.get(CORDVTN_NODES).forEach(vtnNode -> {
Hyunsun Moon187bf532017-01-19 10:57:40 +0900199 CidrAddr localMgmt = CidrAddr.valueOf(get(LOCAL_MANAGEMENT_IP, ""));
200 CidrAddr hostsMgmt = CidrAddr.valueOf(getConfig(vtnNode, HOST_MANAGEMENT_IP));
Hyunsun Moon0592c3d2016-06-23 14:47:52 -0700201
Hyunsun Moon81a13562016-08-04 13:48:08 -0700202 SshAccessInfo sshInfo = new SshAccessInfo(
Hyunsun Moon153db182016-08-04 14:06:40 -0700203 hostsMgmt.ip().getIp4Address(),
Hyunsun Moon81a13562016-08-04 13:48:08 -0700204 TpPort.tpPort(Integer.parseInt(getConfig(sshNode, SSH_PORT))),
Hyunsun Moon153db182016-08-04 14:06:40 -0700205 getConfig(sshNode, SSH_USER),
206 getConfig(sshNode, SSH_KEY_FILE));
Hyunsun Moon81a13562016-08-04 13:48:08 -0700207
208 CordVtnNode.Builder nodeBuilder = CordVtnNode.builder()
Hyunsun Moon153db182016-08-04 14:06:40 -0700209 .hostname(getConfig(vtnNode, HOSTNAME))
210 .hostMgmtIp(hostsMgmt)
Hyunsun Moon81a13562016-08-04 13:48:08 -0700211 .localMgmtIp(localMgmt)
Hyunsun Moon153db182016-08-04 14:06:40 -0700212 .dataIp(getConfig(vtnNode, DATA_IP))
Hyunsun Moon81a13562016-08-04 13:48:08 -0700213 .sshInfo(sshInfo)
Hyunsun Moon153db182016-08-04 14:06:40 -0700214 .integrationBridgeId(getConfig(vtnNode, INTEGRATION_BRIDGE_ID))
215 .dataIface(getConfig(vtnNode, DATA_IFACE));
Hyunsun Moon81a13562016-08-04 13:48:08 -0700216
Hyunsun Moon81a13562016-08-04 13:48:08 -0700217 if (!Strings.isNullOrEmpty(ovsdbPort)) {
218 nodeBuilder.ovsdbPort(Integer.parseInt(ovsdbPort));
219 }
220
Hyunsun Moon153db182016-08-04 14:06:40 -0700221 String hostMgmtIface = getConfig(vtnNode, HOST_MANAGEMENT_IFACE);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700222 if (!Strings.isNullOrEmpty(hostMgmtIface)) {
223 nodeBuilder.hostMgmtIface(hostMgmtIface);
224 }
225
226 nodes.add(nodeBuilder.build());
Hyunsun Moon153db182016-08-04 14:06:40 -0700227 });
228
Hyunsun Moon4edb0172015-11-07 22:08:43 -0800229 return nodes;
Hyunsun Moone9d75992015-09-15 22:39:16 -0700230 }
231
232 /**
Hyunsun Moon153db182016-08-04 14:06:40 -0700233 * Gets the specified property as a string.
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800234 *
Hyunsun Moon153db182016-08-04 14:06:40 -0700235 * @param jsonNode node whose fields to get
236 * @param path property to get
237 * @return value as a string
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800238 */
239 private String getConfig(JsonNode jsonNode, String path) {
240 jsonNode = jsonNode.path(path);
Hyunsun Moon153db182016-08-04 14:06:40 -0700241 return jsonNode.asText();
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800242 }
243
244 /**
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800245 * Returns private network gateway MAC address.
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800246 *
Hyunsun Moon153db182016-08-04 14:06:40 -0700247 * @return mac address
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800248 */
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800249 public MacAddress privateGatewayMac() {
250 JsonNode jsonNode = object.get(PRIVATE_GATEWAY_MAC);
Hyunsun Moon153db182016-08-04 14:06:40 -0700251 return MacAddress.valueOf(jsonNode.asText());
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800252 }
253
254 /**
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800255 * Returns public network gateway IP and MAC address pairs.
256 *
257 * @return map of ip and mac address
258 */
259 public Map<IpAddress, MacAddress> publicGateways() {
260 JsonNode jsonNodes = object.get(PUBLIC_GATEWAYS);
Hyunsun Moon153db182016-08-04 14:06:40 -0700261 Map<IpAddress, MacAddress> publicGateways = Maps.newHashMap();
262
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800263 if (jsonNodes == null) {
Hyunsun Moon153db182016-08-04 14:06:40 -0700264 return publicGateways;
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800265 }
266
Hyunsun Moon153db182016-08-04 14:06:40 -0700267 jsonNodes.forEach(jsonNode -> publicGateways.put(
268 IpAddress.valueOf(jsonNode.path(GATEWAY_IP).asText()),
269 MacAddress.valueOf(jsonNode.path(GATEWAY_MAC).asText())));
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800270 return publicGateways;
271 }
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800272
Hyunsun Moon4a94c2e2016-10-21 17:37:05 -0700273 /**
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800274 * Returns controllers for the integration bridge.
275 * It returns the information taken from cluster service with the default OF
276 * port if no controller is specified in the network config.
277 *
278 * @return list of controller information
279 */
280 public List<ControllerInfo> controllers() {
281 List<ControllerInfo> ctrls = Lists.newArrayList();
282 JsonNode ctrlNodes = object.get(CONTROLLERS);
283
284 if (ctrlNodes == null || isCtrlPortOnly()) {
285 ctrls = clusterService.getNodes().stream()
286 .map(ctrl -> new ControllerInfo(
287 ctrl.ip(),
288 ctrlNodes == null ? DEFAULT_OF_PORT : getCtrlPort(),
289 DEFAULT_OF_PROTOCOL))
290 .collect(Collectors.toList());
291 } else {
292 for (JsonNode ctrlNode : ctrlNodes) {
293 String[] ctrl = ctrlNode.asText().split(":");
294 ctrls.add(new ControllerInfo(
295 IpAddress.valueOf(ctrl[INDEX_IP]),
296 ctrl.length == 1 ? DEFAULT_OF_PORT :
297 Integer.parseInt(ctrl[INDEX_PORT]),
298 DEFAULT_OF_PROTOCOL));
299 }
300 }
301 return ImmutableList.copyOf(ctrls);
302 }
303
304 private boolean isCtrlPortOnly() {
305 if (object.get(CONTROLLERS).size() != 1) {
306 return false;
307 }
308 JsonNode jsonNode = object.get(CONTROLLERS).get(0);
309 String[] ctrl = jsonNode.asText().split(":");
310 return ctrl.length == 2 && ctrl[INDEX_IP].isEmpty();
311 }
312
313 private int getCtrlPort() {
314 JsonNode jsonNode = object.get(CONTROLLERS).get(0);
315 String[] ctrl = jsonNode.asText().split(":");
316 return Integer.parseInt(ctrl[INDEX_PORT]);
317 }
Hyunsun Moon61e79ee2016-04-14 19:04:23 -0700318}