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