blob: b881be86672230f9c033876a6a2fa91964e4cf30 [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 Lieb9f77d2018-02-20 11:25:45 +090023import com.fasterxml.jackson.databind.node.ObjectNode;
Daniel Parka73c2362018-09-17 17:43:25 +090024import com.google.common.base.Charsets;
Jian Li24ec59f2018-05-23 19:01:25 +090025import com.google.common.base.Strings;
Daniel Parka73c2362018-09-17 17:43:25 +090026import com.google.common.collect.Lists;
Jian Li63430202018-08-30 16:24:09 +090027import org.apache.commons.codec.binary.Hex;
28import org.apache.http.HttpException;
29import org.apache.http.HttpRequest;
30import org.apache.http.HttpResponse;
31import org.apache.http.impl.io.DefaultHttpRequestParser;
32import org.apache.http.impl.io.DefaultHttpRequestWriter;
33import org.apache.http.impl.io.DefaultHttpResponseParser;
34import org.apache.http.impl.io.DefaultHttpResponseWriter;
35import org.apache.http.impl.io.HttpTransportMetricsImpl;
36import org.apache.http.impl.io.SessionInputBufferImpl;
37import org.apache.http.impl.io.SessionOutputBufferImpl;
38import org.apache.http.io.HttpMessageWriter;
Daniel Parka73c2362018-09-17 17:43:25 +090039import org.apache.sshd.client.SshClient;
40import org.apache.sshd.client.channel.ClientChannel;
41import org.apache.sshd.client.channel.ClientChannelEvent;
42import org.apache.sshd.client.future.OpenFuture;
43import org.apache.sshd.client.session.ClientSession;
44import org.apache.sshd.common.util.io.NoCloseInputStream;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090045import org.onlab.packet.ARP;
46import org.onlab.packet.Ethernet;
47import org.onlab.packet.Ip4Address;
Daniel Parka73c2362018-09-17 17:43:25 +090048import org.onlab.packet.IpAddress;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090049import org.onlab.packet.MacAddress;
50import org.onlab.packet.VlanId;
Jian Li7f70bb72018-07-06 23:35:30 +090051import org.onosproject.cfg.ConfigProperty;
Jian Li1064e4f2018-05-29 16:16:53 +090052import org.onosproject.net.DeviceId;
Daniel Park95f73312018-07-31 15:48:34 +090053import org.onosproject.net.device.DeviceService;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090054import org.onosproject.net.flow.DefaultTrafficTreatment;
55import org.onosproject.net.flow.TrafficTreatment;
56import org.onosproject.net.packet.DefaultOutboundPacket;
57import org.onosproject.net.packet.PacketService;
Daniel Park7e8c4d82018-08-13 23:47:49 +090058import org.onosproject.openstacknetworking.api.Constants.VnicType;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090059import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Jian Lia171a432018-06-11 11:52:11 +090060import org.onosproject.openstacknetworking.api.InstancePort;
Jian Li24ec59f2018-05-23 19:01:25 +090061import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Li7f70bb72018-07-06 23:35:30 +090062import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
Jian Liebde74d2018-11-14 00:18:57 +090063import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Jian Liec5c32b2018-07-13 14:28:58 +090064import org.onosproject.openstacknetworking.impl.DefaultInstancePort;
Jian Li51b844c2018-05-31 10:59:03 +090065import org.onosproject.openstacknode.api.OpenstackAuth;
66import org.onosproject.openstacknode.api.OpenstackAuth.Perspective;
Jian Li1064e4f2018-05-29 16:16:53 +090067import org.onosproject.openstacknode.api.OpenstackNode;
Daniel Parka73c2362018-09-17 17:43:25 +090068import org.onosproject.openstacknode.api.OpenstackSshAuth;
Jian Li51b844c2018-05-31 10:59:03 +090069import org.openstack4j.api.OSClient;
70import org.openstack4j.api.client.IOSClientBuilder;
71import org.openstack4j.api.exceptions.AuthenticationException;
72import org.openstack4j.api.types.Facing;
73import org.openstack4j.core.transport.Config;
Jian Li091d8d22018-02-20 10:42:06 +090074import org.openstack4j.core.transport.ObjectMapperSingleton;
75import org.openstack4j.model.ModelEntity;
Jian Li51b844c2018-05-31 10:59:03 +090076import org.openstack4j.model.common.Identifier;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090077import org.openstack4j.model.network.ExternalGateway;
Jian Li24ec59f2018-05-23 19:01:25 +090078import org.openstack4j.model.network.NetFloatingIP;
79import org.openstack4j.model.network.Network;
Jian Lia171a432018-06-11 11:52:11 +090080import org.openstack4j.model.network.Port;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090081import org.openstack4j.model.network.Router;
Jian Li0b564282018-06-20 00:50:53 +090082import org.openstack4j.model.network.RouterInterface;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090083import org.openstack4j.model.network.Subnet;
Jian Li51b844c2018-05-31 10:59:03 +090084import org.openstack4j.openstack.OSFactory;
Jian Li0b564282018-06-20 00:50:53 +090085import org.openstack4j.openstack.networking.domain.NeutronRouterInterface;
Jian Li091d8d22018-02-20 10:42:06 +090086import org.slf4j.Logger;
87import org.slf4j.LoggerFactory;
88
Jian Li63430202018-08-30 16:24:09 +090089import javax.crypto.Mac;
90import javax.crypto.spec.SecretKeySpec;
Jian Li51b844c2018-05-31 10:59:03 +090091import javax.net.ssl.HostnameVerifier;
92import javax.net.ssl.HttpsURLConnection;
93import javax.net.ssl.SSLContext;
94import javax.net.ssl.TrustManager;
95import javax.net.ssl.X509TrustManager;
Jian Li63430202018-08-30 16:24:09 +090096import java.io.ByteArrayInputStream;
97import java.io.ByteArrayOutputStream;
Jian Li0b564282018-06-20 00:50:53 +090098import java.io.IOException;
Jian Li091d8d22018-02-20 10:42:06 +090099import java.io.InputStream;
Daniel Parka73c2362018-09-17 17:43:25 +0900100import java.io.OutputStream;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900101import java.nio.ByteBuffer;
Jian Li51b844c2018-05-31 10:59:03 +0900102import java.security.cert.X509Certificate;
Daniel Parka73c2362018-09-17 17:43:25 +0900103import java.util.Collection;
Jian Li1064e4f2018-05-29 16:16:53 +0900104import java.util.HashMap;
105import java.util.Iterator;
106import java.util.Map;
Daniel Park95f73312018-07-31 15:48:34 +0900107import java.util.Objects;
Jian Li7f70bb72018-07-06 23:35:30 +0900108import java.util.Optional;
Jian Li1064e4f2018-05-29 16:16:53 +0900109import java.util.Set;
110import java.util.TreeMap;
Daniel Parka73c2362018-09-17 17:43:25 +0900111import java.util.concurrent.TimeUnit;
Jian Li091d8d22018-02-20 10:42:06 +0900112
113import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
Daniel Park95f73312018-07-31 15:48:34 +0900114import static com.google.common.base.Preconditions.checkNotNull;
Jian Li7f024de2018-07-07 03:51:02 +0900115import static com.google.common.base.Strings.isNullOrEmpty;
Daniel Park95f73312018-07-31 15:48:34 +0900116import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Daniel Parka73c2362018-09-17 17:43:25 +0900117import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC_STR;
Daniel Parkc4d06402018-05-28 15:57:37 +0900118import static org.onosproject.openstacknetworking.api.Constants.PCISLOT;
119import static org.onosproject.openstacknetworking.api.Constants.PCI_VENDOR_INFO;
Daniel Park7e8c4d82018-08-13 23:47:49 +0900120import static org.onosproject.openstacknetworking.api.Constants.PORT_NAME_PREFIX_VM;
121import static org.onosproject.openstacknetworking.api.Constants.PORT_NAME_VHOST_USER_PREFIX_VM;
Daniel Parkec9d1132018-08-19 11:18:03 +0900122import static org.onosproject.openstacknetworking.api.Constants.UNSUPPORTED_VENDOR;
Ray Milkey9dc57392018-06-08 08:52:31 -0700123import static org.onosproject.openstacknetworking.api.Constants.portNamePrefixMap;
Jian Li0b564282018-06-20 00:50:53 +0900124import static org.openstack4j.core.transport.ObjectMapperSingleton.getContext;
Jian Li091d8d22018-02-20 10:42:06 +0900125
126/**
127 * An utility that used in openstack networking app.
128 */
Jian Lidea0fdb2018-04-02 19:02:48 +0900129public final class OpenstackNetworkingUtil {
Jian Li091d8d22018-02-20 10:42:06 +0900130
Daniel Park95985382018-07-23 11:38:07 +0900131 private static final Logger log = LoggerFactory.getLogger(OpenstackNetworkingUtil.class);
Jian Li091d8d22018-02-20 10:42:06 +0900132
Daniel Parkc4d06402018-05-28 15:57:37 +0900133 private static final int HEX_RADIX = 16;
Jian Li51b844c2018-05-31 10:59:03 +0900134 private static final String ZERO_FUNCTION_NUMBER = "0";
Daniel Parkc4d06402018-05-28 15:57:37 +0900135 private static final String PREFIX_DEVICE_NUMBER = "s";
136 private static final String PREFIX_FUNCTION_NUMBER = "f";
137
Jian Li51b844c2018-05-31 10:59:03 +0900138 // keystone endpoint related variables
139 private static final String DOMAIN_DEFAULT = "default";
140 private static final String KEYSTONE_V2 = "v2.0";
141 private static final String KEYSTONE_V3 = "v3";
Jian Li51b844c2018-05-31 10:59:03 +0900142 private static final String SSL_TYPE = "SSL";
143
Jian Li7f024de2018-07-07 03:51:02 +0900144 private static final String PROXY_MODE = "proxy";
145 private static final String BROADCAST_MODE = "broadcast";
146
Jian Licad36c72018-09-13 17:44:54 +0900147 private static final String ENABLE = "enable";
148 private static final String DISABLE = "disable";
149
Jian Li63430202018-08-30 16:24:09 +0900150 private static final int HTTP_PAYLOAD_BUFFER = 8 * 1024;
151
152 private static final String HMAC_SHA256 = "HmacSHA256";
153
Jian Li24ec59f2018-05-23 19:01:25 +0900154 private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
155
Daniel Parka73c2362018-09-17 17:43:25 +0900156 private static final String VXLAN = "VXLAN";
157 private static final String VLAN = "VLAN";
158 private static final String DL_DST = "dl_dst=";
159 private static final String NW_DST = "nw_dst=";
160 private static final String DEFAULT_REQUEST_STRING = "sudo ovs-appctl ofproto/trace br-int ip";
161 private static final String IN_PORT = "in_port=";
162 private static final String NW_SRC = "nw_src=";
163 private static final String COMMA = ",";
164 private static final String TUN_ID = "tun_id=";
165
166 private static final long TIMEOUT_MS = 5000;
167 private static final long WAIT_OUTPUT_STREAM_SECOND = 2;
168 private static final int SSH_PORT = 22;
169
Jian Li091d8d22018-02-20 10:42:06 +0900170 /**
171 * Prevents object instantiation from external.
172 */
Jian Lidea0fdb2018-04-02 19:02:48 +0900173 private OpenstackNetworkingUtil() {
Jian Li091d8d22018-02-20 10:42:06 +0900174 }
175
176 /**
177 * Interprets JSON string to corresponding openstack model entity object.
178 *
179 * @param input JSON string
180 * @param entityClazz openstack model entity class
181 * @return openstack model entity object
182 */
183 public static ModelEntity jsonToModelEntity(InputStream input, Class entityClazz) {
184 ObjectMapper mapper = new ObjectMapper();
185 try {
186 JsonNode jsonTree = mapper.enable(INDENT_OUTPUT).readTree(input);
187 log.trace(new ObjectMapper().writeValueAsString(jsonTree));
188 return ObjectMapperSingleton.getContext(entityClazz)
189 .readerFor(entityClazz)
190 .readValue(jsonTree);
191 } catch (Exception e) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900192 log.error("Exception occurred because of {}", e);
Jian Li091d8d22018-02-20 10:42:06 +0900193 throw new IllegalArgumentException();
194 }
195 }
Jian Lieb9f77d2018-02-20 11:25:45 +0900196
197 /**
198 * Converts openstack model entity object into JSON object.
199 *
200 * @param entity openstack model entity object
201 * @param entityClazz openstack model entity class
202 * @return JSON object
203 */
204 public static ObjectNode modelEntityToJson(ModelEntity entity, Class entityClazz) {
205 ObjectMapper mapper = new ObjectMapper();
206 try {
207 String strModelEntity = ObjectMapperSingleton.getContext(entityClazz)
208 .writerFor(entityClazz)
209 .writeValueAsString(entity);
210 log.trace(strModelEntity);
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900211 return (ObjectNode) mapper.readTree(strModelEntity.getBytes(Charsets.UTF_8));
Daniel Park95985382018-07-23 11:38:07 +0900212 } catch (IOException e) {
213 log.error("IOException occurred because of {}", e.toString());
Jian Lieb9f77d2018-02-20 11:25:45 +0900214 throw new IllegalStateException();
215 }
216 }
Jian Li1064e4f2018-05-29 16:16:53 +0900217
218 /**
Jian Li24ec59f2018-05-23 19:01:25 +0900219 * Obtains a floating IP associated with the given instance port.
220 *
221 * @param port instance port
222 * @param fips a collection of floating IPs
223 * @return associated floating IP
224 */
225 public static NetFloatingIP associatedFloatingIp(InstancePort port,
226 Set<NetFloatingIP> fips) {
Daniel Park2ff66b42018-08-01 11:52:45 +0900227 for (NetFloatingIP fip : fips) {
228 if (Strings.isNullOrEmpty(fip.getFixedIpAddress())) {
229 continue;
Jian Li24ec59f2018-05-23 19:01:25 +0900230 }
Daniel Park2ff66b42018-08-01 11:52:45 +0900231 if (Strings.isNullOrEmpty(fip.getFloatingIpAddress())) {
232 continue;
233 }
Jian Li6bc29d92018-10-02 13:55:05 +0900234 if (fip.getFixedIpAddress().equals(port.ipAddress().toString()) &&
235 fip.getPortId().equals(port.portId())) {
Daniel Park2ff66b42018-08-01 11:52:45 +0900236 return fip;
237 }
Jian Li24ec59f2018-05-23 19:01:25 +0900238 }
Daniel Park2ff66b42018-08-01 11:52:45 +0900239
Jian Li24ec59f2018-05-23 19:01:25 +0900240 return null;
241 }
242
243 /**
244 * Checks whether the given floating IP is associated with a VM.
245 *
246 * @param service openstack network service
247 * @param fip floating IP
248 * @return true if the given floating IP associated with a VM, false otherwise
249 */
250 public static boolean isAssociatedWithVM(OpenstackNetworkService service,
251 NetFloatingIP fip) {
252 Port osPort = service.port(fip.getPortId());
253 if (osPort == null) {
254 return false;
255 }
256
257 if (!Strings.isNullOrEmpty(osPort.getDeviceId())) {
258 Network osNet = service.network(osPort.getNetworkId());
259 if (osNet == null) {
260 final String errorFormat = ERR_FLOW + "no network(%s) exists";
261 final String error = String.format(errorFormat,
262 fip.getFloatingIpAddress(), osPort.getNetworkId());
263 throw new IllegalStateException(error);
264 }
265 return true;
266 } else {
267 return false;
268 }
269 }
270
271 /**
Jian Lia171a432018-06-11 11:52:11 +0900272 * Obtains the gateway node by instance port.
273 *
274 * @param gateways a collection of gateway nodes
275 * @param instPort instance port
276 * @return a gateway node
277 */
278 public static OpenstackNode getGwByInstancePort(Set<OpenstackNode> gateways,
279 InstancePort instPort) {
280 OpenstackNode gw = null;
281 if (instPort != null && instPort.deviceId() != null) {
282 gw = getGwByComputeDevId(gateways, instPort.deviceId());
283 }
284 return gw;
285 }
286
287 /**
Jian Li1064e4f2018-05-29 16:16:53 +0900288 * Obtains the gateway node by device in compute node. Note that the gateway
289 * node is determined by device's device identifier.
290 *
291 * @param gws a collection of gateway nodes
292 * @param deviceId device identifier
293 * @return a gateway node
294 */
295 public static OpenstackNode getGwByComputeDevId(Set<OpenstackNode> gws, DeviceId deviceId) {
296 int numOfGw = gws.size();
297
298 if (numOfGw == 0) {
299 return null;
300 }
301
302 int gwIndex = Math.abs(deviceId.hashCode()) % numOfGw;
303
304 return getGwByIndex(gws, gwIndex);
305 }
306
Jian Li51b844c2018-05-31 10:59:03 +0900307 /**
308 * Obtains a connected openstack client.
309 *
310 * @param osNode openstack node
311 * @return a connected openstack client
312 */
313 public static OSClient getConnectedClient(OpenstackNode osNode) {
Jian Lic704b672018-09-04 18:52:53 +0900314 OpenstackAuth auth = osNode.keystoneConfig().authentication();
Jian Li51b844c2018-05-31 10:59:03 +0900315 String endpoint = buildEndpoint(osNode);
316 Perspective perspective = auth.perspective();
Jian Li1064e4f2018-05-29 16:16:53 +0900317
Jian Li51b844c2018-05-31 10:59:03 +0900318 Config config = getSslConfig();
Jian Li1064e4f2018-05-29 16:16:53 +0900319
Jian Li51b844c2018-05-31 10:59:03 +0900320 try {
321 if (endpoint.contains(KEYSTONE_V2)) {
322 IOSClientBuilder.V2 builder = OSFactory.builderV2()
323 .endpoint(endpoint)
324 .tenantName(auth.project())
325 .credentials(auth.username(), auth.password())
326 .withConfig(config);
327
328 if (perspective != null) {
329 builder.perspective(getFacing(perspective));
330 }
331
332 return builder.authenticate();
333 } else if (endpoint.contains(KEYSTONE_V3)) {
334
335 Identifier project = Identifier.byName(auth.project());
336 Identifier domain = Identifier.byName(DOMAIN_DEFAULT);
337
338 IOSClientBuilder.V3 builder = OSFactory.builderV3()
339 .endpoint(endpoint)
340 .credentials(auth.username(), auth.password(), domain)
341 .scopeToProject(project, domain)
342 .withConfig(config);
343
344 if (perspective != null) {
345 builder.perspective(getFacing(perspective));
346 }
347
348 return builder.authenticate();
349 } else {
350 log.warn("Unrecognized keystone version type");
351 return null;
Jian Li1064e4f2018-05-29 16:16:53 +0900352 }
Jian Li51b844c2018-05-31 10:59:03 +0900353 } catch (AuthenticationException e) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900354 log.error("Authentication failed due to {}", e);
Jian Li51b844c2018-05-31 10:59:03 +0900355 return null;
Jian Li1064e4f2018-05-29 16:16:53 +0900356 }
Jian Li1064e4f2018-05-29 16:16:53 +0900357 }
Daniel Parkc4d06402018-05-28 15:57:37 +0900358
359 /**
360 * Extract the interface name with the supplied port.
361 *
362 * @param port port
363 * @return interface name
364 */
365 public static String getIntfNameFromPciAddress(Port port) {
Daniel Parkff178ba2018-11-23 15:57:24 +0900366 String intfName;
367
Daniel Park95985382018-07-23 11:38:07 +0900368 if (port.getProfile() == null || port.getProfile().isEmpty()) {
Jian Li51b844c2018-05-31 10:59:03 +0900369 log.error("Port profile is not found");
370 return null;
371 }
372
Daniel Park95985382018-07-23 11:38:07 +0900373 if (!port.getProfile().containsKey(PCISLOT) ||
374 Strings.isNullOrEmpty(port.getProfile().get(PCISLOT).toString())) {
Daniel Parkc4d06402018-05-28 15:57:37 +0900375 log.error("Failed to retrieve the interface name because of no pci_slot information from the port");
376 return null;
377 }
Jian Li51b844c2018-05-31 10:59:03 +0900378
Daniel Parkff178ba2018-11-23 15:57:24 +0900379 String vendorInfoForPort = String.valueOf(port.getProfile().get(PCI_VENDOR_INFO));
380
381 if (!portNamePrefixMap().containsKey(vendorInfoForPort)) {
382 log.debug("{} is an non-smart NIC prefix.", vendorInfoForPort);
383 return UNSUPPORTED_VENDOR;
384 }
385
386 String portNamePrefix = portNamePrefixMap().get(vendorInfoForPort);
387
Daniel Parkc4d06402018-05-28 15:57:37 +0900388 String busNumHex = port.getProfile().get(PCISLOT).toString().split(":")[1];
389 String busNumDecimal = String.valueOf(Integer.parseInt(busNumHex, HEX_RADIX));
390
391 String deviceNumHex = port.getProfile().get(PCISLOT).toString()
392 .split(":")[2]
393 .split("\\.")[0];
394 String deviceNumDecimal = String.valueOf(Integer.parseInt(deviceNumHex, HEX_RADIX));
395
396 String functionNumHex = port.getProfile().get(PCISLOT).toString()
397 .split(":")[2]
398 .split("\\.")[1];
399 String functionNumDecimal = String.valueOf(Integer.parseInt(functionNumHex, HEX_RADIX));
400
Daniel Parkc4d06402018-05-28 15:57:37 +0900401 if (functionNumDecimal.equals(ZERO_FUNCTION_NUMBER)) {
402 intfName = portNamePrefix + busNumDecimal + PREFIX_DEVICE_NUMBER + deviceNumDecimal;
403 } else {
404 intfName = portNamePrefix + busNumDecimal + PREFIX_DEVICE_NUMBER + deviceNumDecimal
405 + PREFIX_FUNCTION_NUMBER + functionNumDecimal;
406 }
407
408 return intfName;
409 }
Jian Li51b844c2018-05-31 10:59:03 +0900410
411 /**
Daniel Park95f73312018-07-31 15:48:34 +0900412 * Check if the given interface is added to the given device or not.
413 *
414 * @param deviceId device ID
415 * @param intfName interface name
416 * @param deviceService device service
417 * @return true if the given interface is added to the given device or false otherwise
418 */
419 public static boolean hasIntfAleadyInDevice(DeviceId deviceId, String intfName, DeviceService deviceService) {
420 checkNotNull(deviceId);
421 checkNotNull(intfName);
422
423 return deviceService.getPorts(deviceId).stream()
424 .anyMatch(port -> Objects.equals(port.annotations().value(PORT_NAME), intfName));
425 }
426
427 /**
Jian Li0b564282018-06-20 00:50:53 +0900428 * Adds router interfaces to openstack admin service.
Jian Li0b564282018-06-20 00:50:53 +0900429 *
430 * @param osPort port
431 * @param adminService openstack admin service
432 */
433 public static void addRouterIface(Port osPort, OpenstackRouterAdminService adminService) {
434 osPort.getFixedIps().forEach(p -> {
435 JsonNode jsonTree = new ObjectMapper().createObjectNode()
436 .put("id", osPort.getDeviceId())
437 .put("tenant_id", osPort.getTenantId())
438 .put("subnet_id", p.getSubnetId())
439 .put("port_id", osPort.getId());
440 try {
441 RouterInterface rIface = getContext(NeutronRouterInterface.class)
442 .readerFor(NeutronRouterInterface.class)
443 .readValue(jsonTree);
444 if (adminService.routerInterface(rIface.getPortId()) != null) {
445 adminService.updateRouterInterface(rIface);
446 } else {
447 adminService.addRouterInterface(rIface);
448 }
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900449 } catch (IOException e) {
450 log.error("IOException occurred because of {}", e);
Jian Li0b564282018-06-20 00:50:53 +0900451 }
452 });
453 }
454
455 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900456 * Obtains the property value with specified property key name.
457 *
458 * @param properties a collection of properties
459 * @param name key name
460 * @return mapping value
461 */
462 public static String getPropertyValue(Set<ConfigProperty> properties, String name) {
463 Optional<ConfigProperty> property =
464 properties.stream().filter(p -> p.name().equals(name)).findFirst();
465 return property.map(ConfigProperty::value).orElse(null);
466 }
467
468 /**
Jian Li9d35bd62018-10-13 01:43:24 +0900469 * Obtains the boolean property value with specified property key name.
470 *
471 * @param properties a collection of properties
472 * @param name key name
473 * @return mapping value
474 */
475 public static boolean getPropertyValueAsBoolean(Set<ConfigProperty> properties, String name) {
476 Optional<ConfigProperty> property =
477 properties.stream().filter(p -> p.name().equals(name)).findFirst();
478
479 return property.map(ConfigProperty::asBoolean).orElse(false);
480 }
481
482 /**
Jian Lif1efbe52018-07-17 23:20:16 +0900483 * Prints out the JSON string in pretty format.
484 *
485 * @param mapper Object mapper
486 * @param jsonString JSON string
487 * @return pretty formatted JSON string
488 */
489 public static String prettyJson(ObjectMapper mapper, String jsonString) {
490 try {
491 Object jsonObject = mapper.readValue(jsonString, Object.class);
492 return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject);
Daniel Park2ff66b42018-08-01 11:52:45 +0900493 } catch (JsonParseException e) {
494 log.debug("JsonParseException caused by {}", e);
495 } catch (JsonMappingException e) {
496 log.debug("JsonMappingException caused by {}", e);
497 } catch (JsonProcessingException e) {
498 log.debug("JsonProcessingException caused by {}", e);
Jian Lif1efbe52018-07-17 23:20:16 +0900499 } catch (IOException e) {
Daniel Park2ff66b42018-08-01 11:52:45 +0900500 log.debug("IOException caused by {}", e);
Jian Lif1efbe52018-07-17 23:20:16 +0900501 }
502 return null;
503 }
504
505 /**
Jian Li7f024de2018-07-07 03:51:02 +0900506 * Checks the validity of ARP mode.
507 *
508 * @param arpMode ARP mode
509 * @return returns true if the ARP mode is valid, false otherwise
510 */
511 public static boolean checkArpMode(String arpMode) {
512
513 if (isNullOrEmpty(arpMode)) {
514 return false;
515 } else {
516 return arpMode.equals(PROXY_MODE) || arpMode.equals(BROADCAST_MODE);
517 }
518 }
519
520 /**
Jian Licad36c72018-09-13 17:44:54 +0900521 * Checks the validity of activation flag.
522 *
523 * @param activationFlag activation flag
524 * @return returns true if the activation flag is valid, false otherwise
525 */
526 public static boolean checkActivationFlag(String activationFlag) {
527
528 switch (activationFlag) {
529 case ENABLE:
530 return true;
531 case DISABLE:
532 return false;
533 default:
534 throw new IllegalArgumentException("The given activation flag is not valid!");
535 }
536 }
537
538 /**
Jian Liec5c32b2018-07-13 14:28:58 +0900539 * Swaps current location with old location info.
540 * The revised instance port will be used to mod the flow rules after migration.
541 *
542 * @param instPort instance port
543 * @return location swapped instance port
544 */
545 public static InstancePort swapStaleLocation(InstancePort instPort) {
546 return DefaultInstancePort.builder()
547 .deviceId(instPort.oldDeviceId())
548 .portNumber(instPort.oldPortNumber())
549 .state(instPort.state())
550 .ipAddress(instPort.ipAddress())
551 .macAddress(instPort.macAddress())
552 .networkId(instPort.networkId())
553 .portId(instPort.portId())
554 .build();
555 }
556
557 /**
Daniel Park2ff66b42018-08-01 11:52:45 +0900558 * Compares two router interfaces are equal.
559 * Will be remove this after Openstack4j implements equals.
560 *
561 * @param routerInterface1 router interface
562 * @param routerInterface2 router interface
563 * @return returns true if two router interfaces are equal, false otherwise
564 */
Jian Li63430202018-08-30 16:24:09 +0900565 public static boolean routerInterfacesEquals(RouterInterface routerInterface1,
566 RouterInterface routerInterface2) {
Daniel Park2ff66b42018-08-01 11:52:45 +0900567 return Objects.equals(routerInterface1.getId(), routerInterface2.getId()) &&
568 Objects.equals(routerInterface1.getPortId(), routerInterface2.getPortId()) &&
569 Objects.equals(routerInterface1.getSubnetId(), routerInterface2.getSubnetId()) &&
570 Objects.equals(routerInterface1.getTenantId(), routerInterface2.getTenantId());
571 }
572
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900573 /**
574 * Returns the vnic type of given port.
575 *
576 * @param portName port name
577 * @return vnit type
578 */
Daniel Park7e8c4d82018-08-13 23:47:49 +0900579 public static VnicType vnicType(String portName) {
580 if (portName.startsWith(PORT_NAME_PREFIX_VM) ||
581 portName.startsWith(PORT_NAME_VHOST_USER_PREFIX_VM)) {
582 return VnicType.NORMAL;
583 } else if (isDirectPort(portName)) {
584 return VnicType.DIRECT;
585 } else {
586 return VnicType.UNSUPPORTED;
587 }
588 }
589
Jian Li63430202018-08-30 16:24:09 +0900590 /**
591 * Deserializes raw payload into HttpRequest object.
592 *
593 * @param rawData raw http payload
594 * @return HttpRequest object
595 */
596 public static HttpRequest parseHttpRequest(byte[] rawData) {
597 SessionInputBufferImpl sessionInputBuffer =
598 new SessionInputBufferImpl(
599 new HttpTransportMetricsImpl(), HTTP_PAYLOAD_BUFFER);
600 sessionInputBuffer.bind(new ByteArrayInputStream(rawData));
601 DefaultHttpRequestParser requestParser = new DefaultHttpRequestParser(sessionInputBuffer);
602 try {
603 return requestParser.parse();
604 } catch (IOException | HttpException e) {
605 log.warn("Failed to parse HttpRequest, due to {}", e);
606 }
607
608 return null;
609 }
610
611 /**
612 * Serializes HttpRequest object to byte array.
613 *
614 * @param request http request object
615 * @return byte array
616 */
617 public static byte[] unparseHttpRequest(HttpRequest request) {
618 try {
619 SessionOutputBufferImpl sessionOutputBuffer =
620 new SessionOutputBufferImpl(
621 new HttpTransportMetricsImpl(), HTTP_PAYLOAD_BUFFER);
622
623 ByteArrayOutputStream baos = new ByteArrayOutputStream();
624 sessionOutputBuffer.bind(baos);
625
626 HttpMessageWriter<HttpRequest> requestWriter = new DefaultHttpRequestWriter(
627 sessionOutputBuffer);
628 requestWriter.write(request);
629 sessionOutputBuffer.flush();
630
631 return baos.toByteArray();
632 } catch (HttpException | IOException e) {
633 log.warn("Failed to unparse HttpRequest, due to {}", e);
634 }
635
636 return null;
637 }
638
639 /**
640 * Deserializes raw payload into HttpResponse object.
641 *
642 * @param rawData raw http payload
643 * @return HttpResponse object
644 */
645 public static HttpResponse parseHttpResponse(byte[] rawData) {
646 SessionInputBufferImpl sessionInputBuffer =
647 new SessionInputBufferImpl(
648 new HttpTransportMetricsImpl(), HTTP_PAYLOAD_BUFFER);
649 sessionInputBuffer.bind(new ByteArrayInputStream(rawData));
650 DefaultHttpResponseParser responseParser = new DefaultHttpResponseParser(sessionInputBuffer);
651 try {
652 return responseParser.parse();
653 } catch (IOException | HttpException e) {
654 log.warn("Failed to parse HttpResponse, due to {}", e);
655 }
656
657 return null;
658 }
659
660 /**
661 * Serializes HttpResponse header to byte array.
662 *
663 * @param response http response object
664 * @return byte array
665 */
666 public static byte[] unparseHttpResponseHeader(HttpResponse response) {
667 try {
668 SessionOutputBufferImpl sessionOutputBuffer =
669 new SessionOutputBufferImpl(
670 new HttpTransportMetricsImpl(), HTTP_PAYLOAD_BUFFER);
671
672 ByteArrayOutputStream headerBaos = new ByteArrayOutputStream();
673 sessionOutputBuffer.bind(headerBaos);
674
675 HttpMessageWriter<HttpResponse> responseWriter =
676 new DefaultHttpResponseWriter(sessionOutputBuffer);
677 responseWriter.write(response);
678 sessionOutputBuffer.flush();
679
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900680 log.debug(headerBaos.toString(Charsets.UTF_8.name()));
Jian Li63430202018-08-30 16:24:09 +0900681
682 return headerBaos.toByteArray();
683 } catch (IOException | HttpException e) {
684 log.warn("Failed to unparse HttpResponse headers, due to {}", e);
685 }
686
687 return null;
688 }
689
690 /**
691 * Serializes HttpResponse object to byte array.
692 *
693 * @param response http response object
694 * @return byte array
695 */
696 public static byte[] unparseHttpResponseBody(HttpResponse response) {
697 try {
698 ByteArrayOutputStream baos = new ByteArrayOutputStream();
699 response.getEntity().writeTo(baos);
700
701 log.debug(response.toString());
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900702 log.debug(baos.toString(Charsets.UTF_8.name()));
Jian Li63430202018-08-30 16:24:09 +0900703
704 return baos.toByteArray();
705 } catch (IOException e) {
706 log.warn("Failed to unparse HttpResponse, due to {}", e);
707 }
708
709 return null;
710 }
711
712 /**
713 * Encodes the given data using HmacSHA256 encryption method with given secret key.
714 *
715 * @param key secret key
716 * @param data data to be encrypted
717 * @return Hmac256 encrypted data
718 */
719 public static String hmacEncrypt(String key, String data) {
720 try {
721 Mac sha256Hmac = Mac.getInstance(HMAC_SHA256);
722 SecretKeySpec secretKey = new SecretKeySpec(key.getBytes("UTF-8"), HMAC_SHA256);
723 sha256Hmac.init(secretKey);
724 return Hex.encodeHexString(sha256Hmac.doFinal(data.getBytes("UTF-8")));
725 } catch (Exception e) {
726 log.warn("Failed to encrypt data {} using key {}, due to {}", data, key, e);
727 }
728 return null;
729 }
730
Daniel Parka73c2362018-09-17 17:43:25 +0900731 /**
732 * Creates flow trace request string.
733 *
734 * @param srcIp src ip address
735 * @param dstIp dst ip address
736 * @param srcInstancePort src instance port
737 * @param osNetService openstack networking service
Daniel Park5aef9822018-09-20 18:04:18 +0900738 * @param uplink true if this request is for uplink
Daniel Parka73c2362018-09-17 17:43:25 +0900739 * @return flow trace request string
740 */
741 public static String traceRequestString(String srcIp,
742 String dstIp,
743 InstancePort srcInstancePort,
744 OpenstackNetworkService osNetService, boolean uplink) {
745
746 StringBuilder requestStringBuilder = new StringBuilder(DEFAULT_REQUEST_STRING);
747
748 if (uplink) {
749
750 requestStringBuilder.append(COMMA)
751 .append(IN_PORT)
752 .append(srcInstancePort.portNumber().toString())
753 .append(COMMA)
754 .append(NW_SRC)
755 .append(srcIp)
756 .append(COMMA);
757
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900758 String modifiedDstIp = dstIp;
Daniel Parka73c2362018-09-17 17:43:25 +0900759 if (osNetService.networkType(srcInstancePort.networkId()).equals(VXLAN) ||
760 osNetService.networkType(srcInstancePort.networkId()).equals(VLAN)) {
761 if (srcIp.equals(dstIp)) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900762 modifiedDstIp = osNetService.gatewayIp(srcInstancePort.portId());
Daniel Parka73c2362018-09-17 17:43:25 +0900763 requestStringBuilder.append(DL_DST)
764 .append(DEFAULT_GATEWAY_MAC_STR).append(COMMA);
765 } else if (!osNetService.ipPrefix(srcInstancePort.portId()).contains(IpAddress.valueOf(dstIp))) {
766 requestStringBuilder.append(DL_DST)
767 .append(DEFAULT_GATEWAY_MAC_STR)
768 .append(COMMA);
769 }
770 } else {
771 if (srcIp.equals(dstIp)) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900772 modifiedDstIp = osNetService.gatewayIp(srcInstancePort.portId());
Daniel Parka73c2362018-09-17 17:43:25 +0900773 }
774 }
775
776 requestStringBuilder.append(NW_DST)
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900777 .append(modifiedDstIp)
Daniel Parka73c2362018-09-17 17:43:25 +0900778 .append("\n");
779 } else {
780 requestStringBuilder.append(COMMA)
781 .append(NW_SRC)
782 .append(dstIp)
783 .append(COMMA);
784
785 if (osNetService.networkType(srcInstancePort.networkId()).equals(VXLAN) ||
786 osNetService.networkType(srcInstancePort.networkId()).equals(VLAN)) {
787 requestStringBuilder.append(TUN_ID)
788 .append(osNetService.segmentId(srcInstancePort.networkId()))
789 .append(COMMA);
790 }
791 requestStringBuilder.append(NW_DST)
792 .append(srcIp)
793 .append("\n");
Daniel Parka73c2362018-09-17 17:43:25 +0900794 }
795
796 return requestStringBuilder.toString();
797 }
798
799 /**
800 * Sends flow trace string to node.
801 *
802 * @param requestString reqeust string
803 * @param node src node
804 * @return flow trace result in string format
805 */
806 public static String sendTraceRequestToNode(String requestString,
807 OpenstackNode node) {
808 String traceResult = null;
809 OpenstackSshAuth sshAuth = node.sshAuthInfo();
810
811 try (SshClient client = SshClient.setUpDefaultClient()) {
812 client.start();
813
814 try (ClientSession session = client
815 .connect(sshAuth.id(), node.managementIp().getIp4Address().toString(), SSH_PORT)
816 .verify(TIMEOUT_MS, TimeUnit.SECONDS).getSession()) {
817 session.addPasswordIdentity(sshAuth.password());
818 session.auth().verify(TIMEOUT_MS, TimeUnit.SECONDS);
819
820
821 try (ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL)) {
822
823 log.debug("requestString: {}", requestString);
824 final InputStream inputStream =
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900825 new ByteArrayInputStream(requestString.getBytes(Charsets.UTF_8));
Daniel Parka73c2362018-09-17 17:43:25 +0900826
827 OutputStream outputStream = new ByteArrayOutputStream();
828 OutputStream errStream = new ByteArrayOutputStream();
829
830 channel.setIn(new NoCloseInputStream(inputStream));
831 channel.setErr(errStream);
832 channel.setOut(outputStream);
833
834 Collection<ClientChannelEvent> eventList = Lists.newArrayList();
835 eventList.add(ClientChannelEvent.OPENED);
836
837 OpenFuture channelFuture = channel.open();
838
839 if (channelFuture.await(TIMEOUT_MS, TimeUnit.SECONDS)) {
840
841 long timeoutExpiredMs = System.currentTimeMillis() + TIMEOUT_MS;
842
843 while (!channelFuture.isOpened()) {
844 if ((timeoutExpiredMs - System.currentTimeMillis()) <= 0) {
845 log.error("Failed to open channel");
846 return null;
847 }
848 }
849 TimeUnit.SECONDS.sleep(WAIT_OUTPUT_STREAM_SECOND);
850
851 traceResult = ((ByteArrayOutputStream) outputStream).toString(Charsets.UTF_8.name());
852
853 channel.close();
854 }
855 } finally {
856 session.close();
857 }
858 } finally {
859 client.stop();
860 }
861
862 } catch (Exception e) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900863 log.error("Exception occurred because of {}", e);
Daniel Parka73c2362018-09-17 17:43:25 +0900864 }
865
866 return traceResult;
867 }
868
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900869 /**
870 * Returns the floating ip with supplied instance port.
871 *
872 * @param instancePort instance port
873 * @param osRouterAdminService openstack router admin service
874 * @return floating ip
875 */
876 public static NetFloatingIP floatingIpByInstancePort(InstancePort instancePort,
877 OpenstackRouterAdminService osRouterAdminService) {
878 return osRouterAdminService.floatingIps().stream()
879 .filter(netFloatingIP -> netFloatingIP.getPortId() != null)
880 .filter(netFloatingIP -> netFloatingIP.getPortId().equals(instancePort.portId()))
881 .findAny().orElse(null);
882 }
883
884 /**
885 * Sends GARP packet with supplied floating ip information.
886 *
887 * @param floatingIP floating ip
888 * @param instancePort instance port
889 * @param vlanId vlain id
890 * @param gatewayNode gateway node
891 * @param packetService packet service
892 */
Jian Li32b03622018-11-06 17:54:24 +0900893 public static void processGarpPacketForFloatingIp(NetFloatingIP floatingIP,
894 InstancePort instancePort,
895 VlanId vlanId,
896 OpenstackNode gatewayNode,
897 PacketService packetService) {
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900898 Ethernet ethernet = buildGratuitousArpPacket(floatingIP, instancePort, vlanId);
899
900 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
901 .setOutput(gatewayNode.uplinkPortNum()).build();
902
903 packetService.emit(new DefaultOutboundPacket(gatewayNode.intgBridge(), treatment,
904 ByteBuffer.wrap(ethernet.serialize())));
905 }
906
907 /**
908 * Returns the external peer router with supplied network information.
909 *
910 * @param network network
911 * @param osNetworkService openstack network service
912 * @param osRouterAdminService openstack router admin service
913 * @return external peer router
914 */
915 public static ExternalPeerRouter externalPeerRouterForNetwork(Network network,
916 OpenstackNetworkService osNetworkService,
917 OpenstackRouterAdminService osRouterAdminService) {
918 if (network == null) {
919 return null;
920 }
921
922 Subnet subnet = osNetworkService.subnets(network.getId()).stream().findAny().orElse(null);
923
924 if (subnet == null) {
925 return null;
926 }
927
928 RouterInterface osRouterIface = osRouterAdminService.routerInterfaces().stream()
929 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
930 .findAny().orElse(null);
931 if (osRouterIface == null) {
932 return null;
933 }
934
935 Router osRouter = osRouterAdminService.router(osRouterIface.getId());
Daniel Parka3ffbdb2018-11-28 13:51:39 +0900936 if (osRouter == null || osRouter.getExternalGatewayInfo() == null) {
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900937 return null;
938 }
939
940 ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
941 return osNetworkService.externalPeerRouter(exGatewayInfo);
942
943 }
944
Jian Liebde74d2018-11-14 00:18:57 +0900945 /**
946 * Returns the external peer router with specified subnet information.
947 *
948 * @param subnet openstack subnet
949 * @param osRouterService openstack router service
950 * @param osNetworkService openstack network service
951 * @return external peer router
952 */
953 public static ExternalPeerRouter externalPeerRouterFromSubnet(Subnet subnet, OpenstackRouterService osRouterService,
954 OpenstackNetworkService osNetworkService) {
955 Router osRouter = getRouterFromSubnet(subnet, osRouterService);
956 if (osRouter == null) {
957 return null;
958 }
959 if (osRouter.getExternalGatewayInfo() == null) {
960 // this router does not have external connectivity
961 log.trace("router({}) has no external gateway",
962 osRouter.getName());
963 return null;
964 }
965
966 return osNetworkService.externalPeerRouter(osRouter.getExternalGatewayInfo());
967 }
968
969 /**
970 * Returns the external ip address with specified router information.
971 *
972 * @param srcSubnet source subnet
973 * @param osRouterService openstack router service
974 * @param osNetworkService openstack network service
975 * @return external ip address
976 */
977 public static IpAddress externalIpFromSubnet(Subnet srcSubnet,
978 OpenstackRouterService osRouterService,
979 OpenstackNetworkService osNetworkService) {
980
981 Router osRouter = getRouterFromSubnet(srcSubnet, osRouterService);
982
983 if (osRouter.getExternalGatewayInfo() == null) {
984 // this router does not have external connectivity
985 log.trace("router({}) has no external gateway",
986 osRouter.getName());
987 return null;
988 }
989
990 return getExternalIp(osRouter, osNetworkService);
991 }
992
993 /**
994 * Returns the external ip address with specified router information.
995 *
996 * @param router openstack router
997 * @param osNetworkService openstack network service
998 * @return external ip address
999 */
1000 public static IpAddress getExternalIp(Router router, OpenstackNetworkService osNetworkService) {
1001 if (router == null) {
1002 return null;
1003 }
1004
1005 ExternalGateway externalGateway = router.getExternalGatewayInfo();
1006 if (externalGateway == null || !externalGateway.isEnableSnat()) {
1007 log.trace("Failed to get externalIp for router {} because externalGateway is null or SNAT is disabled",
1008 router.getId());
1009 return null;
1010 }
1011
1012 // TODO fix openstack4j for ExternalGateway provides external fixed IP list
1013 Port exGatewayPort = osNetworkService.ports(externalGateway.getNetworkId())
1014 .stream()
1015 .filter(port -> Objects.equals(port.getDeviceId(), router.getId()))
1016 .findAny().orElse(null);
1017
1018 if (exGatewayPort == null) {
1019 return null;
1020 }
1021
1022 return IpAddress.valueOf(exGatewayPort.getFixedIps().stream()
1023 .findAny().get().getIpAddress());
1024 }
1025
1026 private static Router getRouterFromSubnet(Subnet subnet, OpenstackRouterService osRouterService) {
1027 RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
1028 .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
1029 .findAny().orElse(null);
1030 if (osRouterIface == null) {
1031 return null;
1032 }
1033
1034 return osRouterService.router(osRouterIface.getId());
1035 }
1036
Daniel Park7e8c4d82018-08-13 23:47:49 +09001037 private static boolean isDirectPort(String portName) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001038 return portNamePrefixMap().values().stream().anyMatch(portName::startsWith);
Daniel Park7e8c4d82018-08-13 23:47:49 +09001039 }
1040
Daniel Park2ff66b42018-08-01 11:52:45 +09001041 /**
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001042 * Returns GARP packet with supplied floating ip and instance port information.
1043 *
1044 * @param floatingIP floating ip
1045 * @param instancePort instance port
1046 * @param vlanId vlan id
1047 * @return GARP packet
1048 */
1049 private static Ethernet buildGratuitousArpPacket(NetFloatingIP floatingIP,
1050 InstancePort instancePort,
1051 VlanId vlanId) {
1052 Ethernet ethernet = new Ethernet();
1053 ethernet.setDestinationMACAddress(MacAddress.BROADCAST);
1054 ethernet.setSourceMACAddress(instancePort.macAddress());
1055 ethernet.setEtherType(Ethernet.TYPE_ARP);
1056 ethernet.setVlanID(vlanId.id());
1057
1058 ARP arp = new ARP();
1059 arp.setOpCode(ARP.OP_REPLY);
1060 arp.setProtocolType(ARP.PROTO_TYPE_IP);
1061 arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
1062
1063 arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
1064 arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
1065
1066 arp.setSenderHardwareAddress(instancePort.macAddress().toBytes());
1067 arp.setTargetHardwareAddress(MacAddress.BROADCAST.toBytes());
1068
1069 arp.setSenderProtocolAddress(Ip4Address.valueOf(floatingIP.getFloatingIpAddress()).toInt());
1070 arp.setTargetProtocolAddress(Ip4Address.valueOf(floatingIP.getFloatingIpAddress()).toInt());
1071
1072 ethernet.setPayload(arp);
1073
1074 return ethernet;
1075 }
1076
1077 /**
Jian Li51b844c2018-05-31 10:59:03 +09001078 * Builds up and a complete endpoint URL from gateway node.
1079 *
1080 * @param node gateway node
1081 * @return a complete endpoint URL
1082 */
1083 private static String buildEndpoint(OpenstackNode node) {
1084
Jian Lic704b672018-09-04 18:52:53 +09001085 OpenstackAuth auth = node.keystoneConfig().authentication();
Jian Li51b844c2018-05-31 10:59:03 +09001086
1087 StringBuilder endpointSb = new StringBuilder();
1088 endpointSb.append(auth.protocol().name().toLowerCase());
1089 endpointSb.append("://");
Jian Lic704b672018-09-04 18:52:53 +09001090 endpointSb.append(node.keystoneConfig().endpoint());
Jian Li51b844c2018-05-31 10:59:03 +09001091 return endpointSb.toString();
1092 }
1093
1094 /**
1095 * Obtains the SSL config without verifying the certification.
1096 *
1097 * @return SSL config
1098 */
1099 private static Config getSslConfig() {
1100 // we bypass the SSL certification verification for now
1101 // TODO: verify server side SSL using a given certification
1102 Config config = Config.newConfig().withSSLVerificationDisabled();
1103
1104 TrustManager[] trustAllCerts = new TrustManager[]{
1105 new X509TrustManager() {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001106 @Override
Jian Li51b844c2018-05-31 10:59:03 +09001107 public X509Certificate[] getAcceptedIssuers() {
1108 return null;
1109 }
1110
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001111 @Override
Jian Li51b844c2018-05-31 10:59:03 +09001112 public void checkClientTrusted(X509Certificate[] certs,
1113 String authType) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001114 return;
Jian Li51b844c2018-05-31 10:59:03 +09001115 }
1116
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001117 @Override
Jian Li51b844c2018-05-31 10:59:03 +09001118 public void checkServerTrusted(X509Certificate[] certs,
1119 String authType) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001120 return;
Jian Li51b844c2018-05-31 10:59:03 +09001121 }
1122 }
1123 };
1124
1125 HostnameVerifier allHostsValid = (hostname, session) -> true;
1126
1127 try {
1128 SSLContext sc = SSLContext.getInstance(SSL_TYPE);
1129 sc.init(null, trustAllCerts,
1130 new java.security.SecureRandom());
1131 HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
1132 HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
1133
1134 config.withSSLContext(sc);
1135 } catch (Exception e) {
Daniel Parka3ffbdb2018-11-28 13:51:39 +09001136 log.error("Failed to access OpenStack service due to {}", e);
Jian Li51b844c2018-05-31 10:59:03 +09001137 return null;
1138 }
1139
1140 return config;
1141 }
1142
1143 /**
1144 * Obtains the facing object with given openstack perspective.
1145 *
1146 * @param perspective keystone perspective
1147 * @return facing object
1148 */
1149 private static Facing getFacing(Perspective perspective) {
1150
1151 switch (perspective) {
1152 case PUBLIC:
1153 return Facing.PUBLIC;
1154 case ADMIN:
1155 return Facing.ADMIN;
1156 case INTERNAL:
1157 return Facing.INTERNAL;
1158 default:
1159 return null;
1160 }
1161 }
1162
1163 /**
1164 * Obtains gateway instance by giving index number.
1165 *
1166 * @param gws a collection of gateway nodes
1167 * @param index index number
1168 * @return gateway instance
1169 */
1170 private static OpenstackNode getGwByIndex(Set<OpenstackNode> gws, int index) {
1171 Map<String, OpenstackNode> hashMap = new HashMap<>();
1172 gws.forEach(gw -> hashMap.put(gw.hostname(), gw));
1173 TreeMap<String, OpenstackNode> treeMap = new TreeMap<>(hashMap);
1174 Iterator<String> iteratorKey = treeMap.keySet().iterator();
1175
1176 int intIndex = 0;
1177 OpenstackNode gw = null;
1178 while (iteratorKey.hasNext()) {
1179 String key = iteratorKey.next();
1180
1181 if (intIndex == index) {
1182 gw = treeMap.get(key);
1183 }
1184 intIndex++;
1185 }
1186 return gw;
1187 }
Jian Li63430202018-08-30 16:24:09 +09001188}