blob: 74b7c8a5de97748c343cd5769d6c6798e6ec53ae [file] [log] [blame]
Jian Li3ba5c582021-01-14 11:30:36 +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.impl;
17
18import com.google.common.base.Strings;
19import com.google.common.collect.ImmutableList;
20import com.google.common.collect.Lists;
21import org.onlab.packet.DHCP;
22import org.onlab.packet.Ethernet;
23import org.onlab.packet.IPv4;
24import org.onlab.packet.Ip4Address;
25import org.onlab.packet.IpAddress;
26import org.onlab.packet.IpPrefix;
27import org.onlab.packet.MacAddress;
28import org.onlab.packet.UDP;
29import org.onlab.packet.dhcp.DhcpOption;
30import org.onlab.util.Tools;
31import org.onosproject.cfg.ComponentConfigService;
32import org.onosproject.cluster.ClusterService;
33import org.onosproject.cluster.LeadershipService;
34import org.onosproject.cluster.NodeId;
35import org.onosproject.core.ApplicationId;
36import org.onosproject.core.CoreService;
37import org.onosproject.kubevirtnetworking.api.KubevirtFlowRuleService;
38import org.onosproject.kubevirtnetworking.api.KubevirtHostRoute;
39import org.onosproject.kubevirtnetworking.api.KubevirtNetwork;
40import org.onosproject.kubevirtnetworking.api.KubevirtNetworkService;
41import org.onosproject.kubevirtnetworking.api.KubevirtPort;
42import org.onosproject.kubevirtnetworking.api.KubevirtPortService;
43import org.onosproject.kubevirtnode.api.KubevirtNodeEvent;
44import org.onosproject.kubevirtnode.api.KubevirtNodeListener;
45import org.onosproject.kubevirtnode.api.KubevirtNodeService;
46import org.onosproject.net.ConnectPoint;
47import org.onosproject.net.flow.DefaultTrafficTreatment;
48import org.onosproject.net.flow.TrafficTreatment;
49import org.onosproject.net.packet.DefaultOutboundPacket;
50import org.onosproject.net.packet.PacketContext;
51import org.onosproject.net.packet.PacketProcessor;
52import org.onosproject.net.packet.PacketService;
53import org.osgi.service.component.ComponentContext;
54import org.osgi.service.component.annotations.Activate;
55import org.osgi.service.component.annotations.Component;
56import org.osgi.service.component.annotations.Deactivate;
57import org.osgi.service.component.annotations.Modified;
58import org.osgi.service.component.annotations.Reference;
59import org.osgi.service.component.annotations.ReferenceCardinality;
60import org.slf4j.Logger;
61
62import java.nio.ByteBuffer;
63import java.util.Dictionary;
64import java.util.List;
65import java.util.Objects;
66import java.util.concurrent.ExecutorService;
67
68import static com.google.common.base.Preconditions.checkNotNull;
69import static java.util.concurrent.Executors.newSingleThreadExecutor;
70import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_BroadcastAddress;
71import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_Classless_Static_Route;
72import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_DHCPServerIp;
73import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_DomainServer;
74import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_END;
75import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_LeaseTime;
76import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_MessageType;
77import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_RouterAddress;
78import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_SubnetMask;
79import static org.onlab.packet.DHCP.MsgType.DHCPACK;
80import static org.onlab.packet.DHCP.MsgType.DHCPOFFER;
81import static org.onlab.util.Tools.groupedThreads;
82import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
83import static org.onosproject.kubevirtnetworking.impl.OsgiPropertyConstants.DHCP_SERVER_MAC;
84import static org.onosproject.kubevirtnetworking.impl.OsgiPropertyConstants.DHCP_SERVER_MAC_DEFAULT;
85import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getBroadcastAddr;
86import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.WORKER;
87import static org.slf4j.LoggerFactory.getLogger;
88
89/**
90 * Handles DHCP requests for the virtual instances.
91 */
92@Component(
93 immediate = true,
94 property = {
95 DHCP_SERVER_MAC + "=" + DHCP_SERVER_MAC_DEFAULT
96 }
97)
98public class KubevirtDhcpHandler {
99 protected final Logger log = getLogger(getClass());
100
101 private static final Ip4Address DEFAULT_PRIMARY_DNS = Ip4Address.valueOf("8.8.8.8");
102 private static final Ip4Address DEFAULT_SECONDARY_DNS = Ip4Address.valueOf("8.8.4.4");
103 private static final byte PACKET_TTL = (byte) 127;
104
105 // TODO add MTU, static route option codes to ONOS DHCP and remove here
106 private static final byte DHCP_OPTION_MTU = (byte) 26;
107 private static final byte[] DHCP_DATA_LEASE_INFINITE =
108 ByteBuffer.allocate(4).putInt(-1).array();
109
110 private static final int OCTET_BIT_LENGTH = 8;
111 private static final int V4_BYTE_SIZE = 4;
112 private static final int V4_CIDR_LOWER_BOUND = -1;
113 private static final int V4_CIDR_UPPER_BOUND = 33;
114 private static final int PADDING_SIZE = 4;
115
116 private static final byte HARDWARE_ADDR_LENGTH = (byte) 6;
117 private static final byte DHCP_OPTION_DATA_LENGTH = (byte) 4;
118 private static final int DHCP_OPTION_DNS_LENGTH = 8;
119 private static final int DHCP_OPTION_MTU_LENGTH = 2;
120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY)
122 protected CoreService coreService;
123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY)
125 protected ComponentConfigService configService;
126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY)
128 protected PacketService packetService;
129
130 @Reference(cardinality = ReferenceCardinality.MANDATORY)
131 protected ClusterService clusterService;
132
133 @Reference(cardinality = ReferenceCardinality.MANDATORY)
134 protected LeadershipService leadershipService;
135
136 @Reference(cardinality = ReferenceCardinality.MANDATORY)
137 protected KubevirtNodeService nodeService;
138
139 @Reference(cardinality = ReferenceCardinality.MANDATORY)
140 protected KubevirtPortService portService;
141
142 @Reference(cardinality = ReferenceCardinality.MANDATORY)
143 protected KubevirtNetworkService networkService;
144
145 @Reference(cardinality = ReferenceCardinality.MANDATORY)
146 protected KubevirtFlowRuleService flowService;
147
148 /** Fake MAC address for virtual network subnet gateway. */
149 private String dhcpServerMac = DHCP_SERVER_MAC_DEFAULT;
150
151 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
152 private final KubevirtNodeListener nodeListener = new InternalNodeEventListener();
153
154 private final ExecutorService eventExecutor = newSingleThreadExecutor(
155 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
156
157 private ApplicationId appId;
158 private NodeId localNodeId;
159
160 @Activate
161 protected void activate() {
162 appId = coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
163 localNodeId = clusterService.getLocalNode().id();
164 nodeService.addListener(nodeListener);
165 configService.registerProperties(getClass());
166 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
167 leadershipService.runForLeadership(appId.name());
168
169 log.info("Started");
170 }
171
172 @Deactivate
173 protected void deactivate() {
174 packetService.removeProcessor(packetProcessor);
175 nodeService.removeListener(nodeListener);
176 configService.unregisterProperties(getClass(), false);
177 leadershipService.withdraw(appId.name());
178 eventExecutor.shutdown();
179
180 log.info("Stopped");
181 }
182
183 @Modified
184 protected void modified(ComponentContext context) {
185 Dictionary<?, ?> properties = context.getProperties();
186 String updatedMac;
187
188 updatedMac = Tools.get(properties, DHCP_SERVER_MAC);
189
190 if (!Strings.isNullOrEmpty(updatedMac) && !updatedMac.equals(dhcpServerMac)) {
191 dhcpServerMac = updatedMac;
192 }
193
194 log.info("Modified");
195 }
196
197 private class InternalPacketProcessor implements PacketProcessor {
198
199 @Override
200 public void process(PacketContext context) {
201 if (context.isHandled()) {
202 return;
203 }
204
205 Ethernet ethPacket = context.inPacket().parsed();
206 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_IPV4) {
207 return;
208 }
209 IPv4 ipv4Packet = (IPv4) ethPacket.getPayload();
210 if (ipv4Packet.getProtocol() != IPv4.PROTOCOL_UDP) {
211 return;
212 }
213 UDP udpPacket = (UDP) ipv4Packet.getPayload();
214 if (udpPacket.getDestinationPort() != UDP.DHCP_SERVER_PORT ||
215 udpPacket.getSourcePort() != UDP.DHCP_CLIENT_PORT) {
216 return;
217 }
218
219 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
220
221 eventExecutor.execute(() -> processDhcp(context, dhcpPacket));
222 }
223
224 private void processDhcp(PacketContext context, DHCP dhcpPacket) {
225 if (dhcpPacket == null) {
226 log.trace("DHCP packet without payload received, do nothing");
227 return;
228 }
229
230 DHCP.MsgType inPacketType = getPacketType(dhcpPacket);
231 if (inPacketType == null || dhcpPacket.getClientHardwareAddress() == null) {
232 log.trace("Malformed DHCP packet received, ignore it");
233 return;
234 }
235
236 MacAddress clientMac = MacAddress.valueOf(dhcpPacket.getClientHardwareAddress());
237
238 KubevirtPort port = portService.ports().stream()
239 .filter(p -> p.macAddress().equals(clientMac))
240 .findAny().orElse(null);
241
242 if (port == null) {
243 log.debug("Ignore DHCP request, since it comes from unmanaged VM {}", clientMac);
244 return;
245 }
246
247 IpAddress fixedIp = port.ipAddress();
248
249 if (fixedIp == null) {
250 log.warn("There is no IP addresses are assigned with the port {}", port.macAddress());
251 return;
252 }
253
254 Ethernet ethPacket = context.inPacket().parsed();
255 switch (inPacketType) {
256 case DHCPDISCOVER:
257 processDhcpDiscover(context, clientMac, port, ethPacket);
258 break;
259 case DHCPREQUEST:
260 processDhcpRequest(context, clientMac, port, ethPacket);
261 break;
262 case DHCPRELEASE:
263 log.trace("DHCP RELEASE received from {}", clientMac);
264 // do nothing
265 break;
266 default:
267 break;
268 }
269 }
270
271 private void processDhcpDiscover(PacketContext context, MacAddress clientMac,
272 KubevirtPort port, Ethernet ethPacket) {
273 log.trace("DHCP DISCOVER received from {}", clientMac);
274 Ethernet discoverReply = buildReply(ethPacket,
275 (byte) DHCPOFFER.getValue(),
276 port);
277 sendReply(context, discoverReply);
278 log.trace("DHCP OFFER({}) is sent for {}", port.ipAddress().toString(), clientMac);
279 }
280
281 private void processDhcpRequest(PacketContext context, MacAddress clientMac,
282 KubevirtPort port, Ethernet ethPacket) {
283 log.trace("DHCP REQUEST received from {}", clientMac);
284 Ethernet requestReply = buildReply(ethPacket,
285 (byte) DHCPACK.getValue(),
286 port);
287 sendReply(context, requestReply);
288 log.trace("DHCP ACK({}) is sent for {}", port.ipAddress(), clientMac);
289 }
290
291 private DHCP.MsgType getPacketType(DHCP dhcpPacket) {
292 DhcpOption optType = dhcpPacket.getOption(OptionCode_MessageType);
293 if (optType == null) {
294 log.trace("DHCP packet with no message type, ignore it");
295 return null;
296 }
297
298 DHCP.MsgType inPacketType = DHCP.MsgType.getType(optType.getData()[0]);
299 if (inPacketType == null) {
300 log.trace("DHCP packet with no packet type, ignore it");
301 }
302 return inPacketType;
303 }
304
305 private Ethernet buildReply(Ethernet ethRequest, byte packetType,
306 KubevirtPort port) {
307 log.trace("Build for DHCP reply msg for openstack port {}", port.toString());
308
309 // pick one IP address to make a reply
310 // since we check the validity of fixed IP address at parent method,
311 // so no need to double check the fixed IP existence here
312 IpAddress fixedIp = port.ipAddress();
313
314 KubevirtNetwork network = networkService.network(port.networkId());
315
316 Ethernet ethReply = new Ethernet();
317 ethReply.setSourceMACAddress(dhcpServerMac);
318 ethReply.setDestinationMACAddress(ethRequest.getSourceMAC());
319 ethReply.setEtherType(Ethernet.TYPE_IPV4);
320
321 IPv4 ipv4Request = (IPv4) ethRequest.getPayload();
322 IPv4 ipv4Reply = new IPv4();
323
324 ipv4Reply.setSourceAddress(
325 clusterService.getLocalNode().ip().getIp4Address().toString());
326 ipv4Reply.setDestinationAddress(fixedIp.toString());
327 ipv4Reply.setTtl(PACKET_TTL);
328
329 UDP udpRequest = (UDP) ipv4Request.getPayload();
330 UDP udpReply = new UDP();
331 udpReply.setSourcePort((byte) UDP.DHCP_SERVER_PORT);
332 udpReply.setDestinationPort((byte) UDP.DHCP_CLIENT_PORT);
333
334 DHCP dhcpRequest = (DHCP) udpRequest.getPayload();
335 DHCP dhcpReply = buildDhcpReply(
336 dhcpRequest,
337 packetType,
338 Ip4Address.valueOf(fixedIp.toString()), port, network);
339
340 udpReply.setPayload(dhcpReply);
341 ipv4Reply.setPayload(udpReply);
342 ethReply.setPayload(ipv4Reply);
343
344 return ethReply;
345 }
346
347 private void sendReply(PacketContext context, Ethernet ethReply) {
348 if (ethReply == null) {
349 return;
350 }
351 ConnectPoint srcPoint = context.inPacket().receivedFrom();
352 TrafficTreatment treatment = DefaultTrafficTreatment
353 .builder()
354 .setOutput(srcPoint.port())
355 .build();
356
357 packetService.emit(new DefaultOutboundPacket(
358 srcPoint.deviceId(),
359 treatment,
360 ByteBuffer.wrap(ethReply.serialize())));
361 context.block();
362 }
363
364 private DHCP buildDhcpReply(DHCP request, byte msgType, Ip4Address yourIp,
365 KubevirtPort port, KubevirtNetwork network) {
366 Ip4Address gatewayIp = clusterService.getLocalNode().ip().getIp4Address();
367 int subnetPrefixLen = IpPrefix.valueOf(network.cidr()).prefixLength();
368
369 DHCP dhcpReply = new DHCP();
370 dhcpReply.setOpCode(DHCP.OPCODE_REPLY);
371 dhcpReply.setHardwareType(DHCP.HWTYPE_ETHERNET);
372 dhcpReply.setHardwareAddressLength(HARDWARE_ADDR_LENGTH);
373 dhcpReply.setTransactionId(request.getTransactionId());
374 dhcpReply.setFlags(request.getFlags());
375 dhcpReply.setYourIPAddress(yourIp.toInt());
376 dhcpReply.setServerIPAddress(gatewayIp.toInt());
377 dhcpReply.setClientHardwareAddress(request.getClientHardwareAddress());
378
379 List<DhcpOption> options = Lists.newArrayList();
380
381 // message type
382 options.add(doMsgType(msgType));
383
384 // server identifier
385 options.add(doServerId(gatewayIp));
386
387 // lease time
388 options.add(doLeaseTime());
389
390 // subnet mask
391 options.add(doSubnetMask(subnetPrefixLen));
392
393 // broadcast address
394 options.add(doBroadcastAddr(yourIp, subnetPrefixLen));
395
396 // domain server
397 options.add(doDomainServer(network));
398
399 // mtu
400 options.add(doMtu(network));
401
402 // classless static route
403 if (!network.hostRoutes().isEmpty()) {
404 options.add(doClasslessSr(network));
405 }
406
407 // Sets the default router address up.
408 // Performs only if the gateway is set in subnet.
409 if (network.gatewayIp() != null) {
410 options.add(doRouterAddr(network));
411 }
412
413 // end option
414 options.add(doEnd());
415
416 dhcpReply.setOptions(options);
417 return dhcpReply;
418 }
419
420
421 private DhcpOption doMsgType(byte msgType) {
422 DhcpOption option = new DhcpOption();
423 option.setCode(OptionCode_MessageType.getValue());
424 option.setLength((byte) 1);
425 byte[] optionData = {msgType};
426 option.setData(optionData);
427 return option;
428 }
429
430 private DhcpOption doServerId(IpAddress gatewayIp) {
431 DhcpOption option = new DhcpOption();
432 option.setCode(OptionCode_DHCPServerIp.getValue());
433 option.setLength(DHCP_OPTION_DATA_LENGTH);
434 option.setData(gatewayIp.toOctets());
435 return option;
436 }
437
438 private DhcpOption doLeaseTime() {
439 DhcpOption option = new DhcpOption();
440 option.setCode(OptionCode_LeaseTime.getValue());
441 option.setLength(DHCP_OPTION_DATA_LENGTH);
442 option.setData(DHCP_DATA_LEASE_INFINITE);
443 return option;
444 }
445
446 private DhcpOption doSubnetMask(int subnetPrefixLen) {
447 Ip4Address subnetMask = Ip4Address.makeMaskPrefix(subnetPrefixLen);
448 DhcpOption option = new DhcpOption();
449 option.setCode(OptionCode_SubnetMask.getValue());
450 option.setLength(DHCP_OPTION_DATA_LENGTH);
451 option.setData(subnetMask.toOctets());
452 return option;
453 }
454
455 private DhcpOption doBroadcastAddr(Ip4Address yourIp, int subnetPrefixLen) {
456 String broadcast = getBroadcastAddr(yourIp.toString(), subnetPrefixLen);
457
458 DhcpOption option = new DhcpOption();
459 option.setCode(OptionCode_BroadcastAddress.getValue());
460 option.setLength(DHCP_OPTION_DATA_LENGTH);
461 option.setData(IpAddress.valueOf(broadcast).toOctets());
462
463 return option;
464 }
465
466 private DhcpOption doDomainServer(KubevirtNetwork network) {
467 DhcpOption option = new DhcpOption();
468
469 option.setCode(OptionCode_DomainServer.getValue());
470
471 option.setLength((byte) DHCP_OPTION_DNS_LENGTH);
472 ByteBuffer dnsByteBuf = ByteBuffer.allocate(DHCP_OPTION_DNS_LENGTH);
473 dnsByteBuf.put(DEFAULT_PRIMARY_DNS.toOctets());
474 dnsByteBuf.put(DEFAULT_SECONDARY_DNS.toOctets());
475
476 option.setData(dnsByteBuf.array());
477
478 // TODO: need to customize the DNS server list
479// if (dnsServers.isEmpty()) {
480//
481// } else {
482// int dnsLength = 4 * dnsServers.size();
483//
484// option.setLength((byte) dnsLength);
485//
486// ByteBuffer dnsByteBuf = ByteBuffer.allocate(DHCP_OPTION_DNS_LENGTH);
487//
488// for (String dnsServer : dnsServers) {
489// dnsByteBuf.put(IpAddress.valueOf(dnsServer).toOctets());
490// }
491// option.setData(dnsByteBuf.array());
492// }
493
494 return option;
495 }
496
497 private DhcpOption doMtu(KubevirtNetwork network) {
498 DhcpOption option = new DhcpOption();
499 option.setCode(DHCP_OPTION_MTU);
500 option.setLength((byte) DHCP_OPTION_MTU_LENGTH);
501 checkNotNull(network);
502 checkNotNull(network.mtu());
503
504 option.setData(ByteBuffer.allocate(DHCP_OPTION_MTU_LENGTH)
505 .putShort(network.mtu().shortValue()).array());
506
507 return option;
508 }
509
510 private DhcpOption doClasslessSr(KubevirtNetwork network) {
511 DhcpOption option = new DhcpOption();
512 option.setCode(OptionCode_Classless_Static_Route.getValue());
513
514 int hostRoutesSize = hostRoutesSize(ImmutableList.copyOf(network.hostRoutes()));
515 if (hostRoutesSize == 0) {
516 throw new IllegalArgumentException("Illegal CIDR hostRoutesSize value!");
517 }
518
519 log.trace("hostRouteSize: {}", hostRoutesSize);
520
521 option.setLength((byte) hostRoutesSize);
522 ByteBuffer hostRouteByteBuf = ByteBuffer.allocate(hostRoutesSize);
523
524 network.hostRoutes().forEach(h -> {
525 log.debug("processing host route information: {}", h.toString());
526
527 IpPrefix ipPrefix = h.destination();
528
529 hostRouteByteBuf.put(Objects.requireNonNull(bytesDestinationDescriptor(ipPrefix)));
530 hostRouteByteBuf.put(h.nexthop().toOctets());
531 });
532
533 option.setData(hostRouteByteBuf.array());
534 return option;
535 }
536
537 private DhcpOption doRouterAddr(KubevirtNetwork network) {
538 DhcpOption option = new DhcpOption();
539 option.setCode(OptionCode_RouterAddress.getValue());
540 option.setLength(DHCP_OPTION_DATA_LENGTH);
541 option.setData(Ip4Address.valueOf(network.gatewayIp().toString()).toOctets());
542 return option;
543 }
544
545 private DhcpOption doEnd() {
546 DhcpOption option = new DhcpOption();
547 option.setCode(OptionCode_END.getValue());
548 option.setLength((byte) 1);
549 return option;
550 }
551
552 private int hostRoutesSize(List<KubevirtHostRoute> hostRoutes) {
553 int size = 0;
554 int preFixLen;
555
556 for (KubevirtHostRoute h : hostRoutes) {
557 preFixLen = h.destination().prefixLength();
558 if (Math.max(V4_CIDR_LOWER_BOUND, preFixLen) == V4_CIDR_LOWER_BOUND ||
559 Math.min(preFixLen, V4_CIDR_UPPER_BOUND) == V4_CIDR_UPPER_BOUND) {
560 throw new IllegalArgumentException("Illegal CIDR length value!");
561 }
562
563 for (int i = 0; i <= V4_BYTE_SIZE; i++) {
564 if (preFixLen == Math.min(preFixLen, i * OCTET_BIT_LENGTH)) {
565 size = size + i + 1 + PADDING_SIZE;
566 break;
567 }
568 }
569 }
570 return size;
571 }
572
573 private byte[] bytesDestinationDescriptor(IpPrefix ipPrefix) {
574 ByteBuffer byteBuffer;
575 int prefixLen = ipPrefix.prefixLength();
576
577 // retrieve ipPrefix to the destination descriptor format
578 // ex) 10.1.1.0/24 -> [10,1,1,0]
579 String[] ipPrefixString = ipPrefix.getIp4Prefix().toString()
580 .split("/")[0]
581 .split("\\.");
582
583 // retrieve destination descriptor and put this to byte buffer
584 // according to RFC 3442
585 // ex) 0.0.0.0/0 -> 0
586 // ex) 10.0.0.0/8 -> 8.10
587 // ex) 10.17.0.0/16 -> 16.10.17
588 // ex) 10.27.129.0/24 -> 24.10.27.129
589 // ex) 10.229.0.128/25 -> 25.10.229.0.128
590 for (int i = 0; i <= V4_BYTE_SIZE; i++) {
591 if (prefixLen == Math.min(prefixLen, i * OCTET_BIT_LENGTH)) {
592 byteBuffer = ByteBuffer.allocate(i + 1);
593 byteBuffer.put((byte) prefixLen);
594
595 for (int j = 0; j < i; j++) {
596 byteBuffer.put((byte) Integer.parseInt(ipPrefixString[j]));
597 }
598 return byteBuffer.array();
599 }
600 }
601
602 return null;
603 }
604 }
605
606 private class InternalNodeEventListener implements KubevirtNodeListener {
607
608 @Override
609 public boolean isRelevant(KubevirtNodeEvent event) {
610 return event.subject().type() == WORKER;
611 }
612
613 private boolean isRelevantHelper() {
614 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
615 }
616
617 @Override
618 public void event(KubevirtNodeEvent event) {
619
620 }
621 }
622}