blob: 14bc79cbc3838062e9c3d42bd70a78e2d79ec9c5 [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;
53
Jian Lif97a07e2021-01-13 18:05:00 +090054import java.io.IOException;
Jian Li3ba5c582021-01-14 11:30:36 +090055import java.util.Arrays;
56import java.util.HashSet;
Jian Lif97a07e2021-01-13 18:05:00 +090057import java.util.List;
Jian Lica20b712021-01-18 00:19:31 +090058import java.util.Map;
Jian Li858ccd72021-02-04 17:25:01 +090059import java.util.Objects;
Jian Li43244382021-01-09 00:19:02 +090060import java.util.Optional;
61import java.util.Set;
Jian Li3ba5c582021-01-14 11:30:36 +090062import java.util.stream.Collectors;
Jian Li43244382021-01-09 00:19:02 +090063
Jian Li858ccd72021-02-04 17:25:01 +090064import static org.onosproject.kubevirtnetworking.api.Constants.TUNNEL_TO_TENANT_PREFIX;
Daniel Park2884b232021-03-04 18:58:47 +090065import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.GATEWAY;
Jian Li858ccd72021-02-04 17:25:01 +090066import static org.onosproject.net.AnnotationKeys.PORT_NAME;
67
Jian Li43244382021-01-09 00:19:02 +090068/**
69 * An utility that used in KubeVirt networking app.
70 */
71public final class KubevirtNetworkingUtil {
72
73 private static final Logger log = LoggerFactory.getLogger(KubevirtNetworkingUtil.class);
74
75 private static final int PORT_NAME_MAX_LENGTH = 15;
Jian Li034820d2021-01-15 16:58:48 +090076 private static final String COLON_SLASH = "://";
77 private static final String COLON = ":";
Jian Li556709c2021-02-03 17:54:28 +090078 private static final String OF_PREFIX = "of:";
Jian Li43244382021-01-09 00:19:02 +090079
Jian Lica20b712021-01-18 00:19:31 +090080 private static final String NETWORK_STATUS_KEY = "k8s.v1.cni.cncf.io/network-status";
81 private static final String NAME = "name";
82 private static final String NETWORK_PREFIX = "default/";
83 private static final String MAC = "mac";
84 private static final String IPS = "ips";
Daniel Parkbabde9c2021-03-09 13:37:42 +090085 private static final String BR_INT = "br-int";
Jian Lica20b712021-01-18 00:19:31 +090086
Jian Li43244382021-01-09 00:19:02 +090087 /**
88 * Prevents object installation from external.
89 */
90 private KubevirtNetworkingUtil() {
91 }
92
93 /**
94 * Obtains the boolean property value with specified property key name.
95 *
Daniel Park2884b232021-03-04 18:58:47 +090096 * @param properties a collection of properties
97 * @param name key name
Jian Li43244382021-01-09 00:19:02 +090098 * @return mapping value
99 */
100 public static boolean getPropertyValueAsBoolean(Set<ConfigProperty> properties,
101 String name) {
102 Optional<ConfigProperty> property =
103 properties.stream().filter(p -> p.name().equals(name)).findFirst();
104
105 return property.map(ConfigProperty::asBoolean).orElse(false);
106 }
107
108 /**
109 * Re-structures the OVS port name.
110 * The length of OVS port name should be not large than 15.
111 *
Daniel Park2884b232021-03-04 18:58:47 +0900112 * @param portName original port name
Jian Li43244382021-01-09 00:19:02 +0900113 * @return re-structured OVS port name
114 */
115 public static String structurePortName(String portName) {
116
117 // The size of OVS port name should not be larger than 15
118 if (portName.length() > PORT_NAME_MAX_LENGTH) {
119 return StringUtils.substring(portName, 0, PORT_NAME_MAX_LENGTH);
120 }
121
122 return portName;
123 }
Jian Lif97a07e2021-01-13 18:05:00 +0900124
125 /**
126 * Generates string format based on the given string length list.
127 *
128 * @param stringLengths a list of string lengths
129 * @return string format (e.g., %-28s%-15s%-24s%-20s%-15s)
130 */
131 public static String genFormatString(List<Integer> stringLengths) {
132 StringBuilder fsb = new StringBuilder();
133 stringLengths.forEach(length -> {
134 fsb.append("%-");
135 fsb.append(length);
136 fsb.append("s");
137 });
138 return fsb.toString();
139 }
140
141 /**
Jian Li556709c2021-02-03 17:54:28 +0900142 * Auto generates DPID from the given name.
143 *
144 * @param name name
145 * @return auto generated DPID
146 */
147 public static String genDpidFromName(String name) {
148 if (name != null) {
149 String hexString = Integer.toHexString(name.hashCode());
150 return OF_PREFIX + Strings.padStart(hexString, 16, '0');
151 }
152
153 return null;
154 }
155
156 /**
Jian Lif97a07e2021-01-13 18:05:00 +0900157 * Prints out the JSON string in pretty format.
158 *
Daniel Park2884b232021-03-04 18:58:47 +0900159 * @param mapper Object mapper
160 * @param jsonString JSON string
Jian Lif97a07e2021-01-13 18:05:00 +0900161 * @return pretty formatted JSON string
162 */
163 public static String prettyJson(ObjectMapper mapper, String jsonString) {
164 try {
165 Object jsonObject = mapper.readValue(jsonString, Object.class);
166 return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject);
167 } catch (IOException e) {
168 log.debug("Json string parsing exception caused by {}", e);
169 }
170 return null;
171 }
Jian Li3ba5c582021-01-14 11:30:36 +0900172
173 /**
174 * Obtains valid IP addresses of the given subnet.
175 *
176 * @param cidr CIDR
177 * @return set of IP addresses
178 */
179 public static Set<IpAddress> getSubnetIps(String cidr) {
180 SubnetUtils utils = new SubnetUtils(cidr);
181 utils.setInclusiveHostCount(false);
182 SubnetUtils.SubnetInfo info = utils.getInfo();
183 Set<String> allAddresses =
184 new HashSet<>(Arrays.asList(info.getAllAddresses()));
185
186 if (allAddresses.size() > 2) {
187 allAddresses.remove(info.getLowAddress());
188 allAddresses.remove(info.getHighAddress());
189 }
190
191 return allAddresses.stream()
192 .map(IpAddress::valueOf).collect(Collectors.toSet());
193 }
194
195 /**
196 * Calculate the broadcast address from given IP address and subnet prefix length.
197 *
Daniel Park2884b232021-03-04 18:58:47 +0900198 * @param ipAddr IP address
199 * @param prefixLength subnet prefix length
Jian Li3ba5c582021-01-14 11:30:36 +0900200 * @return broadcast address
201 */
202 public static String getBroadcastAddr(String ipAddr, int prefixLength) {
203 String subnet = ipAddr + "/" + prefixLength;
204 SubnetUtils utils = new SubnetUtils(subnet);
205 return utils.getInfo().getBroadcastAddress();
206 }
Daniel Park2884b232021-03-04 18:58:47 +0900207
Jian Li034820d2021-01-15 16:58:48 +0900208 /**
209 * Generates endpoint URL by referring to scheme, ipAddress and port.
210 *
Daniel Park2884b232021-03-04 18:58:47 +0900211 * @param scheme scheme
212 * @param ipAddress IP address
213 * @param port port number
Jian Li034820d2021-01-15 16:58:48 +0900214 * @return generated endpoint URL
215 */
216 public static String endpoint(KubevirtApiConfig.Scheme scheme, IpAddress ipAddress, int port) {
217 StringBuilder endpoint = new StringBuilder();
218 String protocol = org.apache.commons.lang3.StringUtils.lowerCase(scheme.name());
219
220 endpoint.append(protocol);
221 endpoint.append(COLON_SLASH);
222 endpoint.append(ipAddress.toString());
223 endpoint.append(COLON);
224 endpoint.append(port);
225
226 return endpoint.toString();
227 }
228
229 /**
230 * Generates endpoint URL by referring to scheme, ipAddress and port.
231 *
Daniel Park2884b232021-03-04 18:58:47 +0900232 * @param apiConfig kubernetes API config
Jian Li034820d2021-01-15 16:58:48 +0900233 * @return generated endpoint URL
234 */
235 public static String endpoint(KubevirtApiConfig apiConfig) {
236 return endpoint(apiConfig.scheme(), apiConfig.ipAddress(), apiConfig.port());
237 }
238
239 /**
240 * Obtains workable kubernetes client.
241 *
242 * @param config kubernetes API config
243 * @return kubernetes client
244 */
245 public static KubernetesClient k8sClient(KubevirtApiConfig config) {
246 if (config == null) {
247 log.warn("Kubernetes API server config is empty.");
248 return null;
249 }
250
251 String endpoint = endpoint(config);
252
253 ConfigBuilder configBuilder = new ConfigBuilder().withMasterUrl(endpoint);
254
255 if (config.scheme() == KubevirtApiConfig.Scheme.HTTPS) {
256 configBuilder.withTrustCerts(true)
Jian Li034820d2021-01-15 16:58:48 +0900257 .withCaCertData(config.caCertData())
258 .withClientCertData(config.clientCertData())
259 .withClientKeyData(config.clientKeyData());
260 }
261
262 return new DefaultKubernetesClient(configBuilder.build());
263 }
264
265 /**
266 * Obtains workable kubernetes client.
267 *
268 * @param service kubernetes API service
269 * @return kubernetes client
270 */
271 public static KubernetesClient k8sClient(KubevirtApiConfigService service) {
272 KubevirtApiConfig config = service.apiConfig();
273 if (config == null) {
274 log.error("Failed to find valid kubernetes API configuration.");
275 return null;
276 }
277
278 KubernetesClient client = k8sClient(config);
279
280 if (client == null) {
281 log.error("Failed to connect to kubernetes API server.");
282 return null;
283 }
284
285 return client;
286 }
Jian Lica20b712021-01-18 00:19:31 +0900287
288 /**
Jian Li556709c2021-02-03 17:54:28 +0900289 * Obtains the hex string of the given segment ID with fixed padding.
290 *
291 * @param segIdStr segment identifier string
292 * @return hex string with padding
293 */
294 public static String segmentIdHex(String segIdStr) {
295 int segId = Integer.parseInt(segIdStr);
296 return String.format("%06x", segId).toLowerCase();
297 }
298
299 /**
Jian Li858ccd72021-02-04 17:25:01 +0900300 * Obtains the tunnel port number with the given network and node.
301 *
302 * @param network kubevirt network
Daniel Park2884b232021-03-04 18:58:47 +0900303 * @param node kubevirt node
Jian Li858ccd72021-02-04 17:25:01 +0900304 * @return tunnel port number
305 */
306 public static PortNumber tunnelPort(KubevirtNetwork network, KubevirtNode node) {
307 switch (network.type()) {
308 case VXLAN:
309 return node.vxlanPort();
310 case GRE:
311 return node.grePort();
312 case GENEVE:
313 return node.genevePort();
314 default:
315 break;
316 }
317 return null;
318 }
319
320 /**
Jian Lica20b712021-01-18 00:19:31 +0900321 * Obtains the kubevirt port from kubevirt POD.
322 *
Daniel Parkf3136042021-03-10 07:49:11 +0900323 * @param nodeService kubevirt node service
Jian Lica20b712021-01-18 00:19:31 +0900324 * @param networks set of existing kubevirt networks
Daniel Park2884b232021-03-04 18:58:47 +0900325 * @param pod kubevirt POD
Jian Lid4296d02021-03-12 18:03:58 +0900326 * @return kubevirt ports attached to the POD
Jian Lica20b712021-01-18 00:19:31 +0900327 */
Jian Lib6dc08f2021-03-24 15:24:18 +0900328 public static Set<KubevirtPort> getPorts(KubevirtNodeService nodeService,
329 Set<KubevirtNetwork> networks, Pod pod) {
Jian Lica20b712021-01-18 00:19:31 +0900330 try {
331 Map<String, String> annots = pod.getMetadata().getAnnotations();
Jian Li6e66a302021-01-21 20:30:52 +0900332 if (annots == null) {
Jian Lid4296d02021-03-12 18:03:58 +0900333 return ImmutableSet.of();
Jian Li6e66a302021-01-21 20:30:52 +0900334 }
335
Jian Li7a581b12021-02-18 14:24:32 +0900336 if (!annots.containsKey(NETWORK_STATUS_KEY)) {
Jian Lid4296d02021-03-12 18:03:58 +0900337 return ImmutableSet.of();
Jian Li7a581b12021-02-18 14:24:32 +0900338 }
339
Jian Lica20b712021-01-18 00:19:31 +0900340 String networkStatusStr = annots.get(NETWORK_STATUS_KEY);
341
342 if (networkStatusStr == null) {
Jian Lid4296d02021-03-12 18:03:58 +0900343 return ImmutableSet.of();
Jian Lica20b712021-01-18 00:19:31 +0900344 }
Jian Lib6dc08f2021-03-24 15:24:18 +0900345
Daniel Parkf3136042021-03-10 07:49:11 +0900346 KubevirtPort.Builder builder = DefaultKubevirtPort.builder();
347
348 KubevirtNode node = nodeService.node(pod.getSpec().getNodeName());
Jian Lib6dc08f2021-03-24 15:24:18 +0900349
Daniel Parkf3136042021-03-10 07:49:11 +0900350 if (node != null) {
351 builder.deviceId(node.intgBridge());
352 }
Jian Lica20b712021-01-18 00:19:31 +0900353
354 JSONArray networkStatus = new JSONArray(networkStatusStr);
Jian Lid4296d02021-03-12 18:03:58 +0900355 Set<KubevirtPort> ports = new HashSet<>();
Jian Lica20b712021-01-18 00:19:31 +0900356
357 for (int i = 0; i < networkStatus.length(); i++) {
358 JSONObject object = networkStatus.getJSONObject(i);
359 String name = object.getString(NAME);
360 KubevirtNetwork network = networks.stream()
361 .filter(n -> (NETWORK_PREFIX + n.name()).equals(name))
362 .findAny().orElse(null);
363 if (network != null) {
364 String mac = object.getString(MAC);
365
Daniel Parkf3136042021-03-10 07:49:11 +0900366 builder.macAddress(MacAddress.valueOf(mac))
Jian Lica20b712021-01-18 00:19:31 +0900367 .networkId(network.networkId());
368
Jian Lid4296d02021-03-12 18:03:58 +0900369 ports.add(builder.build());
Jian Lica20b712021-01-18 00:19:31 +0900370 }
371 }
372
Jian Lid4296d02021-03-12 18:03:58 +0900373 return ports;
374
Jian Lica20b712021-01-18 00:19:31 +0900375 } catch (JSONException e) {
376 log.error("Failed to parse network status object", e);
377 }
378
Jian Lid4296d02021-03-12 18:03:58 +0900379 return ImmutableSet.of();
Jian Lica20b712021-01-18 00:19:31 +0900380 }
Jian Li858ccd72021-02-04 17:25:01 +0900381
382 /**
383 * Obtains the tunnel bridge to tenant bridge patch port number.
384 *
Daniel Park2884b232021-03-04 18:58:47 +0900385 * @param node kubevirt node
Jian Li858ccd72021-02-04 17:25:01 +0900386 * @param network kubevirt network
387 * @return patch port number
388 */
389 public static PortNumber tunnelToTenantPort(KubevirtNode node, KubevirtNetwork network) {
390 if (network.segmentId() == null) {
391 return null;
392 }
393
394 if (node.tunBridge() == null) {
395 return null;
396 }
397
398 String tunToTenantPortName = TUNNEL_TO_TENANT_PREFIX + segmentIdHex(network.segmentId());
399 return portNumber(node.tunBridge(), tunToTenantPortName);
400 }
401
402 /**
403 * Obtains the tunnel port number of the given node.
404 *
Daniel Park2884b232021-03-04 18:58:47 +0900405 * @param node kubevirt node
Jian Li858ccd72021-02-04 17:25:01 +0900406 * @param network kubevirt network
407 * @return tunnel port number
408 */
409 public static PortNumber tunnelPort(KubevirtNode node, KubevirtNetwork network) {
410 if (network.segmentId() == null) {
411 return null;
412 }
413
414 if (node.tunBridge() == null) {
415 return null;
416 }
417
418 switch (network.type()) {
419 case VXLAN:
420 return node.vxlanPort();
421 case GRE:
422 return node.grePort();
423 case GENEVE:
424 return node.genevePort();
425 case FLAT:
Jian Li2ce718e2021-02-17 20:42:15 +0900426 case VLAN:
Jian Li858ccd72021-02-04 17:25:01 +0900427 default:
428 // do nothing
429 return null;
430 }
431 }
432
Jian Li810f58c2021-02-27 01:10:50 +0900433 public static String parseResourceName(String resource) {
434 try {
435 JSONObject json = new JSONObject(resource);
436 return json.getJSONObject("metadata").getString("name");
437 } catch (JSONException e) {
438 log.error("");
439 }
440 return "";
441 }
442
Daniel Parkf3136042021-03-10 07:49:11 +0900443 public static PortNumber portNumber(DeviceId deviceId, String portName) {
Jian Li858ccd72021-02-04 17:25:01 +0900444 DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
445 Port port = deviceService.getPorts(deviceId).stream()
446 .filter(p -> p.isEnabled() &&
447 Objects.equals(p.annotations().value(PORT_NAME), portName))
448 .findAny().orElse(null);
449 return port != null ? port.number() : null;
450 }
451
Daniel Park2884b232021-03-04 18:58:47 +0900452 /**
453 * Returns the gateway node for the specified kubevirt router.
454 * Among gateways, only one gateway would act as a gateway per perter.
455 * Currently gateway node is selected based on modulo operation with router hashcode.
456 *
457 * @param nodeService kubevirt node service
458 * @param router kubevirt router
459 * @return elected gateway node
460 */
461 public static KubevirtNode gatewayNodeForSpecifiedRouter(KubevirtNodeService nodeService,
462 KubevirtRouter router) {
463 //TODO: enhance election logic for a better load balancing
464
465 int numOfGateways = nodeService.completeNodes(GATEWAY).size();
466 if (numOfGateways == 0) {
467 return null;
468 }
469 return (KubevirtNode) nodeService.completeNodes(GATEWAY).toArray()[router.hashCode() % numOfGateways];
470 }
471
472 /**
Daniel Parkf3136042021-03-10 07:49:11 +0900473 * Returns the mac address of the router.
474 *
475 * @param router kubevirt router
476 * @return macc address of the router
477 */
478 public static MacAddress getRouterMacAddress(KubevirtRouter router) {
479 if (router.mac() == null) {
480 log.warn("Failed to get mac address of router {}", router.name());
481 }
482
483 return router.mac();
Daniel Park2884b232021-03-04 18:58:47 +0900484 }
485
486 /**
487 * Returns the snat ip address with specified router.
488 *
489 * @param routerService router service
490 * @param internalNetworkId internal network id which is associated with the router
491 * @return snat ip address if exist, null otherwise
492 */
493 public static IpAddress getRouterSnatIpAddress(KubevirtRouterService routerService,
494 String internalNetworkId) {
495 KubevirtRouter router = routerService.routers().stream()
496 .filter(r -> r.internal().contains(internalNetworkId))
497 .findAny().orElse(null);
498
499 if (router == null) {
500 return null;
501 }
502
503 String routerSnatIp = router.external().keySet().stream().findAny().orElse(null);
504
505 if (routerSnatIp == null) {
506 return null;
507 }
508
509 return Ip4Address.valueOf(routerSnatIp);
510 }
Daniel Parkbabde9c2021-03-09 13:37:42 +0900511
512 /**
513 * Returns the kubevirt router with specified kubevirt port.
514 *
515 * @param routerService kubevirt router service
516 * @param kubevirtPort kubevirt port
517 * @return kubevirt router
518 */
519 public static KubevirtRouter getRouterForKubevirtPort(KubevirtRouterService routerService,
520 KubevirtPort kubevirtPort) {
521 if (kubevirtPort.ipAddress() != null) {
522 return routerService.routers().stream()
523 .filter(r -> r.internal().contains(kubevirtPort.networkId()))
524 .findAny().orElse(null);
525 }
526 return null;
527 }
528
529 /**
530 * Returns the kubevirt router with specified kubevirt network.
531 *
532 * @param routerService kubevirt router service
533 * @param kubevirtNetwork kubevirt network
534 * @return kubevirt router
535 */
536 public static KubevirtRouter getRouterForKubevirtNetwork(KubevirtRouterService routerService,
537 KubevirtNetwork kubevirtNetwork) {
538 return routerService.routers().stream()
539 .filter(router -> router.internal().contains(kubevirtNetwork.networkId()))
540 .findAny().orElse(null);
541 }
Daniel Parkf3136042021-03-10 07:49:11 +0900542
543 /**
544 * Returns the external patch port number with specified gateway.
545 *
546 * @param deviceService device service
Jian Li9793ec42021-03-19 15:03:32 +0900547 * @param gatewayNode gateway node
Daniel Parkf3136042021-03-10 07:49:11 +0900548 * @return external patch port number
549 */
550 public static PortNumber externalPatchPortNum(DeviceService deviceService, KubevirtNode gatewayNode) {
Jian Li63f191f2021-03-25 17:14:40 +0900551 String gatewayBridgeName = gatewayNode.gatewayBridgeName();
552 if (gatewayBridgeName == null) {
Jian Li9793ec42021-03-19 15:03:32 +0900553 log.warn("No external interface is attached to gateway {}", gatewayNode.hostname());
554 return null;
555 }
556
Jian Li63f191f2021-03-25 17:14:40 +0900557 String patchPortName = "int-to-" + gatewayBridgeName;
Daniel Parkf3136042021-03-10 07:49:11 +0900558 Port port = deviceService.getPorts(gatewayNode.intgBridge()).stream()
559 .filter(p -> p.isEnabled() &&
Jian Li9793ec42021-03-19 15:03:32 +0900560 Objects.equals(p.annotations().value(PORT_NAME), patchPortName))
Daniel Parkf3136042021-03-10 07:49:11 +0900561 .findAny().orElse(null);
562
563 return port != null ? port.number() : null;
564 }
565
Daniel Park157947f2021-04-09 17:50:53 +0900566 /**
567 * Returns the kubevirt external network with specified router.
568 *
569 * @param networkService kubevirt network service
570 * @param router kubevirt router
571 * @return external network
572 */
Daniel Parkf3136042021-03-10 07:49:11 +0900573 public static KubevirtNetwork getExternalNetworkByRouter(KubevirtNetworkService networkService,
574 KubevirtRouter router) {
575 String networkId = router.external().values().stream().findAny().orElse(null);
576 if (networkId == null) {
577 return null;
578 }
579
580 return networkService.network(networkId);
581 }
Daniel Park157947f2021-04-09 17:50:53 +0900582
583 public static Ethernet buildGarpPacket(MacAddress srcMac, IpAddress srcIp) {
584 if (srcMac == null || srcIp == null) {
585 return null;
586 }
587
588 Ethernet ethernet = new Ethernet();
589 ethernet.setDestinationMACAddress(MacAddress.BROADCAST);
590 ethernet.setSourceMACAddress(srcMac);
591 ethernet.setEtherType(Ethernet.TYPE_ARP);
592
593 ARP arp = new ARP();
594 arp.setOpCode(ARP.OP_REPLY);
595 arp.setProtocolType(ARP.PROTO_TYPE_IP);
596 arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
597
598 arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
599 arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
600
601 arp.setSenderHardwareAddress(srcMac.toBytes());
602 arp.setTargetHardwareAddress(MacAddress.BROADCAST.toBytes());
603
604 arp.setSenderProtocolAddress(srcIp.toOctets());
605 arp.setTargetProtocolAddress(srcIp.toOctets());
606
607 ethernet.setPayload(arp);
608
609 return ethernet;
610 }
Jian Li43244382021-01-09 00:19:02 +0900611}