blob: 7dea4158f9af9ef4a080d1b94637e4ea0406f45f [file] [log] [blame]
Hyunsun Moone9d75992015-09-15 22:39:16 -07001/*
Brian O'Connor80dff972017-08-03 22:46:30 -07002 * Copyright 2015-present Open Networking Foundation
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 Moon2c3f0ee2017-04-06 16:47:21 +090031import org.onosproject.net.DeviceId;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080032import org.onosproject.net.behaviour.ControllerInfo;
Hyunsun Moone9d75992015-09-15 22:39:16 -070033import org.onosproject.net.config.Config;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080034import org.onosproject.net.config.InvalidFieldException;
Hyunsun Moon187bf532017-01-19 10:57:40 +090035import org.opencord.cordvtn.api.net.CidrAddr;
Hyunsun Moonfd5a24e2016-10-19 19:15:48 -070036import org.opencord.cordvtn.api.node.CordVtnNode;
Hyunsun Moonfd5a24e2016-10-19 19:15:48 -070037import org.opencord.cordvtn.api.node.SshAccessInfo;
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +090038import org.opencord.cordvtn.impl.DefaultCordVtnNode;
Hyunsun Moon3fc17f72016-01-24 21:47:06 -080039import org.slf4j.Logger;
Hyunsun Moone9d75992015-09-15 22:39:16 -070040
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080041import java.util.List;
Hyunsun Moonb5f92e52016-02-17 15:02:06 -080042import java.util.Map;
Hyunsun Moone9d75992015-09-15 22:39:16 -070043import java.util.Set;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080044import java.util.stream.Collectors;
Hyunsun Moone9d75992015-09-15 22:39:16 -070045
Hyunsun Moon153db182016-08-04 14:06:40 -070046import static org.onosproject.net.config.Config.FieldPresence.MANDATORY;
47import static org.onosproject.net.config.Config.FieldPresence.OPTIONAL;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080048import static org.opencord.cordvtn.api.Constants.DEFAULT_OF_PORT;
49import static org.opencord.cordvtn.api.Constants.DEFAULT_OF_PROTOCOL;
Hyunsun Moon3fc17f72016-01-24 21:47:06 -080050import static org.slf4j.LoggerFactory.getLogger;
Hyunsun Moone9d75992015-09-15 22:39:16 -070051
52/**
Hyunsun Moon9661d642015-09-23 13:24:35 -070053 * Configuration object for CordVtn service.
Hyunsun Moone9d75992015-09-15 22:39:16 -070054 */
55public class CordVtnConfig extends Config<ApplicationId> {
56
Hyunsun Moon3fc17f72016-01-24 21:47:06 -080057 protected final Logger log = getLogger(getClass());
58
Hyunsun Moonbcf49252017-02-21 22:28:41 +090059 @Deprecated
Hyunsun Moon60a10672016-06-12 17:39:12 -070060 private static final String PRIVATE_GATEWAY_MAC = "privateGatewayMac";
61 private static final String PUBLIC_GATEWAYS = "publicGateways";
62 private static final String GATEWAY_IP = "gatewayIp";
63 private static final String GATEWAY_MAC = "gatewayMac";
64 private static final String LOCAL_MANAGEMENT_IP = "localManagementIp";
65 private static final String OVSDB_PORT = "ovsdbPort";
Hyunsun Moond05b32e2016-03-02 19:27:26 -080066
Hyunsun Moon60a10672016-06-12 17:39:12 -070067 private static final String CORDVTN_NODES = "nodes";
68 private static final String HOSTNAME = "hostname";
69 private static final String HOST_MANAGEMENT_IP = "hostManagementIp";
Hyunsun Moon81a13562016-08-04 13:48:08 -070070 private static final String HOST_MANAGEMENT_IFACE = "hostManagementIface";
71 private static final String DATA_IP = "dataPlaneIp";
72 private static final String DATA_IFACE = "dataPlaneIntf";
73 private static final String INTEGRATION_BRIDGE_ID = "bridgeId";
Hyunsun Moone9d75992015-09-15 22:39:16 -070074
Hyunsun Moon60a10672016-06-12 17:39:12 -070075 private static final String SSH = "ssh";
76 private static final String SSH_PORT = "sshPort";
77 private static final String SSH_USER = "sshUser";
78 private static final String SSH_KEY_FILE = "sshKeyFile";
Hyunsun Moon61e79ee2016-04-14 19:04:23 -070079
Hyunsun Moon187bf532017-01-19 10:57:40 +090080 @Deprecated
Hyunsun Moon60a10672016-06-12 17:39:12 -070081 private static final String OPENSTACK = "openstack";
Hyunsun Moon187bf532017-01-19 10:57:40 +090082 @Deprecated
Hyunsun Moon60a10672016-06-12 17:39:12 -070083 private static final String XOS = "xos";
Hyunsun Moon61e79ee2016-04-14 19:04:23 -070084
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080085 private static final String CONTROLLERS = "controllers";
86 private static final int INDEX_IP = 0;
87 private static final int INDEX_PORT = 1;
88
89 private final ClusterService clusterService =
90 DefaultServiceDirectory.getService(ClusterService.class);
91
Hyunsun Moon153db182016-08-04 14:06:40 -070092 @Override
93 public boolean isValid() {
94 // check only allowed fields are present
95 boolean result = hasOnlyFields(
96 PRIVATE_GATEWAY_MAC,
97 PUBLIC_GATEWAYS,
98 LOCAL_MANAGEMENT_IP,
99 OVSDB_PORT,
100 SSH,
101 OPENSTACK,
102 XOS,
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800103 CORDVTN_NODES,
104 CONTROLLERS);
Hyunsun Moon153db182016-08-04 14:06:40 -0700105
106 if (object.get(CORDVTN_NODES) == null || object.get(CORDVTN_NODES).size() < 1) {
107 final String msg = "No node is present";
108 throw new IllegalArgumentException(msg);
109 }
110
111 // check all mandatory fields are present and valid
Hyunsun Moon187bf532017-01-19 10:57:40 +0900112 result = result && isIpPrefix(LOCAL_MANAGEMENT_IP, MANDATORY);
Hyunsun Moon153db182016-08-04 14:06:40 -0700113
114 for (JsonNode node : object.get(CORDVTN_NODES)) {
115 ObjectNode vtnNode = (ObjectNode) node;
Hyunsun Moon187bf532017-01-19 10:57:40 +0900116 result = result && hasFields(
Hyunsun Moon153db182016-08-04 14:06:40 -0700117 vtnNode,
118 HOSTNAME,
119 HOST_MANAGEMENT_IP,
120 DATA_IP,
121 DATA_IFACE,
122 INTEGRATION_BRIDGE_ID);
Hyunsun Moon187bf532017-01-19 10:57:40 +0900123 result = result && isIpPrefix(vtnNode, HOST_MANAGEMENT_IP, MANDATORY);
124 result = result && isIpPrefix(vtnNode, DATA_IP, MANDATORY);
Hyunsun Moon153db182016-08-04 14:06:40 -0700125
Hyunsun Moon187bf532017-01-19 10:57:40 +0900126 CidrAddr localMgmt = CidrAddr.valueOf(get(LOCAL_MANAGEMENT_IP, ""));
127 CidrAddr hostsMgmt = CidrAddr.valueOf(getConfig(vtnNode, HOST_MANAGEMENT_IP));
Hyunsun Moon153db182016-08-04 14:06:40 -0700128 if (hostsMgmt.prefix().contains(localMgmt.prefix()) ||
129 localMgmt.prefix().contains(hostsMgmt.prefix())) {
130 final String msg = "Host and local management network IP conflict";
131 throw new IllegalArgumentException(msg);
132 }
133 }
134
Hyunsun Moon187bf532017-01-19 10:57:40 +0900135 result = result && hasFields(
Hyunsun Moon153db182016-08-04 14:06:40 -0700136 (ObjectNode) object.get(SSH),
137 SSH_PORT,
138 SSH_USER,
139 SSH_KEY_FILE);
Hyunsun Moon187bf532017-01-19 10:57:40 +0900140 result = result && isTpPort(
Hyunsun Moon153db182016-08-04 14:06:40 -0700141 (ObjectNode) object.get(SSH),
142 SSH_PORT,
143 MANDATORY);
144
Hyunsun Moon153db182016-08-04 14:06:40 -0700145 // check all optional fields are valid
Hyunsun Moon187bf532017-01-19 10:57:40 +0900146 result = result && isTpPort(OVSDB_PORT, OPTIONAL);
Hyunsun Moon153db182016-08-04 14:06:40 -0700147
148 if (object.get(PUBLIC_GATEWAYS) != null && object.get(PUBLIC_GATEWAYS).isArray()) {
149 for (JsonNode node : object.get(PUBLIC_GATEWAYS)) {
150 ObjectNode gateway = (ObjectNode) node;
Hyunsun Moon187bf532017-01-19 10:57:40 +0900151 result = result && isIpAddress(gateway, GATEWAY_IP, MANDATORY);
152 result = result && isMacAddress(gateway, GATEWAY_MAC, MANDATORY);
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800153 }
154 }
155
156 if (object.get(CONTROLLERS) != null) {
157 for (JsonNode jsonNode : object.get(CONTROLLERS)) {
Hyunsun Moon187bf532017-01-19 10:57:40 +0900158 result = result && isController(jsonNode);
Hyunsun Moon153db182016-08-04 14:06:40 -0700159 }
160 }
161 return result;
162 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700163
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800164 private boolean isController(JsonNode jsonNode) {
165 String[] ctrl = jsonNode.asText().split(":");
166 final String error = "Malformed controller string " + jsonNode.asText() +
167 ". Controller only takes a list of 'IP:port', 'IP', " +
168 "or just one ':port'.";
169 try {
170 if (ctrl.length == 1) {
171 IpAddress.valueOf(ctrl[INDEX_IP]);
172 return true;
173 }
174 if (ctrl.length == 2 && ctrl[INDEX_IP].isEmpty() &&
175 object.get(CONTROLLERS).size() == 1) {
176 TpPort.tpPort(Integer.valueOf(ctrl[INDEX_PORT]));
177 return true;
178 }
179 if (ctrl.length == 2 && !ctrl[INDEX_IP].isEmpty()) {
180 IpAddress.valueOf(ctrl[INDEX_IP]);
181 TpPort.tpPort(Integer.valueOf(ctrl[INDEX_PORT]));
182 return true;
183 }
184 throw new InvalidFieldException(CONTROLLERS, error);
185 } catch (IllegalArgumentException e) {
186 throw new InvalidFieldException(CONTROLLERS, error);
187 }
188 }
189
Hyunsun Moone9d75992015-09-15 22:39:16 -0700190 /**
Hyunsun Moon4edb0172015-11-07 22:08:43 -0800191 * Returns the set of nodes read from network config.
Hyunsun Moone9d75992015-09-15 22:39:16 -0700192 *
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800193 * @return set of CordVtnNodeConfig or empty set
Hyunsun Moone9d75992015-09-15 22:39:16 -0700194 */
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800195 public Set<CordVtnNode> cordVtnNodes() {
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800196 Set<CordVtnNode> nodes = Sets.newHashSet();
Hyunsun Moon61e79ee2016-04-14 19:04:23 -0700197 JsonNode sshNode = object.get(SSH);
Hyunsun Moon153db182016-08-04 14:06:40 -0700198 String ovsdbPort = getConfig(object, OVSDB_PORT);
Hyunsun Moon61e79ee2016-04-14 19:04:23 -0700199
Hyunsun Moon153db182016-08-04 14:06:40 -0700200 object.get(CORDVTN_NODES).forEach(vtnNode -> {
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900201 CidrAddr localMgmtIp = CidrAddr.valueOf(get(LOCAL_MANAGEMENT_IP, ""));
202 CidrAddr hostsMgmtIp = CidrAddr.valueOf(getConfig(vtnNode, HOST_MANAGEMENT_IP));
Hyunsun Moon0592c3d2016-06-23 14:47:52 -0700203
Hyunsun Moon81a13562016-08-04 13:48:08 -0700204 SshAccessInfo sshInfo = new SshAccessInfo(
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900205 hostsMgmtIp.ip().getIp4Address(),
Hyunsun Moon81a13562016-08-04 13:48:08 -0700206 TpPort.tpPort(Integer.parseInt(getConfig(sshNode, SSH_PORT))),
Hyunsun Moon153db182016-08-04 14:06:40 -0700207 getConfig(sshNode, SSH_USER),
208 getConfig(sshNode, SSH_KEY_FILE));
Hyunsun Moon81a13562016-08-04 13:48:08 -0700209
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900210 CordVtnNode.Builder nodeBuilder = DefaultCordVtnNode.builder()
Hyunsun Moon153db182016-08-04 14:06:40 -0700211 .hostname(getConfig(vtnNode, HOSTNAME))
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900212 .hostManagementIp(hostsMgmtIp)
213 .localManagementIp(localMgmtIp)
214 .dataIp(CidrAddr.valueOf(getConfig(vtnNode, DATA_IP)))
Hyunsun Moon81a13562016-08-04 13:48:08 -0700215 .sshInfo(sshInfo)
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900216 .integrationBridgeId(DeviceId.deviceId(getConfig(vtnNode, INTEGRATION_BRIDGE_ID)))
217 .dataInterface(getConfig(vtnNode, DATA_IFACE));
Hyunsun Moon81a13562016-08-04 13:48:08 -0700218
Hyunsun Moon81a13562016-08-04 13:48:08 -0700219 if (!Strings.isNullOrEmpty(ovsdbPort)) {
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900220 nodeBuilder.ovsdbPort(TpPort.tpPort(Integer.parseInt(ovsdbPort)));
Hyunsun Moon81a13562016-08-04 13:48:08 -0700221 }
222
Hyunsun Moon153db182016-08-04 14:06:40 -0700223 String hostMgmtIface = getConfig(vtnNode, HOST_MANAGEMENT_IFACE);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700224 if (!Strings.isNullOrEmpty(hostMgmtIface)) {
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900225 nodeBuilder.hostManagementInterface(hostMgmtIface);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700226 }
227
228 nodes.add(nodeBuilder.build());
Hyunsun Moon153db182016-08-04 14:06:40 -0700229 });
230
Hyunsun Moon4edb0172015-11-07 22:08:43 -0800231 return nodes;
Hyunsun Moone9d75992015-09-15 22:39:16 -0700232 }
233
234 /**
Hyunsun Moon153db182016-08-04 14:06:40 -0700235 * Gets the specified property as a string.
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800236 *
Hyunsun Moon153db182016-08-04 14:06:40 -0700237 * @param jsonNode node whose fields to get
238 * @param path property to get
239 * @return value as a string
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800240 */
241 private String getConfig(JsonNode jsonNode, String path) {
242 jsonNode = jsonNode.path(path);
Hyunsun Moon153db182016-08-04 14:06:40 -0700243 return jsonNode.asText();
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800244 }
245
246 /**
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800247 * Returns public network gateway IP and MAC address pairs.
248 *
249 * @return map of ip and mac address
250 */
251 public Map<IpAddress, MacAddress> publicGateways() {
252 JsonNode jsonNodes = object.get(PUBLIC_GATEWAYS);
Hyunsun Moon153db182016-08-04 14:06:40 -0700253 Map<IpAddress, MacAddress> publicGateways = Maps.newHashMap();
254
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800255 if (jsonNodes == null) {
Hyunsun Moon153db182016-08-04 14:06:40 -0700256 return publicGateways;
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800257 }
258
Hyunsun Moon153db182016-08-04 14:06:40 -0700259 jsonNodes.forEach(jsonNode -> publicGateways.put(
260 IpAddress.valueOf(jsonNode.path(GATEWAY_IP).asText()),
261 MacAddress.valueOf(jsonNode.path(GATEWAY_MAC).asText())));
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800262 return publicGateways;
263 }
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800264
Hyunsun Moon4a94c2e2016-10-21 17:37:05 -0700265 /**
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800266 * Returns controllers for the integration bridge.
267 * It returns the information taken from cluster service with the default OF
268 * port if no controller is specified in the network config.
269 *
270 * @return list of controller information
271 */
272 public List<ControllerInfo> controllers() {
273 List<ControllerInfo> ctrls = Lists.newArrayList();
274 JsonNode ctrlNodes = object.get(CONTROLLERS);
275
276 if (ctrlNodes == null || isCtrlPortOnly()) {
277 ctrls = clusterService.getNodes().stream()
278 .map(ctrl -> new ControllerInfo(
279 ctrl.ip(),
280 ctrlNodes == null ? DEFAULT_OF_PORT : getCtrlPort(),
281 DEFAULT_OF_PROTOCOL))
282 .collect(Collectors.toList());
283 } else {
284 for (JsonNode ctrlNode : ctrlNodes) {
285 String[] ctrl = ctrlNode.asText().split(":");
286 ctrls.add(new ControllerInfo(
287 IpAddress.valueOf(ctrl[INDEX_IP]),
288 ctrl.length == 1 ? DEFAULT_OF_PORT :
289 Integer.parseInt(ctrl[INDEX_PORT]),
290 DEFAULT_OF_PROTOCOL));
291 }
292 }
293 return ImmutableList.copyOf(ctrls);
294 }
295
296 private boolean isCtrlPortOnly() {
297 if (object.get(CONTROLLERS).size() != 1) {
298 return false;
299 }
300 JsonNode jsonNode = object.get(CONTROLLERS).get(0);
301 String[] ctrl = jsonNode.asText().split(":");
302 return ctrl.length == 2 && ctrl[INDEX_IP].isEmpty();
303 }
304
305 private int getCtrlPort() {
306 JsonNode jsonNode = object.get(CONTROLLERS).get(0);
307 String[] ctrl = jsonNode.asText().split(":");
308 return Integer.parseInt(ctrl[INDEX_PORT]);
309 }
Hyunsun Moon61e79ee2016-04-14 19:04:23 -0700310}