blob: cb78448f2e6d65539afa5d87a38c2c19fd24c598 [file] [log] [blame]
Jian Li091d8d22018-02-20 10:42:06 +09001/*
2 * Copyright 2018-present Open Networking Foundation
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 */
16package org.onosproject.openstacknetworking.util;
17
Daniel Park2ff66b42018-08-01 11:52:45 +090018import com.fasterxml.jackson.core.JsonParseException;
19import com.fasterxml.jackson.core.JsonProcessingException;
20import com.fasterxml.jackson.databind.JsonMappingException;
Jian Li091d8d22018-02-20 10:42:06 +090021import com.fasterxml.jackson.databind.JsonNode;
22import com.fasterxml.jackson.databind.ObjectMapper;
Jian Lic55a74f2020-05-11 13:05:47 +090023import com.fasterxml.jackson.databind.node.ArrayNode;
Jian Lieb9f77d2018-02-20 11:25:45 +090024import com.fasterxml.jackson.databind.node.ObjectNode;
Daniel Parka73c2362018-09-17 17:43:25 +090025import com.google.common.base.Charsets;
Jian Li24ec59f2018-05-23 19:01:25 +090026import com.google.common.base.Strings;
Daniel Parka73c2362018-09-17 17:43:25 +090027import com.google.common.collect.Lists;
Jian Li63430202018-08-30 16:24:09 +090028import org.apache.commons.codec.binary.Hex;
Jian Li51728702019-05-17 18:38:56 +090029import org.apache.commons.lang3.StringUtils;
Jian Lif654dd12020-01-30 17:41:26 +090030import org.apache.commons.net.util.SubnetUtils;
Jian Li63430202018-08-30 16:24:09 +090031import org.apache.http.HttpException;
32import org.apache.http.HttpRequest;
33import org.apache.http.HttpResponse;
34import org.apache.http.impl.io.DefaultHttpRequestParser;
35import org.apache.http.impl.io.DefaultHttpRequestWriter;
36import org.apache.http.impl.io.DefaultHttpResponseParser;
37import org.apache.http.impl.io.DefaultHttpResponseWriter;
38import org.apache.http.impl.io.HttpTransportMetricsImpl;
39import org.apache.http.impl.io.SessionInputBufferImpl;
40import org.apache.http.impl.io.SessionOutputBufferImpl;
41import org.apache.http.io.HttpMessageWriter;
Daniel Parka73c2362018-09-17 17:43:25 +090042import org.apache.sshd.client.SshClient;
43import org.apache.sshd.client.channel.ClientChannel;
44import org.apache.sshd.client.channel.ClientChannelEvent;
45import org.apache.sshd.client.future.OpenFuture;
46import org.apache.sshd.client.session.ClientSession;
47import org.apache.sshd.common.util.io.NoCloseInputStream;
Jian Li7b8c3682019-05-12 13:57:15 +090048import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090049import org.onlab.packet.ARP;
50import org.onlab.packet.Ethernet;
51import org.onlab.packet.Ip4Address;
Daniel Parka73c2362018-09-17 17:43:25 +090052import org.onlab.packet.IpAddress;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090053import org.onlab.packet.MacAddress;
54import org.onlab.packet.VlanId;
Jian Li7f70bb72018-07-06 23:35:30 +090055import org.onosproject.cfg.ConfigProperty;
Jian Li1064e4f2018-05-29 16:16:53 +090056import org.onosproject.net.DeviceId;
Jian Li2d68c192018-12-13 15:52:59 +090057import org.onosproject.net.PortNumber;
Daniel Park95f73312018-07-31 15:48:34 +090058import org.onosproject.net.device.DeviceService;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090059import org.onosproject.net.flow.DefaultTrafficTreatment;
60import org.onosproject.net.flow.TrafficTreatment;
Jian Lie87c2712019-09-11 11:15:16 +090061import org.onosproject.net.group.DefaultGroupKey;
62import org.onosproject.net.group.GroupKey;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090063import org.onosproject.net.packet.DefaultOutboundPacket;
64import org.onosproject.net.packet.PacketService;
Daniel Park7e8c4d82018-08-13 23:47:49 +090065import org.onosproject.openstacknetworking.api.Constants.VnicType;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090066import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Jian Lia171a432018-06-11 11:52:11 +090067import org.onosproject.openstacknetworking.api.InstancePort;
Jian Li7b8c3682019-05-12 13:57:15 +090068import org.onosproject.openstacknetworking.api.OpenstackHaService;
SONA Project6bc5c4a2018-12-14 23:49:52 +090069import org.onosproject.openstacknetworking.api.OpenstackNetwork.Type;
Jian Li24ec59f2018-05-23 19:01:25 +090070import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Li7f70bb72018-07-06 23:35:30 +090071import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
Jian Liebde74d2018-11-14 00:18:57 +090072import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Jian Liec5c32b2018-07-13 14:28:58 +090073import org.onosproject.openstacknetworking.impl.DefaultInstancePort;
Jian Li51b844c2018-05-31 10:59:03 +090074import org.onosproject.openstacknode.api.OpenstackAuth;
75import org.onosproject.openstacknode.api.OpenstackAuth.Perspective;
Jian Li1064e4f2018-05-29 16:16:53 +090076import org.onosproject.openstacknode.api.OpenstackNode;
Daniel Parka73c2362018-09-17 17:43:25 +090077import org.onosproject.openstacknode.api.OpenstackSshAuth;
Jian Li51728702019-05-17 18:38:56 +090078import org.onosproject.ovsdb.controller.OvsdbClientService;
79import org.onosproject.ovsdb.controller.OvsdbController;
80import org.onosproject.ovsdb.controller.OvsdbNodeId;
Jian Li51b844c2018-05-31 10:59:03 +090081import org.openstack4j.api.OSClient;
82import org.openstack4j.api.client.IOSClientBuilder;
83import org.openstack4j.api.exceptions.AuthenticationException;
84import org.openstack4j.api.types.Facing;
85import org.openstack4j.core.transport.Config;
Jian Li091d8d22018-02-20 10:42:06 +090086import org.openstack4j.core.transport.ObjectMapperSingleton;
87import org.openstack4j.model.ModelEntity;
Jian Li51b844c2018-05-31 10:59:03 +090088import org.openstack4j.model.common.Identifier;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090089import org.openstack4j.model.network.ExternalGateway;
Jian Liecbf10c2019-10-02 20:36:09 +090090import org.openstack4j.model.network.IP;
Jian Li24ec59f2018-05-23 19:01:25 +090091import org.openstack4j.model.network.NetFloatingIP;
92import org.openstack4j.model.network.Network;
Jian Lia171a432018-06-11 11:52:11 +090093import org.openstack4j.model.network.Port;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090094import org.openstack4j.model.network.Router;
Jian Li0b564282018-06-20 00:50:53 +090095import org.openstack4j.model.network.RouterInterface;
Jian Liecbf10c2019-10-02 20:36:09 +090096import org.openstack4j.model.network.SecurityGroup;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090097import org.openstack4j.model.network.Subnet;
Jian Li51b844c2018-05-31 10:59:03 +090098import org.openstack4j.openstack.OSFactory;
Jian Lic55a74f2020-05-11 13:05:47 +090099import org.openstack4j.openstack.networking.domain.NeutronPort;
Jian Li0b564282018-06-20 00:50:53 +0900100import org.openstack4j.openstack.networking.domain.NeutronRouterInterface;
Jian Li091d8d22018-02-20 10:42:06 +0900101import org.slf4j.Logger;
102import org.slf4j.LoggerFactory;
103
Jian Li63430202018-08-30 16:24:09 +0900104import javax.crypto.Mac;
105import javax.crypto.spec.SecretKeySpec;
Jian Li51b844c2018-05-31 10:59:03 +0900106import javax.net.ssl.HostnameVerifier;
107import javax.net.ssl.HttpsURLConnection;
108import javax.net.ssl.SSLContext;
109import javax.net.ssl.TrustManager;
110import javax.net.ssl.X509TrustManager;
Jian Li7b8c3682019-05-12 13:57:15 +0900111import javax.ws.rs.client.Client;
112import javax.ws.rs.client.ClientBuilder;
113import javax.ws.rs.client.Entity;
114import javax.ws.rs.client.WebTarget;
115import javax.ws.rs.core.Response;
Jian Li63430202018-08-30 16:24:09 +0900116import java.io.ByteArrayInputStream;
117import java.io.ByteArrayOutputStream;
Jian Li0b564282018-06-20 00:50:53 +0900118import java.io.IOException;
Jian Li091d8d22018-02-20 10:42:06 +0900119import java.io.InputStream;
Daniel Parka73c2362018-09-17 17:43:25 +0900120import java.io.OutputStream;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900121import java.nio.ByteBuffer;
Jian Li51b844c2018-05-31 10:59:03 +0900122import java.security.cert.X509Certificate;
Daniel Parka73c2362018-09-17 17:43:25 +0900123import java.util.Collection;
Jian Li1064e4f2018-05-29 16:16:53 +0900124import java.util.HashMap;
125import java.util.Iterator;
Jian Liecbf10c2019-10-02 20:36:09 +0900126import java.util.List;
Jian Li1064e4f2018-05-29 16:16:53 +0900127import java.util.Map;
Daniel Park95f73312018-07-31 15:48:34 +0900128import java.util.Objects;
Jian Li7f70bb72018-07-06 23:35:30 +0900129import java.util.Optional;
Jian Li1064e4f2018-05-29 16:16:53 +0900130import java.util.Set;
131import java.util.TreeMap;
Daniel Parka73c2362018-09-17 17:43:25 +0900132import java.util.concurrent.TimeUnit;
Jian Liecbf10c2019-10-02 20:36:09 +0900133import java.util.stream.Collectors;
Jian Li091d8d22018-02-20 10:42:06 +0900134
135import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
Daniel Park95f73312018-07-31 15:48:34 +0900136import static com.google.common.base.Preconditions.checkNotNull;
Jian Li7f024de2018-07-07 03:51:02 +0900137import static com.google.common.base.Strings.isNullOrEmpty;
Jian Li7b8c3682019-05-12 13:57:15 +0900138import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
139import static org.apache.commons.io.IOUtils.toInputStream;
Jian Li5ecfd1a2018-12-10 11:41:03 +0900140import static org.onlab.packet.Ip4Address.valueOf;
Daniel Park95f73312018-07-31 15:48:34 +0900141import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Daniel Parka73c2362018-09-17 17:43:25 +0900142import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC_STR;
Jian Lia97cec42019-10-31 22:24:17 +0900143import static org.onosproject.openstacknetworking.api.Constants.DIRECT;
Jian Liecbf10c2019-10-02 20:36:09 +0900144import static org.onosproject.openstacknetworking.api.Constants.FLOATING_IP_FORMAT;
145import static org.onosproject.openstacknetworking.api.Constants.NETWORK_FORMAT;
Jian Li7b8c3682019-05-12 13:57:15 +0900146import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_REST_PATH;
Daniel Parkc4d06402018-05-28 15:57:37 +0900147import static org.onosproject.openstacknetworking.api.Constants.PCISLOT;
148import static org.onosproject.openstacknetworking.api.Constants.PCI_VENDOR_INFO;
Jian Liecbf10c2019-10-02 20:36:09 +0900149import static org.onosproject.openstacknetworking.api.Constants.PORT_FORMAT;
Daniel Park7e8c4d82018-08-13 23:47:49 +0900150import static org.onosproject.openstacknetworking.api.Constants.PORT_NAME_PREFIX_VM;
151import static org.onosproject.openstacknetworking.api.Constants.PORT_NAME_VHOST_USER_PREFIX_VM;
Jian Li7b8c3682019-05-12 13:57:15 +0900152import static org.onosproject.openstacknetworking.api.Constants.REST_PASSWORD;
153import static org.onosproject.openstacknetworking.api.Constants.REST_PORT;
154import static org.onosproject.openstacknetworking.api.Constants.REST_USER;
155import static org.onosproject.openstacknetworking.api.Constants.REST_UTF8;
Jian Liecbf10c2019-10-02 20:36:09 +0900156import static org.onosproject.openstacknetworking.api.Constants.ROUTER_FORMAT;
157import static org.onosproject.openstacknetworking.api.Constants.ROUTER_INTF_FORMAT;
158import static org.onosproject.openstacknetworking.api.Constants.SECURITY_GROUP_FORMAT;
159import static org.onosproject.openstacknetworking.api.Constants.SUBNET_FORMAT;
Daniel Parkec9d1132018-08-19 11:18:03 +0900160import static org.onosproject.openstacknetworking.api.Constants.UNSUPPORTED_VENDOR;
Ray Milkey9dc57392018-06-08 08:52:31 -0700161import static org.onosproject.openstacknetworking.api.Constants.portNamePrefixMap;
Jian Li0b564282018-06-20 00:50:53 +0900162import static org.openstack4j.core.transport.ObjectMapperSingleton.getContext;
Jian Li091d8d22018-02-20 10:42:06 +0900163
164/**
165 * An utility that used in openstack networking app.
166 */
Jian Lidea0fdb2018-04-02 19:02:48 +0900167public final class OpenstackNetworkingUtil {
Jian Li091d8d22018-02-20 10:42:06 +0900168
Daniel Park95985382018-07-23 11:38:07 +0900169 private static final Logger log = LoggerFactory.getLogger(OpenstackNetworkingUtil.class);
Jian Li091d8d22018-02-20 10:42:06 +0900170
Daniel Parkc4d06402018-05-28 15:57:37 +0900171 private static final int HEX_RADIX = 16;
Jian Li51b844c2018-05-31 10:59:03 +0900172 private static final String ZERO_FUNCTION_NUMBER = "0";
Daniel Parkc4d06402018-05-28 15:57:37 +0900173 private static final String PREFIX_DEVICE_NUMBER = "s";
174 private static final String PREFIX_FUNCTION_NUMBER = "f";
175
Jian Li51b844c2018-05-31 10:59:03 +0900176 // keystone endpoint related variables
177 private static final String DOMAIN_DEFAULT = "default";
178 private static final String KEYSTONE_V2 = "v2.0";
179 private static final String KEYSTONE_V3 = "v3";
Jian Li51b844c2018-05-31 10:59:03 +0900180 private static final String SSL_TYPE = "SSL";
181
Jian Li7f024de2018-07-07 03:51:02 +0900182 private static final String PROXY_MODE = "proxy";
183 private static final String BROADCAST_MODE = "broadcast";
184
Jian Licad36c72018-09-13 17:44:54 +0900185 private static final String ENABLE = "enable";
186 private static final String DISABLE = "disable";
187
Jian Li63430202018-08-30 16:24:09 +0900188 private static final int HTTP_PAYLOAD_BUFFER = 8 * 1024;
189
190 private static final String HMAC_SHA256 = "HmacSHA256";
191
Jian Li24ec59f2018-05-23 19:01:25 +0900192 private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
193
Daniel Parka73c2362018-09-17 17:43:25 +0900194 private static final String DL_DST = "dl_dst=";
195 private static final String NW_DST = "nw_dst=";
196 private static final String DEFAULT_REQUEST_STRING = "sudo ovs-appctl ofproto/trace br-int ip";
197 private static final String IN_PORT = "in_port=";
198 private static final String NW_SRC = "nw_src=";
199 private static final String COMMA = ",";
200 private static final String TUN_ID = "tun_id=";
201
Jian Liecbf10c2019-10-02 20:36:09 +0900202 private static final String DEVICE_OWNER_GW = "network:router_gateway";
203 private static final String DEVICE_OWNER_IFACE = "network:router_interface";
204
205 private static final String NOT_AVAILABLE = "N/A";
206
Daniel Parka73c2362018-09-17 17:43:25 +0900207 private static final long TIMEOUT_MS = 5000;
208 private static final long WAIT_OUTPUT_STREAM_SECOND = 2;
209 private static final int SSH_PORT = 22;
210
Jian Li51728702019-05-17 18:38:56 +0900211 private static final int TAP_PORT_LENGTH = 11;
Jian Li62116942019-09-03 23:10:20 +0900212 private static final int PORT_NAME_MAX_LENGTH = 15;
Jian Li51728702019-05-17 18:38:56 +0900213
Jian Li091d8d22018-02-20 10:42:06 +0900214 /**
215 * Prevents object instantiation from external.
216 */
Jian Lidea0fdb2018-04-02 19:02:48 +0900217 private OpenstackNetworkingUtil() {
Jian Li091d8d22018-02-20 10:42:06 +0900218 }
219
220 /**
221 * Interprets JSON string to corresponding openstack model entity object.
222 *
Jian Li7b8c3682019-05-12 13:57:15 +0900223 * @param inputStr JSON string
Jian Li091d8d22018-02-20 10:42:06 +0900224 * @param entityClazz openstack model entity class
225 * @return openstack model entity object
226 */
Jian Li7b8c3682019-05-12 13:57:15 +0900227 public static ModelEntity jsonToModelEntity(String inputStr, Class entityClazz) {
Jian Li091d8d22018-02-20 10:42:06 +0900228 ObjectMapper mapper = new ObjectMapper();
229 try {
Jian Li7b8c3682019-05-12 13:57:15 +0900230 InputStream input = toInputStream(inputStr, REST_UTF8);
Jian Li091d8d22018-02-20 10:42:06 +0900231 JsonNode jsonTree = mapper.enable(INDENT_OUTPUT).readTree(input);
232 log.trace(new ObjectMapper().writeValueAsString(jsonTree));
233 return ObjectMapperSingleton.getContext(entityClazz)
234 .readerFor(entityClazz)
235 .readValue(jsonTree);
236 } catch (Exception e) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900237 log.error("Exception occurred because of {}", e);
Jian Li091d8d22018-02-20 10:42:06 +0900238 throw new IllegalArgumentException();
239 }
240 }
Jian Lieb9f77d2018-02-20 11:25:45 +0900241
242 /**
243 * Converts openstack model entity object into JSON object.
244 *
245 * @param entity openstack model entity object
246 * @param entityClazz openstack model entity class
247 * @return JSON object
248 */
249 public static ObjectNode modelEntityToJson(ModelEntity entity, Class entityClazz) {
250 ObjectMapper mapper = new ObjectMapper();
251 try {
252 String strModelEntity = ObjectMapperSingleton.getContext(entityClazz)
253 .writerFor(entityClazz)
254 .writeValueAsString(entity);
255 log.trace(strModelEntity);
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900256 return (ObjectNode) mapper.readTree(strModelEntity.getBytes(Charsets.UTF_8));
Daniel Park95985382018-07-23 11:38:07 +0900257 } catch (IOException e) {
258 log.error("IOException occurred because of {}", e.toString());
Jian Lieb9f77d2018-02-20 11:25:45 +0900259 throw new IllegalStateException();
260 }
261 }
Jian Li1064e4f2018-05-29 16:16:53 +0900262
263 /**
Jian Li24ec59f2018-05-23 19:01:25 +0900264 * Obtains a floating IP associated with the given instance port.
265 *
266 * @param port instance port
267 * @param fips a collection of floating IPs
268 * @return associated floating IP
269 */
270 public static NetFloatingIP associatedFloatingIp(InstancePort port,
271 Set<NetFloatingIP> fips) {
Daniel Park2ff66b42018-08-01 11:52:45 +0900272 for (NetFloatingIP fip : fips) {
273 if (Strings.isNullOrEmpty(fip.getFixedIpAddress())) {
274 continue;
Jian Li24ec59f2018-05-23 19:01:25 +0900275 }
Daniel Park2ff66b42018-08-01 11:52:45 +0900276 if (Strings.isNullOrEmpty(fip.getFloatingIpAddress())) {
277 continue;
278 }
Jian Li6bc29d92018-10-02 13:55:05 +0900279 if (fip.getFixedIpAddress().equals(port.ipAddress().toString()) &&
280 fip.getPortId().equals(port.portId())) {
Daniel Park2ff66b42018-08-01 11:52:45 +0900281 return fip;
282 }
Jian Li24ec59f2018-05-23 19:01:25 +0900283 }
Daniel Park2ff66b42018-08-01 11:52:45 +0900284
Jian Li24ec59f2018-05-23 19:01:25 +0900285 return null;
286 }
287
288 /**
289 * Checks whether the given floating IP is associated with a VM.
290 *
291 * @param service openstack network service
292 * @param fip floating IP
293 * @return true if the given floating IP associated with a VM, false otherwise
294 */
295 public static boolean isAssociatedWithVM(OpenstackNetworkService service,
296 NetFloatingIP fip) {
297 Port osPort = service.port(fip.getPortId());
298 if (osPort == null) {
299 return false;
300 }
301
302 if (!Strings.isNullOrEmpty(osPort.getDeviceId())) {
303 Network osNet = service.network(osPort.getNetworkId());
304 if (osNet == null) {
305 final String errorFormat = ERR_FLOW + "no network(%s) exists";
306 final String error = String.format(errorFormat,
307 fip.getFloatingIpAddress(), osPort.getNetworkId());
308 throw new IllegalStateException(error);
309 }
310 return true;
311 } else {
312 return false;
313 }
314 }
315
316 /**
Jian Lia171a432018-06-11 11:52:11 +0900317 * Obtains the gateway node by instance port.
318 *
319 * @param gateways a collection of gateway nodes
320 * @param instPort instance port
321 * @return a gateway node
322 */
323 public static OpenstackNode getGwByInstancePort(Set<OpenstackNode> gateways,
324 InstancePort instPort) {
325 OpenstackNode gw = null;
326 if (instPort != null && instPort.deviceId() != null) {
327 gw = getGwByComputeDevId(gateways, instPort.deviceId());
328 }
329 return gw;
330 }
331
332 /**
Jian Li1064e4f2018-05-29 16:16:53 +0900333 * Obtains the gateway node by device in compute node. Note that the gateway
334 * node is determined by device's device identifier.
335 *
336 * @param gws a collection of gateway nodes
337 * @param deviceId device identifier
338 * @return a gateway node
339 */
Jian Li5ecfd1a2018-12-10 11:41:03 +0900340 public static OpenstackNode getGwByComputeDevId(Set<OpenstackNode> gws,
341 DeviceId deviceId) {
Jian Li1064e4f2018-05-29 16:16:53 +0900342 int numOfGw = gws.size();
343
344 if (numOfGw == 0) {
345 return null;
346 }
347
348 int gwIndex = Math.abs(deviceId.hashCode()) % numOfGw;
349
350 return getGwByIndex(gws, gwIndex);
351 }
352
Jian Li51b844c2018-05-31 10:59:03 +0900353 /**
354 * Obtains a connected openstack client.
355 *
356 * @param osNode openstack node
357 * @return a connected openstack client
358 */
359 public static OSClient getConnectedClient(OpenstackNode osNode) {
Jian Lic704b672018-09-04 18:52:53 +0900360 OpenstackAuth auth = osNode.keystoneConfig().authentication();
Jian Li51b844c2018-05-31 10:59:03 +0900361 String endpoint = buildEndpoint(osNode);
362 Perspective perspective = auth.perspective();
Jian Li1064e4f2018-05-29 16:16:53 +0900363
Jian Li51b844c2018-05-31 10:59:03 +0900364 Config config = getSslConfig();
Jian Li1064e4f2018-05-29 16:16:53 +0900365
Jian Li51b844c2018-05-31 10:59:03 +0900366 try {
367 if (endpoint.contains(KEYSTONE_V2)) {
368 IOSClientBuilder.V2 builder = OSFactory.builderV2()
369 .endpoint(endpoint)
370 .tenantName(auth.project())
371 .credentials(auth.username(), auth.password())
372 .withConfig(config);
373
374 if (perspective != null) {
375 builder.perspective(getFacing(perspective));
376 }
377
378 return builder.authenticate();
379 } else if (endpoint.contains(KEYSTONE_V3)) {
380
381 Identifier project = Identifier.byName(auth.project());
382 Identifier domain = Identifier.byName(DOMAIN_DEFAULT);
383
384 IOSClientBuilder.V3 builder = OSFactory.builderV3()
385 .endpoint(endpoint)
386 .credentials(auth.username(), auth.password(), domain)
387 .scopeToProject(project, domain)
388 .withConfig(config);
389
390 if (perspective != null) {
391 builder.perspective(getFacing(perspective));
392 }
393
394 return builder.authenticate();
395 } else {
396 log.warn("Unrecognized keystone version type");
397 return null;
Jian Li1064e4f2018-05-29 16:16:53 +0900398 }
Jian Li51b844c2018-05-31 10:59:03 +0900399 } catch (AuthenticationException e) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900400 log.error("Authentication failed due to {}", e);
Jian Li51b844c2018-05-31 10:59:03 +0900401 return null;
Jian Li1064e4f2018-05-29 16:16:53 +0900402 }
Jian Li1064e4f2018-05-29 16:16:53 +0900403 }
Daniel Parkc4d06402018-05-28 15:57:37 +0900404
405 /**
Jian Lia97cec42019-10-31 22:24:17 +0900406 * Checks whether the given openstack port is smart NIC capable.
407 *
408 * @param port openstack port
409 * @return true if the given port is smart NIC capable, false otherwise
410 */
411 public static boolean isSmartNicCapable(Port port) {
412 if (port.getProfile() != null && port.getvNicType().equals(DIRECT)) {
413 String vendorInfo = String.valueOf(port.getProfile().get(PCI_VENDOR_INFO));
414 if (portNamePrefixMap().containsKey(vendorInfo)) {
415 log.debug("Port {} is a Smart NIC capable port.", port.getId());
416 return true;
417 }
418 return false;
419 }
420 return false;
421 }
422
423 /**
Daniel Parkc4d06402018-05-28 15:57:37 +0900424 * Extract the interface name with the supplied port.
425 *
426 * @param port port
427 * @return interface name
428 */
429 public static String getIntfNameFromPciAddress(Port port) {
Daniel Parkff178ba2018-11-23 15:57:24 +0900430 String intfName;
431
Daniel Park95985382018-07-23 11:38:07 +0900432 if (port.getProfile() == null || port.getProfile().isEmpty()) {
Jian Li51b844c2018-05-31 10:59:03 +0900433 log.error("Port profile is not found");
434 return null;
435 }
436
Daniel Park95985382018-07-23 11:38:07 +0900437 if (!port.getProfile().containsKey(PCISLOT) ||
438 Strings.isNullOrEmpty(port.getProfile().get(PCISLOT).toString())) {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900439 log.error("Failed to retrieve the interface name because of no " +
440 "pci_slot information from the port");
Daniel Parkc4d06402018-05-28 15:57:37 +0900441 return null;
442 }
Jian Li51b844c2018-05-31 10:59:03 +0900443
Daniel Parkff178ba2018-11-23 15:57:24 +0900444 String vendorInfoForPort = String.valueOf(port.getProfile().get(PCI_VENDOR_INFO));
445
446 if (!portNamePrefixMap().containsKey(vendorInfoForPort)) {
447 log.debug("{} is an non-smart NIC prefix.", vendorInfoForPort);
448 return UNSUPPORTED_VENDOR;
449 }
450
451 String portNamePrefix = portNamePrefixMap().get(vendorInfoForPort);
452
Daniel Parkc4d06402018-05-28 15:57:37 +0900453 String busNumHex = port.getProfile().get(PCISLOT).toString().split(":")[1];
454 String busNumDecimal = String.valueOf(Integer.parseInt(busNumHex, HEX_RADIX));
455
456 String deviceNumHex = port.getProfile().get(PCISLOT).toString()
457 .split(":")[2]
458 .split("\\.")[0];
459 String deviceNumDecimal = String.valueOf(Integer.parseInt(deviceNumHex, HEX_RADIX));
460
461 String functionNumHex = port.getProfile().get(PCISLOT).toString()
462 .split(":")[2]
463 .split("\\.")[1];
464 String functionNumDecimal = String.valueOf(Integer.parseInt(functionNumHex, HEX_RADIX));
465
Daniel Parkc4d06402018-05-28 15:57:37 +0900466 if (functionNumDecimal.equals(ZERO_FUNCTION_NUMBER)) {
467 intfName = portNamePrefix + busNumDecimal + PREFIX_DEVICE_NUMBER + deviceNumDecimal;
468 } else {
469 intfName = portNamePrefix + busNumDecimal + PREFIX_DEVICE_NUMBER + deviceNumDecimal
470 + PREFIX_FUNCTION_NUMBER + functionNumDecimal;
471 }
472
473 return intfName;
474 }
Jian Li51b844c2018-05-31 10:59:03 +0900475
476 /**
Daniel Park95f73312018-07-31 15:48:34 +0900477 * Check if the given interface is added to the given device or not.
478 *
479 * @param deviceId device ID
480 * @param intfName interface name
481 * @param deviceService device service
482 * @return true if the given interface is added to the given device or false otherwise
483 */
Jian Li5ecfd1a2018-12-10 11:41:03 +0900484 public static boolean hasIntfAleadyInDevice(DeviceId deviceId,
485 String intfName,
486 DeviceService deviceService) {
Daniel Park95f73312018-07-31 15:48:34 +0900487 checkNotNull(deviceId);
488 checkNotNull(intfName);
489
Jian Li5ecfd1a2018-12-10 11:41:03 +0900490 return deviceService.getPorts(deviceId).stream().anyMatch(port ->
491 Objects.equals(port.annotations().value(PORT_NAME), intfName));
Daniel Park95f73312018-07-31 15:48:34 +0900492 }
493
494 /**
Jian Li0b564282018-06-20 00:50:53 +0900495 * Adds router interfaces to openstack admin service.
Jian Li0b564282018-06-20 00:50:53 +0900496 *
497 * @param osPort port
498 * @param adminService openstack admin service
499 */
Jian Li5ecfd1a2018-12-10 11:41:03 +0900500 public static void addRouterIface(Port osPort,
501 OpenstackRouterAdminService adminService) {
Jian Li0b564282018-06-20 00:50:53 +0900502 osPort.getFixedIps().forEach(p -> {
503 JsonNode jsonTree = new ObjectMapper().createObjectNode()
504 .put("id", osPort.getDeviceId())
505 .put("tenant_id", osPort.getTenantId())
506 .put("subnet_id", p.getSubnetId())
507 .put("port_id", osPort.getId());
508 try {
509 RouterInterface rIface = getContext(NeutronRouterInterface.class)
510 .readerFor(NeutronRouterInterface.class)
511 .readValue(jsonTree);
512 if (adminService.routerInterface(rIface.getPortId()) != null) {
513 adminService.updateRouterInterface(rIface);
514 } else {
515 adminService.addRouterInterface(rIface);
516 }
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900517 } catch (IOException e) {
518 log.error("IOException occurred because of {}", e);
Jian Li0b564282018-06-20 00:50:53 +0900519 }
520 });
521 }
522
523 /**
Jian Liecbf10c2019-10-02 20:36:09 +0900524 * Prints openstack security group.
525 *
526 * @param osSg openstack security group
527 */
528 public static void printSecurityGroup(SecurityGroup osSg) {
529 print(SECURITY_GROUP_FORMAT, osSg.getId(), osSg.getName());
530 }
531
532 /**
533 * Prints openstack network.
534 *
535 * @param osNet openstack network
536 */
537 public static void printNetwork(Network osNet) {
538 final String strNet = String.format(NETWORK_FORMAT,
539 osNet.getId(),
540 osNet.getName(),
541 osNet.getProviderSegID(),
542 osNet.getSubnets());
543 print(strNet);
544 }
545
546 /**
547 * Prints openstack subnet.
548 *
549 * @param osSubnet openstack subnet
550 * @param osNetService openstack network service
551 */
552 public static void printSubnet(Subnet osSubnet,
553 OpenstackNetworkService osNetService) {
554 final Network network = osNetService.network(osSubnet.getNetworkId());
555 final String netName = network == null ? NOT_AVAILABLE : network.getName();
556 final String strSubnet = String.format(SUBNET_FORMAT,
557 osSubnet.getId(),
558 netName,
559 osSubnet.getCidr());
560 print(strSubnet);
561 }
562
563 /**
564 * Prints openstack port.
565 *
566 * @param osPort openstack port
567 * @param osNetService openstack network service
568 */
569 public static void printPort(Port osPort,
570 OpenstackNetworkService osNetService) {
571 List<String> fixedIps = osPort.getFixedIps().stream()
572 .map(IP::getIpAddress)
573 .collect(Collectors.toList());
574 final Network network = osNetService.network(osPort.getNetworkId());
575 final String netName = network == null ? NOT_AVAILABLE : network.getName();
576 final String strPort = String.format(PORT_FORMAT,
577 osPort.getId(),
578 netName,
579 osPort.getMacAddress(),
580 fixedIps.isEmpty() ? "" : fixedIps);
581 print(strPort);
582 }
583
584 /**
585 * Prints openstack router.
586 *
587 * @param osRouter openstack router
588 * @param osNetService openstack network service
589 */
590 public static void printRouter(Router osRouter,
591 OpenstackNetworkService osNetService) {
592 List<String> externals = osNetService.ports().stream()
593 .filter(osPort -> Objects.equals(osPort.getDeviceId(), osRouter.getId()) &&
594 Objects.equals(osPort.getDeviceOwner(), DEVICE_OWNER_GW))
595 .flatMap(osPort -> osPort.getFixedIps().stream())
596 .map(IP::getIpAddress)
597 .collect(Collectors.toList());
598
599 List<String> internals = osNetService.ports().stream()
600 .filter(osPort -> Objects.equals(osPort.getDeviceId(), osRouter.getId()) &&
601 Objects.equals(osPort.getDeviceOwner(), DEVICE_OWNER_IFACE))
602 .flatMap(osPort -> osPort.getFixedIps().stream())
603 .map(IP::getIpAddress)
604 .collect(Collectors.toList());
605
606 final String strRouter = String.format(ROUTER_FORMAT,
607 osRouter.getId(),
608 osRouter.getName(),
609 externals.isEmpty() ? "" : externals,
610 internals.isEmpty() ? "" : internals);
611 print(strRouter);
612 }
613
614 /**
615 * Prints openstack router interface.
616 *
617 * @param osRouterIntf openstack router interface
618 */
619 public static void printRouterIntf(RouterInterface osRouterIntf) {
620 final String strRouterIntf = String.format(ROUTER_INTF_FORMAT,
621 osRouterIntf.getId(),
622 osRouterIntf.getTenantId(),
623 osRouterIntf.getSubnetId());
624 print(strRouterIntf);
625 }
626
627 /**
628 * Prints openstack floating IP.
629 *
630 * @param floatingIp floating IP
631 */
632 public static void printFloatingIp(NetFloatingIP floatingIp) {
633 final String strFloating = String.format(FLOATING_IP_FORMAT,
634 floatingIp.getId(),
635 floatingIp.getFloatingIpAddress(),
636 Strings.isNullOrEmpty(floatingIp.getFixedIpAddress()) ?
637 "" : floatingIp.getFixedIpAddress());
638 print(strFloating);
639 }
640
641 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900642 * Obtains the property value with specified property key name.
643 *
644 * @param properties a collection of properties
645 * @param name key name
646 * @return mapping value
647 */
Jian Li5ecfd1a2018-12-10 11:41:03 +0900648 public static String getPropertyValue(Set<ConfigProperty> properties,
649 String name) {
Jian Li7f70bb72018-07-06 23:35:30 +0900650 Optional<ConfigProperty> property =
651 properties.stream().filter(p -> p.name().equals(name)).findFirst();
652 return property.map(ConfigProperty::value).orElse(null);
653 }
654
655 /**
Jian Li9d35bd62018-10-13 01:43:24 +0900656 * Obtains the boolean property value with specified property key name.
657 *
658 * @param properties a collection of properties
659 * @param name key name
660 * @return mapping value
661 */
Jian Li5ecfd1a2018-12-10 11:41:03 +0900662 public static boolean getPropertyValueAsBoolean(Set<ConfigProperty> properties,
663 String name) {
Jian Li9d35bd62018-10-13 01:43:24 +0900664 Optional<ConfigProperty> property =
665 properties.stream().filter(p -> p.name().equals(name)).findFirst();
666
667 return property.map(ConfigProperty::asBoolean).orElse(false);
668 }
669
670 /**
Jian Lif1efbe52018-07-17 23:20:16 +0900671 * Prints out the JSON string in pretty format.
672 *
673 * @param mapper Object mapper
674 * @param jsonString JSON string
675 * @return pretty formatted JSON string
676 */
677 public static String prettyJson(ObjectMapper mapper, String jsonString) {
678 try {
679 Object jsonObject = mapper.readValue(jsonString, Object.class);
680 return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject);
Daniel Park2ff66b42018-08-01 11:52:45 +0900681 } catch (JsonParseException e) {
682 log.debug("JsonParseException caused by {}", e);
683 } catch (JsonMappingException e) {
684 log.debug("JsonMappingException caused by {}", e);
685 } catch (JsonProcessingException e) {
686 log.debug("JsonProcessingException caused by {}", e);
Jian Lif1efbe52018-07-17 23:20:16 +0900687 } catch (IOException e) {
Daniel Park2ff66b42018-08-01 11:52:45 +0900688 log.debug("IOException caused by {}", e);
Jian Lif1efbe52018-07-17 23:20:16 +0900689 }
690 return null;
691 }
692
693 /**
Jian Li7f024de2018-07-07 03:51:02 +0900694 * Checks the validity of ARP mode.
695 *
696 * @param arpMode ARP mode
697 * @return returns true if the ARP mode is valid, false otherwise
698 */
699 public static boolean checkArpMode(String arpMode) {
700
701 if (isNullOrEmpty(arpMode)) {
702 return false;
703 } else {
704 return arpMode.equals(PROXY_MODE) || arpMode.equals(BROADCAST_MODE);
705 }
706 }
707
708 /**
Jian Licad36c72018-09-13 17:44:54 +0900709 * Checks the validity of activation flag.
710 *
711 * @param activationFlag activation flag
712 * @return returns true if the activation flag is valid, false otherwise
713 */
714 public static boolean checkActivationFlag(String activationFlag) {
715
716 switch (activationFlag) {
717 case ENABLE:
718 return true;
719 case DISABLE:
720 return false;
721 default:
722 throw new IllegalArgumentException("The given activation flag is not valid!");
723 }
724 }
725
726 /**
Jian Liec5c32b2018-07-13 14:28:58 +0900727 * Swaps current location with old location info.
728 * The revised instance port will be used to mod the flow rules after migration.
729 *
730 * @param instPort instance port
731 * @return location swapped instance port
732 */
733 public static InstancePort swapStaleLocation(InstancePort instPort) {
734 return DefaultInstancePort.builder()
735 .deviceId(instPort.oldDeviceId())
736 .portNumber(instPort.oldPortNumber())
737 .state(instPort.state())
738 .ipAddress(instPort.ipAddress())
739 .macAddress(instPort.macAddress())
740 .networkId(instPort.networkId())
741 .portId(instPort.portId())
742 .build();
743 }
744
745 /**
Daniel Park2ff66b42018-08-01 11:52:45 +0900746 * Compares two router interfaces are equal.
747 * Will be remove this after Openstack4j implements equals.
748 *
749 * @param routerInterface1 router interface
750 * @param routerInterface2 router interface
751 * @return returns true if two router interfaces are equal, false otherwise
752 */
Jian Li63430202018-08-30 16:24:09 +0900753 public static boolean routerInterfacesEquals(RouterInterface routerInterface1,
754 RouterInterface routerInterface2) {
Daniel Park2ff66b42018-08-01 11:52:45 +0900755 return Objects.equals(routerInterface1.getId(), routerInterface2.getId()) &&
756 Objects.equals(routerInterface1.getPortId(), routerInterface2.getPortId()) &&
757 Objects.equals(routerInterface1.getSubnetId(), routerInterface2.getSubnetId()) &&
758 Objects.equals(routerInterface1.getTenantId(), routerInterface2.getTenantId());
759 }
760
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900761 /**
762 * Returns the vnic type of given port.
763 *
764 * @param portName port name
765 * @return vnit type
766 */
Daniel Park7e8c4d82018-08-13 23:47:49 +0900767 public static VnicType vnicType(String portName) {
768 if (portName.startsWith(PORT_NAME_PREFIX_VM) ||
769 portName.startsWith(PORT_NAME_VHOST_USER_PREFIX_VM)) {
770 return VnicType.NORMAL;
771 } else if (isDirectPort(portName)) {
772 return VnicType.DIRECT;
773 } else {
774 return VnicType.UNSUPPORTED;
775 }
776 }
777
Jian Li63430202018-08-30 16:24:09 +0900778 /**
779 * Deserializes raw payload into HttpRequest object.
780 *
781 * @param rawData raw http payload
782 * @return HttpRequest object
783 */
784 public static HttpRequest parseHttpRequest(byte[] rawData) {
785 SessionInputBufferImpl sessionInputBuffer =
786 new SessionInputBufferImpl(
787 new HttpTransportMetricsImpl(), HTTP_PAYLOAD_BUFFER);
788 sessionInputBuffer.bind(new ByteArrayInputStream(rawData));
Jian Li5ecfd1a2018-12-10 11:41:03 +0900789 DefaultHttpRequestParser requestParser =
790 new DefaultHttpRequestParser(sessionInputBuffer);
Jian Li63430202018-08-30 16:24:09 +0900791 try {
792 return requestParser.parse();
793 } catch (IOException | HttpException e) {
794 log.warn("Failed to parse HttpRequest, due to {}", e);
795 }
796
797 return null;
798 }
799
800 /**
801 * Serializes HttpRequest object to byte array.
802 *
803 * @param request http request object
804 * @return byte array
805 */
806 public static byte[] unparseHttpRequest(HttpRequest request) {
807 try {
808 SessionOutputBufferImpl sessionOutputBuffer =
809 new SessionOutputBufferImpl(
810 new HttpTransportMetricsImpl(), HTTP_PAYLOAD_BUFFER);
811
812 ByteArrayOutputStream baos = new ByteArrayOutputStream();
813 sessionOutputBuffer.bind(baos);
814
Jian Li5ecfd1a2018-12-10 11:41:03 +0900815 HttpMessageWriter<HttpRequest> requestWriter =
816 new DefaultHttpRequestWriter(sessionOutputBuffer);
Jian Li63430202018-08-30 16:24:09 +0900817 requestWriter.write(request);
818 sessionOutputBuffer.flush();
819
820 return baos.toByteArray();
821 } catch (HttpException | IOException e) {
822 log.warn("Failed to unparse HttpRequest, due to {}", e);
823 }
824
825 return null;
826 }
827
828 /**
829 * Deserializes raw payload into HttpResponse object.
830 *
831 * @param rawData raw http payload
832 * @return HttpResponse object
833 */
834 public static HttpResponse parseHttpResponse(byte[] rawData) {
835 SessionInputBufferImpl sessionInputBuffer =
836 new SessionInputBufferImpl(
837 new HttpTransportMetricsImpl(), HTTP_PAYLOAD_BUFFER);
838 sessionInputBuffer.bind(new ByteArrayInputStream(rawData));
Jian Li5ecfd1a2018-12-10 11:41:03 +0900839 DefaultHttpResponseParser responseParser =
840 new DefaultHttpResponseParser(sessionInputBuffer);
Jian Li63430202018-08-30 16:24:09 +0900841 try {
842 return responseParser.parse();
843 } catch (IOException | HttpException e) {
844 log.warn("Failed to parse HttpResponse, due to {}", e);
845 }
846
847 return null;
848 }
849
850 /**
851 * Serializes HttpResponse header to byte array.
852 *
853 * @param response http response object
854 * @return byte array
855 */
856 public static byte[] unparseHttpResponseHeader(HttpResponse response) {
857 try {
858 SessionOutputBufferImpl sessionOutputBuffer =
859 new SessionOutputBufferImpl(
860 new HttpTransportMetricsImpl(), HTTP_PAYLOAD_BUFFER);
861
862 ByteArrayOutputStream headerBaos = new ByteArrayOutputStream();
863 sessionOutputBuffer.bind(headerBaos);
864
865 HttpMessageWriter<HttpResponse> responseWriter =
866 new DefaultHttpResponseWriter(sessionOutputBuffer);
867 responseWriter.write(response);
868 sessionOutputBuffer.flush();
869
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900870 log.debug(headerBaos.toString(Charsets.UTF_8.name()));
Jian Li63430202018-08-30 16:24:09 +0900871
872 return headerBaos.toByteArray();
873 } catch (IOException | HttpException e) {
874 log.warn("Failed to unparse HttpResponse headers, due to {}", e);
875 }
876
877 return null;
878 }
879
880 /**
881 * Serializes HttpResponse object to byte array.
882 *
883 * @param response http response object
884 * @return byte array
885 */
886 public static byte[] unparseHttpResponseBody(HttpResponse response) {
887 try {
888 ByteArrayOutputStream baos = new ByteArrayOutputStream();
889 response.getEntity().writeTo(baos);
890
891 log.debug(response.toString());
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900892 log.debug(baos.toString(Charsets.UTF_8.name()));
Jian Li63430202018-08-30 16:24:09 +0900893
894 return baos.toByteArray();
895 } catch (IOException e) {
896 log.warn("Failed to unparse HttpResponse, due to {}", e);
897 }
898
899 return null;
900 }
901
902 /**
903 * Encodes the given data using HmacSHA256 encryption method with given secret key.
904 *
905 * @param key secret key
906 * @param data data to be encrypted
907 * @return Hmac256 encrypted data
908 */
909 public static String hmacEncrypt(String key, String data) {
910 try {
911 Mac sha256Hmac = Mac.getInstance(HMAC_SHA256);
912 SecretKeySpec secretKey = new SecretKeySpec(key.getBytes("UTF-8"), HMAC_SHA256);
913 sha256Hmac.init(secretKey);
914 return Hex.encodeHexString(sha256Hmac.doFinal(data.getBytes("UTF-8")));
915 } catch (Exception e) {
916 log.warn("Failed to encrypt data {} using key {}, due to {}", data, key, e);
917 }
918 return null;
919 }
920
Daniel Parka73c2362018-09-17 17:43:25 +0900921 /**
922 * Creates flow trace request string.
923 *
924 * @param srcIp src ip address
925 * @param dstIp dst ip address
926 * @param srcInstancePort src instance port
927 * @param osNetService openstack networking service
Daniel Park5aef9822018-09-20 18:04:18 +0900928 * @param uplink true if this request is for uplink
Daniel Parka73c2362018-09-17 17:43:25 +0900929 * @return flow trace request string
930 */
931 public static String traceRequestString(String srcIp,
932 String dstIp,
933 InstancePort srcInstancePort,
Jian Li5ecfd1a2018-12-10 11:41:03 +0900934 OpenstackNetworkService osNetService,
935 boolean uplink) {
Daniel Parka73c2362018-09-17 17:43:25 +0900936
937 StringBuilder requestStringBuilder = new StringBuilder(DEFAULT_REQUEST_STRING);
938
939 if (uplink) {
940
941 requestStringBuilder.append(COMMA)
942 .append(IN_PORT)
943 .append(srcInstancePort.portNumber().toString())
944 .append(COMMA)
945 .append(NW_SRC)
946 .append(srcIp)
947 .append(COMMA);
948
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900949 String modifiedDstIp = dstIp;
Jian Li621f73c2018-12-15 01:49:22 +0900950 Type netType = osNetService.networkType(srcInstancePort.networkId());
951 if (netType == Type.VXLAN || netType == Type.GRE ||
952 netType == Type.VLAN || netType == Type.GENEVE) {
Daniel Parka73c2362018-09-17 17:43:25 +0900953 if (srcIp.equals(dstIp)) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900954 modifiedDstIp = osNetService.gatewayIp(srcInstancePort.portId());
Daniel Parka73c2362018-09-17 17:43:25 +0900955 requestStringBuilder.append(DL_DST)
956 .append(DEFAULT_GATEWAY_MAC_STR).append(COMMA);
Jian Li5ecfd1a2018-12-10 11:41:03 +0900957 } else if (!osNetService.ipPrefix(srcInstancePort.portId()).contains(
958 IpAddress.valueOf(dstIp))) {
Daniel Parka73c2362018-09-17 17:43:25 +0900959 requestStringBuilder.append(DL_DST)
960 .append(DEFAULT_GATEWAY_MAC_STR)
961 .append(COMMA);
962 }
963 } else {
964 if (srcIp.equals(dstIp)) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900965 modifiedDstIp = osNetService.gatewayIp(srcInstancePort.portId());
Daniel Parka73c2362018-09-17 17:43:25 +0900966 }
967 }
968
969 requestStringBuilder.append(NW_DST)
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900970 .append(modifiedDstIp)
Daniel Parka73c2362018-09-17 17:43:25 +0900971 .append("\n");
972 } else {
973 requestStringBuilder.append(COMMA)
974 .append(NW_SRC)
975 .append(dstIp)
976 .append(COMMA);
977
Jian Li621f73c2018-12-15 01:49:22 +0900978 Type netType = osNetService.networkType(srcInstancePort.networkId());
979
980 if (netType == Type.VXLAN || netType == Type.GRE ||
981 netType == Type.VLAN || netType == Type.GENEVE) {
Daniel Parka73c2362018-09-17 17:43:25 +0900982 requestStringBuilder.append(TUN_ID)
983 .append(osNetService.segmentId(srcInstancePort.networkId()))
984 .append(COMMA);
985 }
986 requestStringBuilder.append(NW_DST)
987 .append(srcIp)
988 .append("\n");
Daniel Parka73c2362018-09-17 17:43:25 +0900989 }
990
991 return requestStringBuilder.toString();
992 }
993
994 /**
995 * Sends flow trace string to node.
996 *
997 * @param requestString reqeust string
998 * @param node src node
999 * @return flow trace result in string format
1000 */
1001 public static String sendTraceRequestToNode(String requestString,
1002 OpenstackNode node) {
1003 String traceResult = null;
1004 OpenstackSshAuth sshAuth = node.sshAuthInfo();
1005
1006 try (SshClient client = SshClient.setUpDefaultClient()) {
1007 client.start();
1008
1009 try (ClientSession session = client
1010 .connect(sshAuth.id(), node.managementIp().getIp4Address().toString(), SSH_PORT)
1011 .verify(TIMEOUT_MS, TimeUnit.SECONDS).getSession()) {
1012 session.addPasswordIdentity(sshAuth.password());
1013 session.auth().verify(TIMEOUT_MS, TimeUnit.SECONDS);
1014
1015
1016 try (ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL)) {
1017
1018 log.debug("requestString: {}", requestString);
1019 final InputStream inputStream =
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001020 new ByteArrayInputStream(requestString.getBytes(Charsets.UTF_8));
Daniel Parka73c2362018-09-17 17:43:25 +09001021
Jian Li5ecfd1a2018-12-10 11:41:03 +09001022 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Daniel Parka73c2362018-09-17 17:43:25 +09001023 OutputStream errStream = new ByteArrayOutputStream();
1024
1025 channel.setIn(new NoCloseInputStream(inputStream));
1026 channel.setErr(errStream);
1027 channel.setOut(outputStream);
1028
1029 Collection<ClientChannelEvent> eventList = Lists.newArrayList();
1030 eventList.add(ClientChannelEvent.OPENED);
1031
1032 OpenFuture channelFuture = channel.open();
1033
1034 if (channelFuture.await(TIMEOUT_MS, TimeUnit.SECONDS)) {
1035
1036 long timeoutExpiredMs = System.currentTimeMillis() + TIMEOUT_MS;
1037
1038 while (!channelFuture.isOpened()) {
1039 if ((timeoutExpiredMs - System.currentTimeMillis()) <= 0) {
1040 log.error("Failed to open channel");
1041 return null;
1042 }
1043 }
1044 TimeUnit.SECONDS.sleep(WAIT_OUTPUT_STREAM_SECOND);
1045
Jian Li5ecfd1a2018-12-10 11:41:03 +09001046 traceResult = outputStream.toString(Charsets.UTF_8.name());
Daniel Parka73c2362018-09-17 17:43:25 +09001047
1048 channel.close();
1049 }
1050 } finally {
1051 session.close();
1052 }
1053 } finally {
1054 client.stop();
1055 }
1056
1057 } catch (Exception e) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001058 log.error("Exception occurred because of {}", e);
Daniel Parka73c2362018-09-17 17:43:25 +09001059 }
1060
1061 return traceResult;
1062 }
1063
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001064 /**
1065 * Returns the floating ip with supplied instance port.
1066 *
1067 * @param instancePort instance port
1068 * @param osRouterAdminService openstack router admin service
1069 * @return floating ip
1070 */
1071 public static NetFloatingIP floatingIpByInstancePort(InstancePort instancePort,
Jian Li5ecfd1a2018-12-10 11:41:03 +09001072 OpenstackRouterAdminService
1073 osRouterAdminService) {
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001074 return osRouterAdminService.floatingIps().stream()
1075 .filter(netFloatingIP -> netFloatingIP.getPortId() != null)
1076 .filter(netFloatingIP -> netFloatingIP.getPortId().equals(instancePort.portId()))
1077 .findAny().orElse(null);
1078 }
1079
1080 /**
1081 * Sends GARP packet with supplied floating ip information.
1082 *
1083 * @param floatingIP floating ip
1084 * @param instancePort instance port
1085 * @param vlanId vlain id
1086 * @param gatewayNode gateway node
1087 * @param packetService packet service
1088 */
Jian Li32b03622018-11-06 17:54:24 +09001089 public static void processGarpPacketForFloatingIp(NetFloatingIP floatingIP,
1090 InstancePort instancePort,
1091 VlanId vlanId,
1092 OpenstackNode gatewayNode,
1093 PacketService packetService) {
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001094 Ethernet ethernet = buildGratuitousArpPacket(floatingIP, instancePort, vlanId);
1095
1096 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1097 .setOutput(gatewayNode.uplinkPortNum()).build();
1098
1099 packetService.emit(new DefaultOutboundPacket(gatewayNode.intgBridge(), treatment,
1100 ByteBuffer.wrap(ethernet.serialize())));
1101 }
1102
1103 /**
1104 * Returns the external peer router with supplied network information.
1105 *
1106 * @param network network
1107 * @param osNetworkService openstack network service
1108 * @param osRouterAdminService openstack router admin service
1109 * @return external peer router
1110 */
1111 public static ExternalPeerRouter externalPeerRouterForNetwork(Network network,
Jian Li5ecfd1a2018-12-10 11:41:03 +09001112 OpenstackNetworkService
1113 osNetworkService,
1114 OpenstackRouterAdminService
1115 osRouterAdminService) {
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001116 if (network == null) {
1117 return null;
1118 }
1119
Jian Lie6e609f2019-05-14 17:45:54 +09001120 Subnet subnet = osNetworkService.subnets(network.getId())
1121 .stream().findAny().orElse(null);
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001122
1123 if (subnet == null) {
1124 return null;
1125 }
1126
1127 RouterInterface osRouterIface = osRouterAdminService.routerInterfaces().stream()
1128 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
1129 .findAny().orElse(null);
1130 if (osRouterIface == null) {
1131 return null;
1132 }
1133
1134 Router osRouter = osRouterAdminService.router(osRouterIface.getId());
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001135 if (osRouter == null || osRouter.getExternalGatewayInfo() == null) {
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001136 return null;
1137 }
1138
1139 ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
1140 return osNetworkService.externalPeerRouter(exGatewayInfo);
1141
1142 }
1143
Jian Liebde74d2018-11-14 00:18:57 +09001144 /**
1145 * Returns the external peer router with specified subnet information.
1146 *
1147 * @param subnet openstack subnet
1148 * @param osRouterService openstack router service
1149 * @param osNetworkService openstack network service
1150 * @return external peer router
1151 */
Jian Li5ecfd1a2018-12-10 11:41:03 +09001152 public static ExternalPeerRouter externalPeerRouterFromSubnet(Subnet subnet,
1153 OpenstackRouterService
1154 osRouterService,
1155 OpenstackNetworkService
1156 osNetworkService) {
Jian Liebde74d2018-11-14 00:18:57 +09001157 Router osRouter = getRouterFromSubnet(subnet, osRouterService);
1158 if (osRouter == null) {
1159 return null;
1160 }
1161 if (osRouter.getExternalGatewayInfo() == null) {
1162 // this router does not have external connectivity
1163 log.trace("router({}) has no external gateway",
1164 osRouter.getName());
1165 return null;
1166 }
1167
1168 return osNetworkService.externalPeerRouter(osRouter.getExternalGatewayInfo());
1169 }
1170
1171 /**
Jian Lia5c7edf2020-02-24 16:42:24 +09001172 * Returns the external gateway IP address with specified router information.
Jian Liebde74d2018-11-14 00:18:57 +09001173 *
1174 * @param router openstack router
1175 * @param osNetworkService openstack network service
Jian Lia5c7edf2020-02-24 16:42:24 +09001176 * @return external IP address
Jian Liebde74d2018-11-14 00:18:57 +09001177 */
Jian Lia5c7edf2020-02-24 16:42:24 +09001178 public static IpAddress externalGatewayIp(Router router,
1179 OpenstackNetworkService osNetworkService) {
1180 return externalGatewayIpBase(router, false, osNetworkService);
1181 }
Jian Liebde74d2018-11-14 00:18:57 +09001182
Jian Lia5c7edf2020-02-24 16:42:24 +09001183 /**
1184 * Returns the external gateway IP address (SNAT enabled) with specified router information.
1185 *
1186 * @param router openstack router
1187 * @param osNetworkService openstack network service
1188 * @return external IP address
1189 */
1190 public static IpAddress externalGatewayIpSnatEnabled(Router router,
1191 OpenstackNetworkService osNetworkService) {
1192 return externalGatewayIpBase(router, true, osNetworkService);
Jian Liebde74d2018-11-14 00:18:57 +09001193 }
1194
Jian Li2d68c192018-12-13 15:52:59 +09001195 /**
1196 * Returns the tunnel port number with specified net ID and openstack node.
1197 *
1198 * @param netId network ID
1199 * @param netService network service
1200 * @param osNode openstack node
1201 * @return tunnel port number
1202 */
1203 public static PortNumber tunnelPortNumByNetId(String netId,
1204 OpenstackNetworkService netService,
1205 OpenstackNode osNode) {
SONA Project6bc5c4a2018-12-14 23:49:52 +09001206 Type netType = netService.networkType(netId);
Jian Li2d68c192018-12-13 15:52:59 +09001207
1208 if (netType == null) {
1209 return null;
1210 }
1211
1212 return tunnelPortNumByNetType(netType, osNode);
1213 }
1214
1215 /**
1216 * Returns the tunnel port number with specified net type and openstack node.
1217 *
1218 * @param netType network type
1219 * @param osNode openstack node
1220 * @return tunnel port number
1221 */
SONA Project6bc5c4a2018-12-14 23:49:52 +09001222 public static PortNumber tunnelPortNumByNetType(Type netType, OpenstackNode osNode) {
Jian Li2d68c192018-12-13 15:52:59 +09001223 switch (netType) {
1224 case VXLAN:
1225 return osNode.vxlanTunnelPortNum();
1226 case GRE:
1227 return osNode.greTunnelPortNum();
Jian Li621f73c2018-12-15 01:49:22 +09001228 case GENEVE:
1229 return osNode.geneveTunnelPortNum();
Jian Li2d68c192018-12-13 15:52:59 +09001230 default:
1231 return null;
1232 }
1233 }
1234
Jian Li7b8c3682019-05-12 13:57:15 +09001235 /**
1236 * Returns the REST URL of active node.
1237 *
1238 * @param haService openstack HA service
1239 * @return REST URL of active node
1240 */
1241 public static String getActiveUrl(OpenstackHaService haService) {
1242 return "http://" + haService.getActiveIp().toString() + ":" +
1243 REST_PORT + "/" + OPENSTACK_NETWORKING_REST_PATH + "/";
1244 }
1245
1246 /**
1247 * Returns the REST client instance with given resource path.
1248 *
1249 * @param haService openstack HA service
1250 * @param resourcePath resource path
1251 * @return REST client instance
1252 */
1253 public static WebTarget getActiveClient(OpenstackHaService haService,
1254 String resourcePath) {
1255 HttpAuthenticationFeature feature =
1256 HttpAuthenticationFeature.universal(REST_USER, REST_PASSWORD);
1257 Client client = ClientBuilder.newClient().register(feature);
1258 return client.target(getActiveUrl(haService)).path(resourcePath);
1259 }
1260
1261 /**
1262 * Returns the post response from the active node.
1263 *
1264 * @param haService openstack HA service
1265 * @param resourcePath resource path
1266 * @param input input
1267 * @return post response
1268 */
1269 public static Response syncPost(OpenstackHaService haService,
1270 String resourcePath,
1271 String input) {
1272
1273 log.debug("Sync POST request with {} on {}",
1274 haService.getActiveIp().toString(), resourcePath);
1275
1276 return getActiveClient(haService, resourcePath)
1277 .request(APPLICATION_JSON_TYPE)
1278 .post(Entity.json(input));
1279 }
1280
1281 /**
1282 * Returns the put response from the active node.
1283 *
1284 * @param haService openstack HA service
1285 * @param resourcePath resource path
1286 * @param id resource identifier
1287 * @param input input
1288 * @return put response
1289 */
1290 public static Response syncPut(OpenstackHaService haService,
1291 String resourcePath,
1292 String id, String input) {
1293 return syncPut(haService, resourcePath, null, id, input);
1294 }
1295
1296 /**
1297 * Returns the put response from the active node.
1298 *
1299 * @param haService openstack HA service
1300 * @param resourcePath resource path
1301 * @param id resource identifier
1302 * @param suffix resource suffix
1303 * @param input input
1304 * @return put response
1305 */
1306 public static Response syncPut(OpenstackHaService haService,
1307 String resourcePath,
1308 String suffix,
1309 String id, String input) {
1310
1311 log.debug("Sync PUT request with {} on {}",
1312 haService.getActiveIp().toString(), resourcePath);
1313
1314 String pathStr = "/" + id;
1315
1316 if (suffix != null) {
1317 pathStr += "/" + suffix;
1318 }
1319
1320 return getActiveClient(haService, resourcePath)
1321 .path(pathStr)
1322 .request(APPLICATION_JSON_TYPE)
1323 .put(Entity.json(input));
1324 }
1325
1326 /**
1327 * Returns the delete response from the active node.
1328 *
1329 * @param haService openstack HA service
1330 * @param resourcePath resource path
1331 * @param id resource identifier
1332 * @return delete response
1333 */
1334 public static Response syncDelete(OpenstackHaService haService,
1335 String resourcePath,
1336 String id) {
1337
1338 log.debug("Sync DELETE request with {} on {}",
1339 haService.getActiveIp().toString(), resourcePath);
1340
1341 return getActiveClient(haService, resourcePath)
1342 .path("/" + id)
1343 .request(APPLICATION_JSON_TYPE)
1344 .delete();
1345 }
1346
Jian Li51728702019-05-17 18:38:56 +09001347 /**
1348 * Gets the ovsdb client with supplied openstack node.
1349 *
1350 * @param node openstack node
1351 * @param ovsdbPort openvswitch DB port number
1352 * @param controller openvswitch DB controller instance
1353 * @return ovsdb client instance
1354 */
1355 public static OvsdbClientService getOvsdbClient(OpenstackNode node, int ovsdbPort,
1356 OvsdbController controller) {
1357 OvsdbNodeId ovsdb = new OvsdbNodeId(node.managementIp(), ovsdbPort);
1358 return controller.getOvsdbClient(ovsdb);
1359 }
1360
1361 /**
1362 * Obtains the name of interface attached to the openstack VM.
1363 *
1364 * @param portId openstack port identifier
1365 * @return name of interface
1366 */
1367 public static String ifaceNameFromOsPortId(String portId) {
1368 if (portId != null) {
1369 return PORT_NAME_PREFIX_VM + StringUtils.substring(portId, 0, TAP_PORT_LENGTH);
1370 }
1371
1372 return null;
1373 }
1374
Jian Lia5c7edf2020-02-24 16:42:24 +09001375 /**
1376 * Return the router associated with the given subnet.
1377 *
1378 * @param subnet openstack subnet
1379 * @param osRouterService openstack router service
1380 * @return router
1381 */
1382 public static Router getRouterFromSubnet(Subnet subnet,
1383 OpenstackRouterService osRouterService) {
Jian Liebde74d2018-11-14 00:18:57 +09001384 RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
1385 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
1386 .findAny().orElse(null);
1387 if (osRouterIface == null) {
1388 return null;
1389 }
1390
1391 return osRouterService.router(osRouterIface.getId());
1392 }
1393
Daniel Park7e8c4d82018-08-13 23:47:49 +09001394 private static boolean isDirectPort(String portName) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001395 return portNamePrefixMap().values().stream().anyMatch(portName::startsWith);
Daniel Park7e8c4d82018-08-13 23:47:49 +09001396 }
1397
Daniel Park2ff66b42018-08-01 11:52:45 +09001398 /**
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001399 * Returns GARP packet with supplied floating ip and instance port information.
1400 *
1401 * @param floatingIP floating ip
1402 * @param instancePort instance port
1403 * @param vlanId vlan id
1404 * @return GARP packet
1405 */
1406 private static Ethernet buildGratuitousArpPacket(NetFloatingIP floatingIP,
1407 InstancePort instancePort,
1408 VlanId vlanId) {
1409 Ethernet ethernet = new Ethernet();
1410 ethernet.setDestinationMACAddress(MacAddress.BROADCAST);
1411 ethernet.setSourceMACAddress(instancePort.macAddress());
1412 ethernet.setEtherType(Ethernet.TYPE_ARP);
1413 ethernet.setVlanID(vlanId.id());
1414
1415 ARP arp = new ARP();
1416 arp.setOpCode(ARP.OP_REPLY);
1417 arp.setProtocolType(ARP.PROTO_TYPE_IP);
1418 arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
1419
1420 arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
1421 arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
1422
1423 arp.setSenderHardwareAddress(instancePort.macAddress().toBytes());
1424 arp.setTargetHardwareAddress(MacAddress.BROADCAST.toBytes());
1425
Jian Li5ecfd1a2018-12-10 11:41:03 +09001426 arp.setSenderProtocolAddress(valueOf(floatingIP.getFloatingIpAddress()).toInt());
1427 arp.setTargetProtocolAddress(valueOf(floatingIP.getFloatingIpAddress()).toInt());
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001428
1429 ethernet.setPayload(arp);
1430
1431 return ethernet;
1432 }
1433
1434 /**
Jian Li62116942019-09-03 23:10:20 +09001435 * Re-structures the OVS port name.
1436 * The length of OVS port name should be not large than 15.
1437 *
1438 * @param portName original port name
1439 * @return re-structured OVS port name
1440 */
1441 public static String structurePortName(String portName) {
1442
1443 // The size of OVS port name should not be larger than 15
1444 if (portName.length() > PORT_NAME_MAX_LENGTH) {
1445 return StringUtils.substring(portName, 0, PORT_NAME_MAX_LENGTH);
1446 }
1447
1448 return portName;
1449 }
1450
1451 /**
Jian Lie87c2712019-09-11 11:15:16 +09001452 * Obtains flow group key from the given id.
1453 *
1454 * @param groupId flow group identifier
1455 * @return flow group key
1456 */
1457 public static GroupKey getGroupKey(int groupId) {
1458 return new DefaultGroupKey((Integer.toString(groupId)).getBytes());
1459 }
1460
1461 /**
Jian Lif654dd12020-01-30 17:41:26 +09001462 * Calculate the broadcast address from given IP address and subnet prefix length.
1463 *
1464 * @param ipAddr IP address
1465 * @param prefixLength subnet prefix length
1466 * @return broadcast address
1467 */
1468 public static String getBroadcastAddr(String ipAddr, int prefixLength) {
1469 String subnet = ipAddr + "/" + prefixLength;
1470 SubnetUtils utils = new SubnetUtils(subnet);
1471 return utils.getInfo().getBroadcastAddress();
1472 }
1473
1474 /**
Jian Lic55a74f2020-05-11 13:05:47 +09001475 * Obtains the DHCP server name from option.
1476 *
1477 * @param port neutron port
1478 * @return server name
1479 */
1480 public static String getDhcpServerName(NeutronPort port) {
1481 return getDhcpOptionValue(port, "server-ip-address");
1482 }
1483
1484 /**
1485 * Obtains the DHCP static boot file name from option.
1486 *
1487 * @param port neutron port
1488 * @return DHCP static boot file name
1489 */
1490 public static String getDhcpStaticBootFileName(NeutronPort port) {
1491 return getDhcpOptionValue(port, "tag:!ipxe,67");
1492 }
1493
1494 /**
1495 * Obtains the DHCP full boot file name from option.
1496 *
1497 * @param port neutron port
1498 * @return DHCP full boot file name
1499 */
1500 public static String getDhcpFullBootFileName(NeutronPort port) {
1501 return getDhcpOptionValue(port, "tag:ipxe,67");
1502 }
1503
1504 private static String getDhcpOptionValue(NeutronPort port, String optionNameStr) {
1505 ObjectNode node = modelEntityToJson(port, NeutronPort.class);
1506
1507 if (node != null) {
1508 JsonNode portJson = node.get("port");
1509 ArrayNode options = (ArrayNode) portJson.get("extra_dhcp_opts");
1510 for (JsonNode option : options) {
1511 String optionName = option.get("optName").asText();
1512 if (StringUtils.equals(optionName, optionNameStr)) {
1513 return option.get("optValue").asText();
1514 }
1515 }
1516 }
1517
1518 return null;
1519 }
1520
1521 /**
Jian Li51b844c2018-05-31 10:59:03 +09001522 * Builds up and a complete endpoint URL from gateway node.
1523 *
1524 * @param node gateway node
1525 * @return a complete endpoint URL
1526 */
1527 private static String buildEndpoint(OpenstackNode node) {
1528
Jian Lic704b672018-09-04 18:52:53 +09001529 OpenstackAuth auth = node.keystoneConfig().authentication();
Jian Li51b844c2018-05-31 10:59:03 +09001530
1531 StringBuilder endpointSb = new StringBuilder();
1532 endpointSb.append(auth.protocol().name().toLowerCase());
1533 endpointSb.append("://");
Jian Lic704b672018-09-04 18:52:53 +09001534 endpointSb.append(node.keystoneConfig().endpoint());
Jian Li51b844c2018-05-31 10:59:03 +09001535 return endpointSb.toString();
1536 }
1537
1538 /**
1539 * Obtains the SSL config without verifying the certification.
1540 *
1541 * @return SSL config
1542 */
1543 private static Config getSslConfig() {
1544 // we bypass the SSL certification verification for now
1545 // TODO: verify server side SSL using a given certification
1546 Config config = Config.newConfig().withSSLVerificationDisabled();
1547
1548 TrustManager[] trustAllCerts = new TrustManager[]{
1549 new X509TrustManager() {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001550 @Override
Jian Li51b844c2018-05-31 10:59:03 +09001551 public X509Certificate[] getAcceptedIssuers() {
1552 return null;
1553 }
1554
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001555 @Override
Jian Li51b844c2018-05-31 10:59:03 +09001556 public void checkClientTrusted(X509Certificate[] certs,
1557 String authType) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001558 return;
Jian Li51b844c2018-05-31 10:59:03 +09001559 }
1560
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001561 @Override
Jian Li51b844c2018-05-31 10:59:03 +09001562 public void checkServerTrusted(X509Certificate[] certs,
1563 String authType) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001564 return;
Jian Li51b844c2018-05-31 10:59:03 +09001565 }
1566 }
1567 };
1568
1569 HostnameVerifier allHostsValid = (hostname, session) -> true;
1570
1571 try {
1572 SSLContext sc = SSLContext.getInstance(SSL_TYPE);
1573 sc.init(null, trustAllCerts,
1574 new java.security.SecureRandom());
1575 HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
1576 HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
1577
1578 config.withSSLContext(sc);
1579 } catch (Exception e) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001580 log.error("Failed to access OpenStack service due to {}", e);
Jian Li51b844c2018-05-31 10:59:03 +09001581 return null;
1582 }
1583
1584 return config;
1585 }
1586
1587 /**
1588 * Obtains the facing object with given openstack perspective.
1589 *
1590 * @param perspective keystone perspective
1591 * @return facing object
1592 */
1593 private static Facing getFacing(Perspective perspective) {
1594
1595 switch (perspective) {
1596 case PUBLIC:
1597 return Facing.PUBLIC;
1598 case ADMIN:
1599 return Facing.ADMIN;
1600 case INTERNAL:
1601 return Facing.INTERNAL;
1602 default:
1603 return null;
1604 }
1605 }
1606
1607 /**
1608 * Obtains gateway instance by giving index number.
1609 *
1610 * @param gws a collection of gateway nodes
1611 * @param index index number
1612 * @return gateway instance
1613 */
1614 private static OpenstackNode getGwByIndex(Set<OpenstackNode> gws, int index) {
1615 Map<String, OpenstackNode> hashMap = new HashMap<>();
1616 gws.forEach(gw -> hashMap.put(gw.hostname(), gw));
1617 TreeMap<String, OpenstackNode> treeMap = new TreeMap<>(hashMap);
1618 Iterator<String> iteratorKey = treeMap.keySet().iterator();
1619
1620 int intIndex = 0;
1621 OpenstackNode gw = null;
1622 while (iteratorKey.hasNext()) {
1623 String key = iteratorKey.next();
1624
1625 if (intIndex == index) {
1626 gw = treeMap.get(key);
1627 }
1628 intIndex++;
1629 }
1630 return gw;
1631 }
Jian Liecbf10c2019-10-02 20:36:09 +09001632
Jian Lia5c7edf2020-02-24 16:42:24 +09001633 /**
1634 * Returns the external gateway IP address with specified router information.
1635 *
1636 * @param router openstack router
1637 * @param snatOnly true for only query SNAT enabled case, false otherwise
1638 * @param osNetworkService openstack network service
1639 * @return external IP address
1640 */
1641 private static IpAddress externalGatewayIpBase(Router router, boolean snatOnly,
1642 OpenstackNetworkService osNetworkService) {
1643 if (router == null) {
1644 return null;
1645 }
1646
1647 ExternalGateway externalGateway = router.getExternalGatewayInfo();
1648 if (externalGateway == null) {
1649 log.info("Failed to get external IP for router {} because no " +
1650 "external gateway is associated with the router",
1651 router.getId());
1652 return null;
1653 }
1654
1655 if (snatOnly) {
1656 if (!externalGateway.isEnableSnat()) {
1657 log.warn("The given router {} SNAT is configured as false", router.getId());
1658 return null;
1659 }
1660 }
1661
1662 // TODO fix openstack4j for ExternalGateway provides external fixed IP list
1663 Port exGatewayPort = osNetworkService.ports(externalGateway.getNetworkId())
1664 .stream()
1665 .filter(port -> Objects.equals(port.getDeviceId(), router.getId()))
1666 .findAny().orElse(null);
1667
1668 if (exGatewayPort == null) {
1669 return null;
1670 }
1671
1672 return IpAddress.valueOf(exGatewayPort.getFixedIps().stream()
1673 .findAny().get().getIpAddress());
1674 }
1675
Jian Liecbf10c2019-10-02 20:36:09 +09001676 private static void print(String format, Object... args) {
1677 System.out.println(String.format(format, args));
1678 }
Jian Li63430202018-08-30 16:24:09 +09001679}