blob: bfb2916f7abb6007d4a7aa99c77faf6a986b1ec6 [file] [log] [blame]
Jian Li43244382021-01-09 00:19:02 +09001/*
2 * Copyright 2021-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.kubevirtnetworking.util;
17
Jian Lif97a07e2021-01-13 18:05:00 +090018import com.fasterxml.jackson.databind.ObjectMapper;
Jian Li556709c2021-02-03 17:54:28 +090019import com.google.common.base.Strings;
Jian Lid4296d02021-03-12 18:03:58 +090020import com.google.common.collect.ImmutableSet;
Jian Lica20b712021-01-18 00:19:31 +090021import io.fabric8.kubernetes.api.model.Pod;
Jian Li034820d2021-01-15 16:58:48 +090022import io.fabric8.kubernetes.client.ConfigBuilder;
23import io.fabric8.kubernetes.client.DefaultKubernetesClient;
24import io.fabric8.kubernetes.client.KubernetesClient;
Jian Li43244382021-01-09 00:19:02 +090025import org.apache.commons.lang.StringUtils;
Jian Li3ba5c582021-01-14 11:30:36 +090026import org.apache.commons.net.util.SubnetUtils;
Jian Lica20b712021-01-18 00:19:31 +090027import org.json.JSONArray;
28import org.json.JSONException;
29import org.json.JSONObject;
Jian Li858ccd72021-02-04 17:25:01 +090030import org.onlab.osgi.DefaultServiceDirectory;
Daniel Park157947f2021-04-09 17:50:53 +090031import org.onlab.packet.ARP;
32import org.onlab.packet.Ethernet;
Daniel Park2884b232021-03-04 18:58:47 +090033import org.onlab.packet.Ip4Address;
Jian Li3ba5c582021-01-14 11:30:36 +090034import org.onlab.packet.IpAddress;
Jian Lica20b712021-01-18 00:19:31 +090035import org.onlab.packet.MacAddress;
Jian Li43244382021-01-09 00:19:02 +090036import org.onosproject.cfg.ConfigProperty;
Jian Lica20b712021-01-18 00:19:31 +090037import org.onosproject.kubevirtnetworking.api.DefaultKubevirtPort;
38import org.onosproject.kubevirtnetworking.api.KubevirtNetwork;
Daniel Parkf3136042021-03-10 07:49:11 +090039import org.onosproject.kubevirtnetworking.api.KubevirtNetworkService;
Jian Lica20b712021-01-18 00:19:31 +090040import org.onosproject.kubevirtnetworking.api.KubevirtPort;
Daniel Park2884b232021-03-04 18:58:47 +090041import org.onosproject.kubevirtnetworking.api.KubevirtRouter;
42import org.onosproject.kubevirtnetworking.api.KubevirtRouterService;
Jian Li034820d2021-01-15 16:58:48 +090043import org.onosproject.kubevirtnode.api.KubevirtApiConfig;
44import org.onosproject.kubevirtnode.api.KubevirtApiConfigService;
Jian Li858ccd72021-02-04 17:25:01 +090045import org.onosproject.kubevirtnode.api.KubevirtNode;
Daniel Park2884b232021-03-04 18:58:47 +090046import org.onosproject.kubevirtnode.api.KubevirtNodeService;
Jian Li858ccd72021-02-04 17:25:01 +090047import org.onosproject.net.DeviceId;
48import org.onosproject.net.Port;
49import org.onosproject.net.PortNumber;
50import org.onosproject.net.device.DeviceService;
Jian Li43244382021-01-09 00:19:02 +090051import org.slf4j.Logger;
52import org.slf4j.LoggerFactory;
Jian Li94b6d162021-04-15 17:09:11 +090053import org.xbill.DNS.Address;
Jian Li43244382021-01-09 00:19:02 +090054
Jian Lif97a07e2021-01-13 18:05:00 +090055import java.io.IOException;
Jian Li94b6d162021-04-15 17:09:11 +090056import java.net.InetAddress;
57import java.net.UnknownHostException;
Jian Li3ba5c582021-01-14 11:30:36 +090058import java.util.Arrays;
59import java.util.HashSet;
Jian Lif97a07e2021-01-13 18:05:00 +090060import java.util.List;
Jian Lica20b712021-01-18 00:19:31 +090061import java.util.Map;
Jian Li858ccd72021-02-04 17:25:01 +090062import java.util.Objects;
Jian Li43244382021-01-09 00:19:02 +090063import java.util.Optional;
64import java.util.Set;
Jian Li3ba5c582021-01-14 11:30:36 +090065import java.util.stream.Collectors;
Jian Li43244382021-01-09 00:19:02 +090066
Jian Li858ccd72021-02-04 17:25:01 +090067import static org.onosproject.kubevirtnetworking.api.Constants.TUNNEL_TO_TENANT_PREFIX;
Daniel Park2884b232021-03-04 18:58:47 +090068import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.GATEWAY;
Jian Li858ccd72021-02-04 17:25:01 +090069import static org.onosproject.net.AnnotationKeys.PORT_NAME;
70
Jian Li43244382021-01-09 00:19:02 +090071/**
72 * An utility that used in KubeVirt networking app.
73 */
74public final class KubevirtNetworkingUtil {
75
76 private static final Logger log = LoggerFactory.getLogger(KubevirtNetworkingUtil.class);
77
78 private static final int PORT_NAME_MAX_LENGTH = 15;
Jian Li034820d2021-01-15 16:58:48 +090079 private static final String COLON_SLASH = "://";
80 private static final String COLON = ":";
Jian Li556709c2021-02-03 17:54:28 +090081 private static final String OF_PREFIX = "of:";
Jian Li43244382021-01-09 00:19:02 +090082
Jian Lica20b712021-01-18 00:19:31 +090083 private static final String NETWORK_STATUS_KEY = "k8s.v1.cni.cncf.io/network-status";
84 private static final String NAME = "name";
85 private static final String NETWORK_PREFIX = "default/";
86 private static final String MAC = "mac";
87 private static final String IPS = "ips";
Daniel Parkbabde9c2021-03-09 13:37:42 +090088 private static final String BR_INT = "br-int";
Jian Lica20b712021-01-18 00:19:31 +090089
Jian Li43244382021-01-09 00:19:02 +090090 /**
91 * Prevents object installation from external.
92 */
93 private KubevirtNetworkingUtil() {
94 }
95
96 /**
97 * Obtains the boolean property value with specified property key name.
98 *
Daniel Park2884b232021-03-04 18:58:47 +090099 * @param properties a collection of properties
100 * @param name key name
Jian Li43244382021-01-09 00:19:02 +0900101 * @return mapping value
102 */
103 public static boolean getPropertyValueAsBoolean(Set<ConfigProperty> properties,
104 String name) {
105 Optional<ConfigProperty> property =
106 properties.stream().filter(p -> p.name().equals(name)).findFirst();
107
108 return property.map(ConfigProperty::asBoolean).orElse(false);
109 }
110
111 /**
112 * Re-structures the OVS port name.
113 * The length of OVS port name should be not large than 15.
114 *
Daniel Park2884b232021-03-04 18:58:47 +0900115 * @param portName original port name
Jian Li43244382021-01-09 00:19:02 +0900116 * @return re-structured OVS port name
117 */
118 public static String structurePortName(String portName) {
119
120 // The size of OVS port name should not be larger than 15
121 if (portName.length() > PORT_NAME_MAX_LENGTH) {
122 return StringUtils.substring(portName, 0, PORT_NAME_MAX_LENGTH);
123 }
124
125 return portName;
126 }
Jian Lif97a07e2021-01-13 18:05:00 +0900127
128 /**
129 * Generates string format based on the given string length list.
130 *
131 * @param stringLengths a list of string lengths
132 * @return string format (e.g., %-28s%-15s%-24s%-20s%-15s)
133 */
134 public static String genFormatString(List<Integer> stringLengths) {
135 StringBuilder fsb = new StringBuilder();
136 stringLengths.forEach(length -> {
137 fsb.append("%-");
138 fsb.append(length);
139 fsb.append("s");
140 });
141 return fsb.toString();
142 }
143
144 /**
Jian Li556709c2021-02-03 17:54:28 +0900145 * Auto generates DPID from the given name.
146 *
147 * @param name name
148 * @return auto generated DPID
149 */
150 public static String genDpidFromName(String name) {
151 if (name != null) {
152 String hexString = Integer.toHexString(name.hashCode());
153 return OF_PREFIX + Strings.padStart(hexString, 16, '0');
154 }
155
156 return null;
157 }
158
159 /**
Jian Lif97a07e2021-01-13 18:05:00 +0900160 * Prints out the JSON string in pretty format.
161 *
Daniel Park2884b232021-03-04 18:58:47 +0900162 * @param mapper Object mapper
163 * @param jsonString JSON string
Jian Lif97a07e2021-01-13 18:05:00 +0900164 * @return pretty formatted JSON string
165 */
166 public static String prettyJson(ObjectMapper mapper, String jsonString) {
167 try {
168 Object jsonObject = mapper.readValue(jsonString, Object.class);
169 return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject);
170 } catch (IOException e) {
171 log.debug("Json string parsing exception caused by {}", e);
172 }
173 return null;
174 }
Jian Li3ba5c582021-01-14 11:30:36 +0900175
176 /**
177 * Obtains valid IP addresses of the given subnet.
178 *
179 * @param cidr CIDR
180 * @return set of IP addresses
181 */
182 public static Set<IpAddress> getSubnetIps(String cidr) {
183 SubnetUtils utils = new SubnetUtils(cidr);
184 utils.setInclusiveHostCount(false);
185 SubnetUtils.SubnetInfo info = utils.getInfo();
186 Set<String> allAddresses =
187 new HashSet<>(Arrays.asList(info.getAllAddresses()));
188
189 if (allAddresses.size() > 2) {
190 allAddresses.remove(info.getLowAddress());
191 allAddresses.remove(info.getHighAddress());
192 }
193
194 return allAddresses.stream()
195 .map(IpAddress::valueOf).collect(Collectors.toSet());
196 }
197
198 /**
199 * Calculate the broadcast address from given IP address and subnet prefix length.
200 *
Daniel Park2884b232021-03-04 18:58:47 +0900201 * @param ipAddr IP address
202 * @param prefixLength subnet prefix length
Jian Li3ba5c582021-01-14 11:30:36 +0900203 * @return broadcast address
204 */
205 public static String getBroadcastAddr(String ipAddr, int prefixLength) {
206 String subnet = ipAddr + "/" + prefixLength;
207 SubnetUtils utils = new SubnetUtils(subnet);
208 return utils.getInfo().getBroadcastAddress();
209 }
Daniel Park2884b232021-03-04 18:58:47 +0900210
Jian Li034820d2021-01-15 16:58:48 +0900211 /**
212 * Generates endpoint URL by referring to scheme, ipAddress and port.
213 *
Daniel Park2884b232021-03-04 18:58:47 +0900214 * @param scheme scheme
215 * @param ipAddress IP address
216 * @param port port number
Jian Li034820d2021-01-15 16:58:48 +0900217 * @return generated endpoint URL
218 */
219 public static String endpoint(KubevirtApiConfig.Scheme scheme, IpAddress ipAddress, int port) {
220 StringBuilder endpoint = new StringBuilder();
221 String protocol = org.apache.commons.lang3.StringUtils.lowerCase(scheme.name());
222
223 endpoint.append(protocol);
224 endpoint.append(COLON_SLASH);
225 endpoint.append(ipAddress.toString());
226 endpoint.append(COLON);
227 endpoint.append(port);
228
229 return endpoint.toString();
230 }
231
232 /**
233 * Generates endpoint URL by referring to scheme, ipAddress and port.
234 *
Daniel Park2884b232021-03-04 18:58:47 +0900235 * @param apiConfig kubernetes API config
Jian Li034820d2021-01-15 16:58:48 +0900236 * @return generated endpoint URL
237 */
238 public static String endpoint(KubevirtApiConfig apiConfig) {
239 return endpoint(apiConfig.scheme(), apiConfig.ipAddress(), apiConfig.port());
240 }
241
242 /**
243 * Obtains workable kubernetes client.
244 *
245 * @param config kubernetes API config
246 * @return kubernetes client
247 */
248 public static KubernetesClient k8sClient(KubevirtApiConfig config) {
249 if (config == null) {
250 log.warn("Kubernetes API server config is empty.");
251 return null;
252 }
253
254 String endpoint = endpoint(config);
255
256 ConfigBuilder configBuilder = new ConfigBuilder().withMasterUrl(endpoint);
257
258 if (config.scheme() == KubevirtApiConfig.Scheme.HTTPS) {
259 configBuilder.withTrustCerts(true)
Jian Li034820d2021-01-15 16:58:48 +0900260 .withCaCertData(config.caCertData())
261 .withClientCertData(config.clientCertData())
262 .withClientKeyData(config.clientKeyData());
263 }
264
265 return new DefaultKubernetesClient(configBuilder.build());
266 }
267
268 /**
269 * Obtains workable kubernetes client.
270 *
271 * @param service kubernetes API service
272 * @return kubernetes client
273 */
274 public static KubernetesClient k8sClient(KubevirtApiConfigService service) {
275 KubevirtApiConfig config = service.apiConfig();
276 if (config == null) {
277 log.error("Failed to find valid kubernetes API configuration.");
278 return null;
279 }
280
281 KubernetesClient client = k8sClient(config);
282
283 if (client == null) {
284 log.error("Failed to connect to kubernetes API server.");
285 return null;
286 }
287
288 return client;
289 }
Jian Lica20b712021-01-18 00:19:31 +0900290
291 /**
Jian Li556709c2021-02-03 17:54:28 +0900292 * Obtains the hex string of the given segment ID with fixed padding.
293 *
294 * @param segIdStr segment identifier string
295 * @return hex string with padding
296 */
297 public static String segmentIdHex(String segIdStr) {
298 int segId = Integer.parseInt(segIdStr);
299 return String.format("%06x", segId).toLowerCase();
300 }
301
302 /**
Jian Li858ccd72021-02-04 17:25:01 +0900303 * Obtains the tunnel port number with the given network and node.
304 *
305 * @param network kubevirt network
Daniel Park2884b232021-03-04 18:58:47 +0900306 * @param node kubevirt node
Jian Li858ccd72021-02-04 17:25:01 +0900307 * @return tunnel port number
308 */
309 public static PortNumber tunnelPort(KubevirtNetwork network, KubevirtNode node) {
310 switch (network.type()) {
311 case VXLAN:
312 return node.vxlanPort();
313 case GRE:
314 return node.grePort();
315 case GENEVE:
316 return node.genevePort();
317 default:
318 break;
319 }
320 return null;
321 }
322
323 /**
Jian Lica20b712021-01-18 00:19:31 +0900324 * Obtains the kubevirt port from kubevirt POD.
325 *
Daniel Parkf3136042021-03-10 07:49:11 +0900326 * @param nodeService kubevirt node service
Jian Lica20b712021-01-18 00:19:31 +0900327 * @param networks set of existing kubevirt networks
Daniel Park2884b232021-03-04 18:58:47 +0900328 * @param pod kubevirt POD
Jian Lid4296d02021-03-12 18:03:58 +0900329 * @return kubevirt ports attached to the POD
Jian Lica20b712021-01-18 00:19:31 +0900330 */
Jian Lib6dc08f2021-03-24 15:24:18 +0900331 public static Set<KubevirtPort> getPorts(KubevirtNodeService nodeService,
332 Set<KubevirtNetwork> networks, Pod pod) {
Jian Lica20b712021-01-18 00:19:31 +0900333 try {
334 Map<String, String> annots = pod.getMetadata().getAnnotations();
Jian Li6e66a302021-01-21 20:30:52 +0900335 if (annots == null) {
Jian Lid4296d02021-03-12 18:03:58 +0900336 return ImmutableSet.of();
Jian Li6e66a302021-01-21 20:30:52 +0900337 }
338
Jian Li7a581b12021-02-18 14:24:32 +0900339 if (!annots.containsKey(NETWORK_STATUS_KEY)) {
Jian Lid4296d02021-03-12 18:03:58 +0900340 return ImmutableSet.of();
Jian Li7a581b12021-02-18 14:24:32 +0900341 }
342
Jian Lica20b712021-01-18 00:19:31 +0900343 String networkStatusStr = annots.get(NETWORK_STATUS_KEY);
344
345 if (networkStatusStr == null) {
Jian Lid4296d02021-03-12 18:03:58 +0900346 return ImmutableSet.of();
Jian Lica20b712021-01-18 00:19:31 +0900347 }
Jian Lib6dc08f2021-03-24 15:24:18 +0900348
Daniel Parkf3136042021-03-10 07:49:11 +0900349 KubevirtPort.Builder builder = DefaultKubevirtPort.builder();
350
351 KubevirtNode node = nodeService.node(pod.getSpec().getNodeName());
Jian Lib6dc08f2021-03-24 15:24:18 +0900352
Daniel Parkf3136042021-03-10 07:49:11 +0900353 if (node != null) {
354 builder.deviceId(node.intgBridge());
355 }
Jian Lica20b712021-01-18 00:19:31 +0900356
357 JSONArray networkStatus = new JSONArray(networkStatusStr);
Jian Lid4296d02021-03-12 18:03:58 +0900358 Set<KubevirtPort> ports = new HashSet<>();
Jian Lica20b712021-01-18 00:19:31 +0900359
360 for (int i = 0; i < networkStatus.length(); i++) {
361 JSONObject object = networkStatus.getJSONObject(i);
362 String name = object.getString(NAME);
363 KubevirtNetwork network = networks.stream()
Jian Li46592cf2021-05-11 18:12:55 +0900364 .filter(n -> (NETWORK_PREFIX + n.name()).equals(name) || (n.name()).equals(name))
Jian Lica20b712021-01-18 00:19:31 +0900365 .findAny().orElse(null);
366 if (network != null) {
367 String mac = object.getString(MAC);
368
Daniel Parkf3136042021-03-10 07:49:11 +0900369 builder.macAddress(MacAddress.valueOf(mac))
Jian Lica20b712021-01-18 00:19:31 +0900370 .networkId(network.networkId());
371
Jian Lid4296d02021-03-12 18:03:58 +0900372 ports.add(builder.build());
Jian Lica20b712021-01-18 00:19:31 +0900373 }
374 }
375
Jian Lid4296d02021-03-12 18:03:58 +0900376 return ports;
377
Jian Lica20b712021-01-18 00:19:31 +0900378 } catch (JSONException e) {
379 log.error("Failed to parse network status object", e);
380 }
381
Jian Lid4296d02021-03-12 18:03:58 +0900382 return ImmutableSet.of();
Jian Lica20b712021-01-18 00:19:31 +0900383 }
Jian Li858ccd72021-02-04 17:25:01 +0900384
385 /**
386 * Obtains the tunnel bridge to tenant bridge patch port number.
387 *
Daniel Park2884b232021-03-04 18:58:47 +0900388 * @param node kubevirt node
Jian Li858ccd72021-02-04 17:25:01 +0900389 * @param network kubevirt network
390 * @return patch port number
391 */
392 public static PortNumber tunnelToTenantPort(KubevirtNode node, KubevirtNetwork network) {
393 if (network.segmentId() == null) {
394 return null;
395 }
396
397 if (node.tunBridge() == null) {
398 return null;
399 }
400
401 String tunToTenantPortName = TUNNEL_TO_TENANT_PREFIX + segmentIdHex(network.segmentId());
402 return portNumber(node.tunBridge(), tunToTenantPortName);
403 }
404
405 /**
406 * Obtains the tunnel port number of the given node.
407 *
Daniel Park2884b232021-03-04 18:58:47 +0900408 * @param node kubevirt node
Jian Li858ccd72021-02-04 17:25:01 +0900409 * @param network kubevirt network
410 * @return tunnel port number
411 */
412 public static PortNumber tunnelPort(KubevirtNode node, KubevirtNetwork network) {
413 if (network.segmentId() == null) {
414 return null;
415 }
416
417 if (node.tunBridge() == null) {
418 return null;
419 }
420
421 switch (network.type()) {
422 case VXLAN:
423 return node.vxlanPort();
424 case GRE:
425 return node.grePort();
426 case GENEVE:
427 return node.genevePort();
428 case FLAT:
Jian Li2ce718e2021-02-17 20:42:15 +0900429 case VLAN:
Jian Li858ccd72021-02-04 17:25:01 +0900430 default:
431 // do nothing
432 return null;
433 }
434 }
435
Jian Li810f58c2021-02-27 01:10:50 +0900436 public static String parseResourceName(String resource) {
437 try {
438 JSONObject json = new JSONObject(resource);
439 return json.getJSONObject("metadata").getString("name");
440 } catch (JSONException e) {
441 log.error("");
442 }
443 return "";
444 }
445
Daniel Parkf3136042021-03-10 07:49:11 +0900446 public static PortNumber portNumber(DeviceId deviceId, String portName) {
Jian Li858ccd72021-02-04 17:25:01 +0900447 DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
448 Port port = deviceService.getPorts(deviceId).stream()
449 .filter(p -> p.isEnabled() &&
450 Objects.equals(p.annotations().value(PORT_NAME), portName))
451 .findAny().orElse(null);
452 return port != null ? port.number() : null;
453 }
454
Daniel Park2884b232021-03-04 18:58:47 +0900455 /**
456 * Returns the gateway node for the specified kubevirt router.
457 * Among gateways, only one gateway would act as a gateway per perter.
458 * Currently gateway node is selected based on modulo operation with router hashcode.
459 *
460 * @param nodeService kubevirt node service
461 * @param router kubevirt router
462 * @return elected gateway node
463 */
464 public static KubevirtNode gatewayNodeForSpecifiedRouter(KubevirtNodeService nodeService,
465 KubevirtRouter router) {
466 //TODO: enhance election logic for a better load balancing
467
468 int numOfGateways = nodeService.completeNodes(GATEWAY).size();
469 if (numOfGateways == 0) {
470 return null;
471 }
472 return (KubevirtNode) nodeService.completeNodes(GATEWAY).toArray()[router.hashCode() % numOfGateways];
473 }
474
475 /**
Daniel Parkf3136042021-03-10 07:49:11 +0900476 * Returns the mac address of the router.
477 *
478 * @param router kubevirt router
479 * @return macc address of the router
480 */
481 public static MacAddress getRouterMacAddress(KubevirtRouter router) {
482 if (router.mac() == null) {
483 log.warn("Failed to get mac address of router {}", router.name());
484 }
485
486 return router.mac();
Daniel Park2884b232021-03-04 18:58:47 +0900487 }
488
489 /**
490 * Returns the snat ip address with specified router.
491 *
492 * @param routerService router service
493 * @param internalNetworkId internal network id which is associated with the router
494 * @return snat ip address if exist, null otherwise
495 */
496 public static IpAddress getRouterSnatIpAddress(KubevirtRouterService routerService,
497 String internalNetworkId) {
498 KubevirtRouter router = routerService.routers().stream()
499 .filter(r -> r.internal().contains(internalNetworkId))
500 .findAny().orElse(null);
501
502 if (router == null) {
503 return null;
504 }
505
506 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
507
508 if (routerSnatIp == null) {
509 return null;
510 }
511
512 return Ip4Address.valueOf(routerSnatIp);
513 }
Daniel Parkbabde9c2021-03-09 13:37:42 +0900514
515 /**
516 * Returns the kubevirt router with specified kubevirt port.
517 *
518 * @param routerService kubevirt router service
519 * @param kubevirtPort kubevirt port
520 * @return kubevirt router
521 */
522 public static KubevirtRouter getRouterForKubevirtPort(KubevirtRouterService routerService,
523 KubevirtPort kubevirtPort) {
524 if (kubevirtPort.ipAddress() != null) {
525 return routerService.routers().stream()
526 .filter(r -> r.internal().contains(kubevirtPort.networkId()))
527 .findAny().orElse(null);
528 }
529 return null;
530 }
531
532 /**
533 * Returns the kubevirt router with specified kubevirt network.
534 *
535 * @param routerService kubevirt router service
536 * @param kubevirtNetwork kubevirt network
537 * @return kubevirt router
538 */
539 public static KubevirtRouter getRouterForKubevirtNetwork(KubevirtRouterService routerService,
540 KubevirtNetwork kubevirtNetwork) {
541 return routerService.routers().stream()
542 .filter(router -> router.internal().contains(kubevirtNetwork.networkId()))
543 .findAny().orElse(null);
544 }
Daniel Parkf3136042021-03-10 07:49:11 +0900545
546 /**
547 * Returns the external patch port number with specified gateway.
548 *
549 * @param deviceService device service
Jian Li9793ec42021-03-19 15:03:32 +0900550 * @param gatewayNode gateway node
Daniel Parkf3136042021-03-10 07:49:11 +0900551 * @return external patch port number
552 */
553 public static PortNumber externalPatchPortNum(DeviceService deviceService, KubevirtNode gatewayNode) {
Jian Li63f191f2021-03-25 17:14:40 +0900554 String gatewayBridgeName = gatewayNode.gatewayBridgeName();
555 if (gatewayBridgeName == null) {
Jian Li9793ec42021-03-19 15:03:32 +0900556 log.warn("No external interface is attached to gateway {}", gatewayNode.hostname());
557 return null;
558 }
559
Jian Li63f191f2021-03-25 17:14:40 +0900560 String patchPortName = "int-to-" + gatewayBridgeName;
Daniel Parkf3136042021-03-10 07:49:11 +0900561 Port port = deviceService.getPorts(gatewayNode.intgBridge()).stream()
562 .filter(p -> p.isEnabled() &&
Jian Li9793ec42021-03-19 15:03:32 +0900563 Objects.equals(p.annotations().value(PORT_NAME), patchPortName))
Daniel Parkf3136042021-03-10 07:49:11 +0900564 .findAny().orElse(null);
565
566 return port != null ? port.number() : null;
567 }
568
Daniel Park157947f2021-04-09 17:50:53 +0900569 /**
570 * Returns the kubevirt external network with specified router.
571 *
572 * @param networkService kubevirt network service
573 * @param router kubevirt router
574 * @return external network
575 */
Daniel Parkf3136042021-03-10 07:49:11 +0900576 public static KubevirtNetwork getExternalNetworkByRouter(KubevirtNetworkService networkService,
577 KubevirtRouter router) {
578 String networkId = router.external().values().stream().findAny().orElse(null);
579 if (networkId == null) {
580 return null;
581 }
582
583 return networkService.network(networkId);
584 }
Daniel Park157947f2021-04-09 17:50:53 +0900585
Jian Li94b6d162021-04-15 17:09:11 +0900586 /**
587 * Resolve a DNS with the given DNS server and hostname.
588 *
589 * @param hostname hostname to be resolved
590 * @return resolved IP address
591 */
592 public static IpAddress resolveHostname(String hostname) {
593 try {
594 InetAddress addr = Address.getByName(hostname);
595 return IpAddress.valueOf(IpAddress.Version.INET, addr.getAddress());
596 } catch (UnknownHostException e) {
597 log.warn("Failed to resolve IP address of host {}", hostname);
598 }
599 return null;
600 }
601
602 /**
603 * Builds a GARP packet using the given source MAC and source IP address.
604 *
605 * @param srcMac source MAC address
606 * @param srcIp source IP address
607 * @return GARP packet
608 */
Daniel Park157947f2021-04-09 17:50:53 +0900609 public static Ethernet buildGarpPacket(MacAddress srcMac, IpAddress srcIp) {
610 if (srcMac == null || srcIp == null) {
611 return null;
612 }
613
614 Ethernet ethernet = new Ethernet();
615 ethernet.setDestinationMACAddress(MacAddress.BROADCAST);
616 ethernet.setSourceMACAddress(srcMac);
617 ethernet.setEtherType(Ethernet.TYPE_ARP);
618
619 ARP arp = new ARP();
620 arp.setOpCode(ARP.OP_REPLY);
621 arp.setProtocolType(ARP.PROTO_TYPE_IP);
622 arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
623
624 arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
625 arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
626
627 arp.setSenderHardwareAddress(srcMac.toBytes());
628 arp.setTargetHardwareAddress(MacAddress.BROADCAST.toBytes());
629
630 arp.setSenderProtocolAddress(srcIp.toOctets());
631 arp.setTargetProtocolAddress(srcIp.toOctets());
632
633 ethernet.setPayload(arp);
634
635 return ethernet;
636 }
Jian Li43244382021-01-09 00:19:02 +0900637}