blob: 8771dda90420b2bc861f186182ced59e679291b1 [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;
Daniel Park05a94582021-05-12 10:57:02 +090038import org.onosproject.kubevirtnetworking.api.KubevirtLoadBalancer;
39import org.onosproject.kubevirtnetworking.api.KubevirtLoadBalancerService;
Jian Lica20b712021-01-18 00:19:31 +090040import org.onosproject.kubevirtnetworking.api.KubevirtNetwork;
Daniel Parkf3136042021-03-10 07:49:11 +090041import org.onosproject.kubevirtnetworking.api.KubevirtNetworkService;
Jian Lica20b712021-01-18 00:19:31 +090042import org.onosproject.kubevirtnetworking.api.KubevirtPort;
Daniel Park2884b232021-03-04 18:58:47 +090043import org.onosproject.kubevirtnetworking.api.KubevirtRouter;
44import org.onosproject.kubevirtnetworking.api.KubevirtRouterService;
Jian Li034820d2021-01-15 16:58:48 +090045import org.onosproject.kubevirtnode.api.KubevirtApiConfig;
46import org.onosproject.kubevirtnode.api.KubevirtApiConfigService;
Jian Li858ccd72021-02-04 17:25:01 +090047import org.onosproject.kubevirtnode.api.KubevirtNode;
Daniel Park2884b232021-03-04 18:58:47 +090048import org.onosproject.kubevirtnode.api.KubevirtNodeService;
Jian Li858ccd72021-02-04 17:25:01 +090049import org.onosproject.net.DeviceId;
50import org.onosproject.net.Port;
51import org.onosproject.net.PortNumber;
52import org.onosproject.net.device.DeviceService;
Daniel Park05a94582021-05-12 10:57:02 +090053import org.onosproject.net.group.DefaultGroupKey;
54import org.onosproject.net.group.GroupKey;
Jian Li43244382021-01-09 00:19:02 +090055import org.slf4j.Logger;
56import org.slf4j.LoggerFactory;
Jian Li94b6d162021-04-15 17:09:11 +090057import org.xbill.DNS.Address;
Jian Li43244382021-01-09 00:19:02 +090058
Jian Lif97a07e2021-01-13 18:05:00 +090059import java.io.IOException;
Jian Li94b6d162021-04-15 17:09:11 +090060import java.net.InetAddress;
61import java.net.UnknownHostException;
Jian Li3ba5c582021-01-14 11:30:36 +090062import java.util.Arrays;
63import java.util.HashSet;
Jian Lif97a07e2021-01-13 18:05:00 +090064import java.util.List;
Jian Lica20b712021-01-18 00:19:31 +090065import java.util.Map;
Jian Li858ccd72021-02-04 17:25:01 +090066import java.util.Objects;
Jian Li43244382021-01-09 00:19:02 +090067import java.util.Optional;
68import java.util.Set;
Jian Li3ba5c582021-01-14 11:30:36 +090069import java.util.stream.Collectors;
Jian Li43244382021-01-09 00:19:02 +090070
Jian Li858ccd72021-02-04 17:25:01 +090071import static org.onosproject.kubevirtnetworking.api.Constants.TUNNEL_TO_TENANT_PREFIX;
Daniel Park2884b232021-03-04 18:58:47 +090072import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.GATEWAY;
Jian Li858ccd72021-02-04 17:25:01 +090073import static org.onosproject.net.AnnotationKeys.PORT_NAME;
74
Jian Li43244382021-01-09 00:19:02 +090075/**
76 * An utility that used in KubeVirt networking app.
77 */
78public final class KubevirtNetworkingUtil {
79
80 private static final Logger log = LoggerFactory.getLogger(KubevirtNetworkingUtil.class);
81
82 private static final int PORT_NAME_MAX_LENGTH = 15;
Jian Li034820d2021-01-15 16:58:48 +090083 private static final String COLON_SLASH = "://";
84 private static final String COLON = ":";
Jian Li556709c2021-02-03 17:54:28 +090085 private static final String OF_PREFIX = "of:";
Jian Li43244382021-01-09 00:19:02 +090086
Jian Lica20b712021-01-18 00:19:31 +090087 private static final String NETWORK_STATUS_KEY = "k8s.v1.cni.cncf.io/network-status";
88 private static final String NAME = "name";
89 private static final String NETWORK_PREFIX = "default/";
90 private static final String MAC = "mac";
91 private static final String IPS = "ips";
Daniel Parkbabde9c2021-03-09 13:37:42 +090092 private static final String BR_INT = "br-int";
Jian Lica20b712021-01-18 00:19:31 +090093
Jian Li43244382021-01-09 00:19:02 +090094 /**
95 * Prevents object installation from external.
96 */
97 private KubevirtNetworkingUtil() {
98 }
99
100 /**
101 * Obtains the boolean property value with specified property key name.
102 *
Daniel Park2884b232021-03-04 18:58:47 +0900103 * @param properties a collection of properties
104 * @param name key name
Jian Li43244382021-01-09 00:19:02 +0900105 * @return mapping value
106 */
107 public static boolean getPropertyValueAsBoolean(Set<ConfigProperty> properties,
108 String name) {
109 Optional<ConfigProperty> property =
110 properties.stream().filter(p -> p.name().equals(name)).findFirst();
111
112 return property.map(ConfigProperty::asBoolean).orElse(false);
113 }
114
115 /**
116 * Re-structures the OVS port name.
117 * The length of OVS port name should be not large than 15.
118 *
Daniel Park2884b232021-03-04 18:58:47 +0900119 * @param portName original port name
Jian Li43244382021-01-09 00:19:02 +0900120 * @return re-structured OVS port name
121 */
122 public static String structurePortName(String portName) {
123
124 // The size of OVS port name should not be larger than 15
125 if (portName.length() > PORT_NAME_MAX_LENGTH) {
126 return StringUtils.substring(portName, 0, PORT_NAME_MAX_LENGTH);
127 }
128
129 return portName;
130 }
Jian Lif97a07e2021-01-13 18:05:00 +0900131
132 /**
133 * Generates string format based on the given string length list.
134 *
135 * @param stringLengths a list of string lengths
136 * @return string format (e.g., %-28s%-15s%-24s%-20s%-15s)
137 */
138 public static String genFormatString(List<Integer> stringLengths) {
139 StringBuilder fsb = new StringBuilder();
140 stringLengths.forEach(length -> {
141 fsb.append("%-");
142 fsb.append(length);
143 fsb.append("s");
144 });
145 return fsb.toString();
146 }
147
148 /**
Jian Li556709c2021-02-03 17:54:28 +0900149 * Auto generates DPID from the given name.
150 *
151 * @param name name
152 * @return auto generated DPID
153 */
154 public static String genDpidFromName(String name) {
155 if (name != null) {
156 String hexString = Integer.toHexString(name.hashCode());
157 return OF_PREFIX + Strings.padStart(hexString, 16, '0');
158 }
159
160 return null;
161 }
162
163 /**
Jian Lif97a07e2021-01-13 18:05:00 +0900164 * Prints out the JSON string in pretty format.
165 *
Daniel Park2884b232021-03-04 18:58:47 +0900166 * @param mapper Object mapper
167 * @param jsonString JSON string
Jian Lif97a07e2021-01-13 18:05:00 +0900168 * @return pretty formatted JSON string
169 */
170 public static String prettyJson(ObjectMapper mapper, String jsonString) {
171 try {
172 Object jsonObject = mapper.readValue(jsonString, Object.class);
173 return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject);
174 } catch (IOException e) {
175 log.debug("Json string parsing exception caused by {}", e);
176 }
177 return null;
178 }
Jian Li3ba5c582021-01-14 11:30:36 +0900179
180 /**
181 * Obtains valid IP addresses of the given subnet.
182 *
183 * @param cidr CIDR
184 * @return set of IP addresses
185 */
186 public static Set<IpAddress> getSubnetIps(String cidr) {
187 SubnetUtils utils = new SubnetUtils(cidr);
188 utils.setInclusiveHostCount(false);
189 SubnetUtils.SubnetInfo info = utils.getInfo();
190 Set<String> allAddresses =
191 new HashSet<>(Arrays.asList(info.getAllAddresses()));
192
193 if (allAddresses.size() > 2) {
194 allAddresses.remove(info.getLowAddress());
195 allAddresses.remove(info.getHighAddress());
196 }
197
198 return allAddresses.stream()
199 .map(IpAddress::valueOf).collect(Collectors.toSet());
200 }
201
202 /**
203 * Calculate the broadcast address from given IP address and subnet prefix length.
204 *
Daniel Park2884b232021-03-04 18:58:47 +0900205 * @param ipAddr IP address
206 * @param prefixLength subnet prefix length
Jian Li3ba5c582021-01-14 11:30:36 +0900207 * @return broadcast address
208 */
209 public static String getBroadcastAddr(String ipAddr, int prefixLength) {
210 String subnet = ipAddr + "/" + prefixLength;
211 SubnetUtils utils = new SubnetUtils(subnet);
212 return utils.getInfo().getBroadcastAddress();
213 }
Daniel Park2884b232021-03-04 18:58:47 +0900214
Jian Li034820d2021-01-15 16:58:48 +0900215 /**
216 * Generates endpoint URL by referring to scheme, ipAddress and port.
217 *
Daniel Park2884b232021-03-04 18:58:47 +0900218 * @param scheme scheme
219 * @param ipAddress IP address
220 * @param port port number
Jian Li034820d2021-01-15 16:58:48 +0900221 * @return generated endpoint URL
222 */
223 public static String endpoint(KubevirtApiConfig.Scheme scheme, IpAddress ipAddress, int port) {
224 StringBuilder endpoint = new StringBuilder();
225 String protocol = org.apache.commons.lang3.StringUtils.lowerCase(scheme.name());
226
227 endpoint.append(protocol);
228 endpoint.append(COLON_SLASH);
229 endpoint.append(ipAddress.toString());
230 endpoint.append(COLON);
231 endpoint.append(port);
232
233 return endpoint.toString();
234 }
235
236 /**
237 * Generates endpoint URL by referring to scheme, ipAddress and port.
238 *
Daniel Park2884b232021-03-04 18:58:47 +0900239 * @param apiConfig kubernetes API config
Jian Li034820d2021-01-15 16:58:48 +0900240 * @return generated endpoint URL
241 */
242 public static String endpoint(KubevirtApiConfig apiConfig) {
243 return endpoint(apiConfig.scheme(), apiConfig.ipAddress(), apiConfig.port());
244 }
245
246 /**
247 * Obtains workable kubernetes client.
248 *
249 * @param config kubernetes API config
250 * @return kubernetes client
251 */
252 public static KubernetesClient k8sClient(KubevirtApiConfig config) {
253 if (config == null) {
254 log.warn("Kubernetes API server config is empty.");
255 return null;
256 }
257
258 String endpoint = endpoint(config);
259
260 ConfigBuilder configBuilder = new ConfigBuilder().withMasterUrl(endpoint);
261
262 if (config.scheme() == KubevirtApiConfig.Scheme.HTTPS) {
263 configBuilder.withTrustCerts(true)
Jian Li034820d2021-01-15 16:58:48 +0900264 .withCaCertData(config.caCertData())
265 .withClientCertData(config.clientCertData())
266 .withClientKeyData(config.clientKeyData());
267 }
268
269 return new DefaultKubernetesClient(configBuilder.build());
270 }
271
272 /**
273 * Obtains workable kubernetes client.
274 *
275 * @param service kubernetes API service
276 * @return kubernetes client
277 */
278 public static KubernetesClient k8sClient(KubevirtApiConfigService service) {
279 KubevirtApiConfig config = service.apiConfig();
280 if (config == null) {
281 log.error("Failed to find valid kubernetes API configuration.");
282 return null;
283 }
284
285 KubernetesClient client = k8sClient(config);
286
287 if (client == null) {
288 log.error("Failed to connect to kubernetes API server.");
289 return null;
290 }
291
292 return client;
293 }
Jian Lica20b712021-01-18 00:19:31 +0900294
295 /**
Jian Li556709c2021-02-03 17:54:28 +0900296 * Obtains the hex string of the given segment ID with fixed padding.
297 *
298 * @param segIdStr segment identifier string
299 * @return hex string with padding
300 */
301 public static String segmentIdHex(String segIdStr) {
302 int segId = Integer.parseInt(segIdStr);
303 return String.format("%06x", segId).toLowerCase();
304 }
305
306 /**
Jian Li858ccd72021-02-04 17:25:01 +0900307 * Obtains the tunnel port number with the given network and node.
308 *
309 * @param network kubevirt network
Daniel Park2884b232021-03-04 18:58:47 +0900310 * @param node kubevirt node
Jian Li858ccd72021-02-04 17:25:01 +0900311 * @return tunnel port number
312 */
313 public static PortNumber tunnelPort(KubevirtNetwork network, KubevirtNode node) {
314 switch (network.type()) {
315 case VXLAN:
316 return node.vxlanPort();
317 case GRE:
318 return node.grePort();
319 case GENEVE:
320 return node.genevePort();
321 default:
322 break;
323 }
324 return null;
325 }
326
327 /**
Jian Lica20b712021-01-18 00:19:31 +0900328 * Obtains the kubevirt port from kubevirt POD.
329 *
Daniel Parkf3136042021-03-10 07:49:11 +0900330 * @param nodeService kubevirt node service
Jian Lica20b712021-01-18 00:19:31 +0900331 * @param networks set of existing kubevirt networks
Daniel Park2884b232021-03-04 18:58:47 +0900332 * @param pod kubevirt POD
Jian Lid4296d02021-03-12 18:03:58 +0900333 * @return kubevirt ports attached to the POD
Jian Lica20b712021-01-18 00:19:31 +0900334 */
Jian Lib6dc08f2021-03-24 15:24:18 +0900335 public static Set<KubevirtPort> getPorts(KubevirtNodeService nodeService,
336 Set<KubevirtNetwork> networks, Pod pod) {
Jian Lica20b712021-01-18 00:19:31 +0900337 try {
338 Map<String, String> annots = pod.getMetadata().getAnnotations();
Jian Li6e66a302021-01-21 20:30:52 +0900339 if (annots == null) {
Jian Lid4296d02021-03-12 18:03:58 +0900340 return ImmutableSet.of();
Jian Li6e66a302021-01-21 20:30:52 +0900341 }
342
Jian Li7a581b12021-02-18 14:24:32 +0900343 if (!annots.containsKey(NETWORK_STATUS_KEY)) {
Jian Lid4296d02021-03-12 18:03:58 +0900344 return ImmutableSet.of();
Jian Li7a581b12021-02-18 14:24:32 +0900345 }
346
Jian Lica20b712021-01-18 00:19:31 +0900347 String networkStatusStr = annots.get(NETWORK_STATUS_KEY);
348
349 if (networkStatusStr == null) {
Jian Lid4296d02021-03-12 18:03:58 +0900350 return ImmutableSet.of();
Jian Lica20b712021-01-18 00:19:31 +0900351 }
Jian Lib6dc08f2021-03-24 15:24:18 +0900352
Daniel Parkf3136042021-03-10 07:49:11 +0900353 KubevirtPort.Builder builder = DefaultKubevirtPort.builder();
354
355 KubevirtNode node = nodeService.node(pod.getSpec().getNodeName());
Jian Lib6dc08f2021-03-24 15:24:18 +0900356
Daniel Parkf3136042021-03-10 07:49:11 +0900357 if (node != null) {
358 builder.deviceId(node.intgBridge());
359 }
Jian Lica20b712021-01-18 00:19:31 +0900360
361 JSONArray networkStatus = new JSONArray(networkStatusStr);
Jian Lid4296d02021-03-12 18:03:58 +0900362 Set<KubevirtPort> ports = new HashSet<>();
Jian Lica20b712021-01-18 00:19:31 +0900363
364 for (int i = 0; i < networkStatus.length(); i++) {
365 JSONObject object = networkStatus.getJSONObject(i);
366 String name = object.getString(NAME);
367 KubevirtNetwork network = networks.stream()
Jian Li46592cf2021-05-11 18:12:55 +0900368 .filter(n -> (NETWORK_PREFIX + n.name()).equals(name) || (n.name()).equals(name))
Jian Lica20b712021-01-18 00:19:31 +0900369 .findAny().orElse(null);
370 if (network != null) {
371 String mac = object.getString(MAC);
372
Daniel Parkf3136042021-03-10 07:49:11 +0900373 builder.macAddress(MacAddress.valueOf(mac))
Jian Lica20b712021-01-18 00:19:31 +0900374 .networkId(network.networkId());
375
Jian Lid4296d02021-03-12 18:03:58 +0900376 ports.add(builder.build());
Jian Lica20b712021-01-18 00:19:31 +0900377 }
378 }
379
Jian Lid4296d02021-03-12 18:03:58 +0900380 return ports;
381
Jian Lica20b712021-01-18 00:19:31 +0900382 } catch (JSONException e) {
383 log.error("Failed to parse network status object", e);
384 }
385
Jian Lid4296d02021-03-12 18:03:58 +0900386 return ImmutableSet.of();
Jian Lica20b712021-01-18 00:19:31 +0900387 }
Jian Li858ccd72021-02-04 17:25:01 +0900388
389 /**
390 * Obtains the tunnel bridge to tenant bridge patch port number.
391 *
Daniel Park2884b232021-03-04 18:58:47 +0900392 * @param node kubevirt node
Jian Li858ccd72021-02-04 17:25:01 +0900393 * @param network kubevirt network
394 * @return patch port number
395 */
396 public static PortNumber tunnelToTenantPort(KubevirtNode node, KubevirtNetwork network) {
397 if (network.segmentId() == null) {
398 return null;
399 }
400
401 if (node.tunBridge() == null) {
402 return null;
403 }
404
405 String tunToTenantPortName = TUNNEL_TO_TENANT_PREFIX + segmentIdHex(network.segmentId());
406 return portNumber(node.tunBridge(), tunToTenantPortName);
407 }
408
409 /**
410 * Obtains the tunnel port number of the given node.
411 *
Daniel Park2884b232021-03-04 18:58:47 +0900412 * @param node kubevirt node
Jian Li858ccd72021-02-04 17:25:01 +0900413 * @param network kubevirt network
414 * @return tunnel port number
415 */
416 public static PortNumber tunnelPort(KubevirtNode node, KubevirtNetwork network) {
417 if (network.segmentId() == null) {
418 return null;
419 }
420
421 if (node.tunBridge() == null) {
422 return null;
423 }
424
425 switch (network.type()) {
426 case VXLAN:
427 return node.vxlanPort();
428 case GRE:
429 return node.grePort();
430 case GENEVE:
431 return node.genevePort();
432 case FLAT:
Jian Li2ce718e2021-02-17 20:42:15 +0900433 case VLAN:
Jian Li858ccd72021-02-04 17:25:01 +0900434 default:
435 // do nothing
436 return null;
437 }
438 }
439
Jian Li810f58c2021-02-27 01:10:50 +0900440 public static String parseResourceName(String resource) {
441 try {
442 JSONObject json = new JSONObject(resource);
443 return json.getJSONObject("metadata").getString("name");
444 } catch (JSONException e) {
445 log.error("");
446 }
447 return "";
448 }
449
Daniel Parkf3136042021-03-10 07:49:11 +0900450 public static PortNumber portNumber(DeviceId deviceId, String portName) {
Jian Li858ccd72021-02-04 17:25:01 +0900451 DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
452 Port port = deviceService.getPorts(deviceId).stream()
453 .filter(p -> p.isEnabled() &&
454 Objects.equals(p.annotations().value(PORT_NAME), portName))
455 .findAny().orElse(null);
456 return port != null ? port.number() : null;
457 }
458
Daniel Park2884b232021-03-04 18:58:47 +0900459 /**
460 * Returns the gateway node for the specified kubevirt router.
461 * Among gateways, only one gateway would act as a gateway per perter.
462 * Currently gateway node is selected based on modulo operation with router hashcode.
463 *
464 * @param nodeService kubevirt node service
465 * @param router kubevirt router
466 * @return elected gateway node
467 */
468 public static KubevirtNode gatewayNodeForSpecifiedRouter(KubevirtNodeService nodeService,
469 KubevirtRouter router) {
470 //TODO: enhance election logic for a better load balancing
471
472 int numOfGateways = nodeService.completeNodes(GATEWAY).size();
473 if (numOfGateways == 0) {
474 return null;
475 }
476 return (KubevirtNode) nodeService.completeNodes(GATEWAY).toArray()[router.hashCode() % numOfGateways];
477 }
478
479 /**
Daniel Parkf3136042021-03-10 07:49:11 +0900480 * Returns the mac address of the router.
481 *
482 * @param router kubevirt router
483 * @return macc address of the router
484 */
485 public static MacAddress getRouterMacAddress(KubevirtRouter router) {
486 if (router.mac() == null) {
487 log.warn("Failed to get mac address of router {}", router.name());
488 }
489
490 return router.mac();
Daniel Park2884b232021-03-04 18:58:47 +0900491 }
492
493 /**
494 * Returns the snat ip address with specified router.
495 *
496 * @param routerService router service
497 * @param internalNetworkId internal network id which is associated with the router
498 * @return snat ip address if exist, null otherwise
499 */
500 public static IpAddress getRouterSnatIpAddress(KubevirtRouterService routerService,
501 String internalNetworkId) {
502 KubevirtRouter router = routerService.routers().stream()
503 .filter(r -> r.internal().contains(internalNetworkId))
504 .findAny().orElse(null);
505
506 if (router == null) {
507 return null;
508 }
509
510 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
511
512 if (routerSnatIp == null) {
513 return null;
514 }
515
516 return Ip4Address.valueOf(routerSnatIp);
517 }
Daniel Parkbabde9c2021-03-09 13:37:42 +0900518
519 /**
520 * Returns the kubevirt router with specified kubevirt port.
521 *
522 * @param routerService kubevirt router service
523 * @param kubevirtPort kubevirt port
524 * @return kubevirt router
525 */
526 public static KubevirtRouter getRouterForKubevirtPort(KubevirtRouterService routerService,
527 KubevirtPort kubevirtPort) {
528 if (kubevirtPort.ipAddress() != null) {
529 return routerService.routers().stream()
530 .filter(r -> r.internal().contains(kubevirtPort.networkId()))
531 .findAny().orElse(null);
532 }
533 return null;
534 }
535
536 /**
537 * Returns the kubevirt router with specified kubevirt network.
538 *
539 * @param routerService kubevirt router service
540 * @param kubevirtNetwork kubevirt network
541 * @return kubevirt router
542 */
543 public static KubevirtRouter getRouterForKubevirtNetwork(KubevirtRouterService routerService,
544 KubevirtNetwork kubevirtNetwork) {
545 return routerService.routers().stream()
546 .filter(router -> router.internal().contains(kubevirtNetwork.networkId()))
547 .findAny().orElse(null);
548 }
Daniel Parkf3136042021-03-10 07:49:11 +0900549
550 /**
551 * Returns the external patch port number with specified gateway.
552 *
553 * @param deviceService device service
Jian Li9793ec42021-03-19 15:03:32 +0900554 * @param gatewayNode gateway node
Daniel Parkf3136042021-03-10 07:49:11 +0900555 * @return external patch port number
556 */
557 public static PortNumber externalPatchPortNum(DeviceService deviceService, KubevirtNode gatewayNode) {
Jian Li63f191f2021-03-25 17:14:40 +0900558 String gatewayBridgeName = gatewayNode.gatewayBridgeName();
559 if (gatewayBridgeName == null) {
Jian Li9793ec42021-03-19 15:03:32 +0900560 log.warn("No external interface is attached to gateway {}", gatewayNode.hostname());
561 return null;
562 }
563
Jian Li63f191f2021-03-25 17:14:40 +0900564 String patchPortName = "int-to-" + gatewayBridgeName;
Daniel Parkf3136042021-03-10 07:49:11 +0900565 Port port = deviceService.getPorts(gatewayNode.intgBridge()).stream()
566 .filter(p -> p.isEnabled() &&
Jian Li9793ec42021-03-19 15:03:32 +0900567 Objects.equals(p.annotations().value(PORT_NAME), patchPortName))
Daniel Parkf3136042021-03-10 07:49:11 +0900568 .findAny().orElse(null);
569
570 return port != null ? port.number() : null;
571 }
572
Daniel Park157947f2021-04-09 17:50:53 +0900573 /**
574 * Returns the kubevirt external network with specified router.
575 *
576 * @param networkService kubevirt network service
577 * @param router kubevirt router
578 * @return external network
579 */
Daniel Parkf3136042021-03-10 07:49:11 +0900580 public static KubevirtNetwork getExternalNetworkByRouter(KubevirtNetworkService networkService,
581 KubevirtRouter router) {
582 String networkId = router.external().values().stream().findAny().orElse(null);
583 if (networkId == null) {
584 return null;
585 }
586
587 return networkService.network(networkId);
588 }
Daniel Park157947f2021-04-09 17:50:53 +0900589
Jian Li94b6d162021-04-15 17:09:11 +0900590 /**
591 * Resolve a DNS with the given DNS server and hostname.
592 *
593 * @param hostname hostname to be resolved
594 * @return resolved IP address
595 */
596 public static IpAddress resolveHostname(String hostname) {
597 try {
598 InetAddress addr = Address.getByName(hostname);
599 return IpAddress.valueOf(IpAddress.Version.INET, addr.getAddress());
600 } catch (UnknownHostException e) {
601 log.warn("Failed to resolve IP address of host {}", hostname);
602 }
603 return null;
604 }
605
606 /**
607 * Builds a GARP packet using the given source MAC and source IP address.
608 *
609 * @param srcMac source MAC address
610 * @param srcIp source IP address
611 * @return GARP packet
612 */
Daniel Park157947f2021-04-09 17:50:53 +0900613 public static Ethernet buildGarpPacket(MacAddress srcMac, IpAddress srcIp) {
614 if (srcMac == null || srcIp == null) {
615 return null;
616 }
617
618 Ethernet ethernet = new Ethernet();
619 ethernet.setDestinationMACAddress(MacAddress.BROADCAST);
620 ethernet.setSourceMACAddress(srcMac);
621 ethernet.setEtherType(Ethernet.TYPE_ARP);
622
623 ARP arp = new ARP();
624 arp.setOpCode(ARP.OP_REPLY);
625 arp.setProtocolType(ARP.PROTO_TYPE_IP);
626 arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
627
628 arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
629 arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
630
631 arp.setSenderHardwareAddress(srcMac.toBytes());
632 arp.setTargetHardwareAddress(MacAddress.BROADCAST.toBytes());
633
634 arp.setSenderProtocolAddress(srcIp.toOctets());
635 arp.setTargetProtocolAddress(srcIp.toOctets());
636
637 ethernet.setPayload(arp);
638
639 return ethernet;
640 }
Daniel Park05a94582021-05-12 10:57:02 +0900641
642 /**
643 * Obtains flow group key from the given id.
644 *
645 * @param groupId flow group identifier
646 * @return flow group key
647 */
648 public static GroupKey getGroupKey(int groupId) {
649 return new DefaultGroupKey((Integer.toString(groupId)).getBytes());
650 }
651
652 /**
653 * Obtains load balancer set from the given router.
654 *
655 * @param router kubevirt router
656 * @param lbService kubevirt loadbalancer service
657 * @return loadbalancer set
658 */
659 public static Set<KubevirtLoadBalancer> getLoadBalancerSetForRouter(KubevirtRouter router,
660 KubevirtLoadBalancerService lbService) {
661
662 return lbService.loadBalancers().stream()
663 .filter(lb -> router.internal().contains(lb.networkId()))
664 .collect(Collectors.toSet());
665 }
Jian Li43244382021-01-09 00:19:02 +0900666}