blob: 54f6987b5c11426301bdc5a5afa8af44bcb5e183 [file] [log] [blame]
Hyunsun Moon28b358a2016-11-28 13:23:05 -08001/*
Brian O'Connor80dff972017-08-03 22:46:30 -07002 * Copyright 2016-present Open Networking Foundation
Hyunsun Moon28b358a2016-11-28 13:23:05 -08003 *
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.opencord.cordvtn.impl;
17
Hyunsun Moonbcf49252017-02-21 22:28:41 +090018import com.google.common.base.Strings;
Hyunsun Moon28b358a2016-11-28 13:23:05 -080019import com.google.common.collect.Lists;
Hyunsun Moon0984cbd2016-12-01 17:34:11 -080020import com.google.common.primitives.Bytes;
Hyunsun Moon28b358a2016-11-28 13:23:05 -080021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
Hyunsun Moonbcf49252017-02-21 22:28:41 +090024import org.apache.felix.scr.annotations.Modified;
25import org.apache.felix.scr.annotations.Property;
Hyunsun Moon28b358a2016-11-28 13:23:05 -080026import org.apache.felix.scr.annotations.Reference;
27import org.apache.felix.scr.annotations.ReferenceCardinality;
28import org.onlab.packet.DHCP;
Hyunsun Moon28b358a2016-11-28 13:23:05 -080029import org.onlab.packet.Ethernet;
30import org.onlab.packet.IPv4;
31import org.onlab.packet.Ip4Address;
Hyunsun Moon0984cbd2016-12-01 17:34:11 -080032import org.onlab.packet.IpPrefix;
Hyunsun Moon28b358a2016-11-28 13:23:05 -080033import org.onlab.packet.MacAddress;
34import org.onlab.packet.TpPort;
35import org.onlab.packet.UDP;
Jonathan Hart18031442018-01-24 16:45:12 -080036import org.onlab.packet.dhcp.DhcpOption;
Hyunsun Moonbcf49252017-02-21 22:28:41 +090037import org.onlab.util.Tools;
38import org.onosproject.cfg.ComponentConfigService;
Hyunsun Moon28b358a2016-11-28 13:23:05 -080039import org.onosproject.core.ApplicationId;
40import org.onosproject.core.CoreService;
41import org.onosproject.net.ConnectPoint;
42import org.onosproject.net.Host;
43import org.onosproject.net.HostId;
Hyunsun Moon28b358a2016-11-28 13:23:05 -080044import org.onosproject.net.flow.DefaultTrafficSelector;
45import org.onosproject.net.flow.DefaultTrafficTreatment;
46import org.onosproject.net.flow.TrafficSelector;
47import org.onosproject.net.flow.TrafficTreatment;
48import org.onosproject.net.host.HostService;
49import org.onosproject.net.packet.DefaultOutboundPacket;
50import org.onosproject.net.packet.PacketContext;
51import org.onosproject.net.packet.PacketPriority;
52import org.onosproject.net.packet.PacketProcessor;
53import org.onosproject.net.packet.PacketService;
54import org.opencord.cordvtn.api.Constants;
Hyunsun Moon187bf532017-01-19 10:57:40 +090055import org.opencord.cordvtn.api.core.Instance;
56import org.opencord.cordvtn.api.core.ServiceNetworkService;
57import org.opencord.cordvtn.api.net.NetworkId;
58import org.opencord.cordvtn.api.net.ServiceNetwork;
Hyunsun Moonbcf49252017-02-21 22:28:41 +090059import org.osgi.service.component.ComponentContext;
Hyunsun Moon28b358a2016-11-28 13:23:05 -080060import org.slf4j.Logger;
61
62import java.nio.ByteBuffer;
Hyunsun Moon0984cbd2016-12-01 17:34:11 -080063import java.util.Arrays;
Hyunsun Moonbcf49252017-02-21 22:28:41 +090064import java.util.Dictionary;
Hyunsun Moon28b358a2016-11-28 13:23:05 -080065import java.util.List;
Hyunsun Moon0984cbd2016-12-01 17:34:11 -080066import java.util.Objects;
67import java.util.Set;
68import java.util.stream.Collectors;
Hyunsun Moon28b358a2016-11-28 13:23:05 -080069
Jonathan Hart18031442018-01-24 16:45:12 -080070import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_BroadcastAddress;
71import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_DHCPServerIp;
72import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_DomainServer;
73import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_END;
74import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_LeaseTime;
75import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_MessageType;
76import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_RouterAddress;
77import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_SubnetMask;
Hyunsun Moon28b358a2016-11-28 13:23:05 -080078import static org.onlab.packet.DHCPPacketType.DHCPACK;
79import static org.onlab.packet.DHCPPacketType.DHCPOFFER;
Hyunsun Moonbcf49252017-02-21 22:28:41 +090080import static org.opencord.cordvtn.api.Constants.DEFAULT_GATEWAY_MAC_STR;
Hyunsun Moon187bf532017-01-19 10:57:40 +090081import static org.opencord.cordvtn.api.net.ServiceNetwork.DependencyType.BIDIRECTIONAL;
82import static org.opencord.cordvtn.api.net.ServiceNetwork.NetworkType.MANAGEMENT_HOST;
83import static org.opencord.cordvtn.api.net.ServiceNetwork.NetworkType.MANAGEMENT_LOCAL;
Hyunsun Moon28b358a2016-11-28 13:23:05 -080084import static org.slf4j.LoggerFactory.getLogger;
85
86/**
87 * Handles DHCP requests for the virtual instances.
88 */
89@Component(immediate = true)
90public class CordVtnDhcpProxy {
91
92 protected final Logger log = getLogger(getClass());
93
Hyunsun Moonbcf49252017-02-21 22:28:41 +090094 private static final String DHCP_SERVER_MAC = "dhcpServerMac";
95
Hyunsun Moon28b358a2016-11-28 13:23:05 -080096 private static final byte DHCP_OPTION_MTU = (byte) 26;
Hyunsun Moon0984cbd2016-12-01 17:34:11 -080097 private static final byte DHCP_OPTION_CLASSLESS_STATIC_ROUTE = (byte) 121;
Hyunsun Moonbcf49252017-02-21 22:28:41 +090098
99 private static final Ip4Address DEFAULT_DNS = Ip4Address.valueOf("8.8.8.8");
Angelos Mimidis93fa3722018-04-23 16:37:55 +0200100 private static final Ip4Address IP_BROADCAST = Ip4Address.valueOf("255.255.255.255");
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900101 private static final byte DEFAULT_PACKET_TTL = (byte) 127;
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800102 private static final byte[] DHCP_DATA_LEASE_INFINITE =
103 ByteBuffer.allocate(4).putInt(-1).array();
104 private static final byte[] DHCP_DATA_MTU_DEFAULT =
105 ByteBuffer.allocate(2).putShort((short) 1450).array();
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected CoreService coreService;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900111 protected ComponentConfigService configService;
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected PacketService packetService;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected HostService hostService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon187bf532017-01-19 10:57:40 +0900120 protected ServiceNetworkService snetService;
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800121
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900122 @Property(name = DHCP_SERVER_MAC, value = DEFAULT_GATEWAY_MAC_STR,
123 label = "Fake MAC address for DHCP server interface")
124 private String dhcpServerMac = DEFAULT_GATEWAY_MAC_STR;
125
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800126 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800127
128 private ApplicationId appId;
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800129
130 @Activate
131 protected void activate() {
132 appId = coreService.registerApplication(Constants.CORDVTN_APP_ID);
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900133 configService.registerProperties(getClass());
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800134 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
135 requestPackets();
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900136
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800137 log.info("Started");
138 }
139
140 @Deactivate
141 protected void deactivate() {
142 packetService.removeProcessor(packetProcessor);
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900143 configService.unregisterProperties(getClass(), false);
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800144 cancelPackets();
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900145
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800146 log.info("Stopped");
147 }
148
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900149 @Modified
150 protected void modified(ComponentContext context) {
151 Dictionary<?, ?> properties = context.getProperties();
152 String updatedMac;
153
154 updatedMac = Tools.get(properties, DHCP_SERVER_MAC);
155 if (!Strings.isNullOrEmpty(updatedMac) && !updatedMac.equals(dhcpServerMac)) {
156 dhcpServerMac = updatedMac;
157 }
158
159 log.info("Modified");
160 }
161
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800162 private void requestPackets() {
163 TrafficSelector selector = DefaultTrafficSelector.builder()
164 .matchEthType(Ethernet.TYPE_IPV4)
165 .matchIPProtocol(IPv4.PROTOCOL_UDP)
166 .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
167 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
168 .build();
169 packetService.requestPackets(selector, PacketPriority.CONTROL, appId);
170 }
171
172 private void cancelPackets() {
173 TrafficSelector selector = DefaultTrafficSelector.builder()
174 .matchEthType(Ethernet.TYPE_IPV4)
175 .matchIPProtocol(IPv4.PROTOCOL_UDP)
176 .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
177 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
178 .build();
179 packetService.cancelPackets(selector, PacketPriority.CONTROL, appId);
180 }
181
182 private class InternalPacketProcessor implements PacketProcessor {
183
184 @Override
185 public void process(PacketContext context) {
186 if (context.isHandled()) {
187 return;
188 }
189
190 Ethernet ethPacket = context.inPacket().parsed();
191 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_IPV4) {
192 return;
193 }
Jonathan Hart18031442018-01-24 16:45:12 -0800194
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800195 IPv4 ipv4Packet = (IPv4) ethPacket.getPayload();
196 if (ipv4Packet.getProtocol() != IPv4.PROTOCOL_UDP) {
197 return;
198 }
Jonathan Hart18031442018-01-24 16:45:12 -0800199
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800200 UDP udpPacket = (UDP) ipv4Packet.getPayload();
201 if (udpPacket.getDestinationPort() != UDP.DHCP_SERVER_PORT ||
202 udpPacket.getSourcePort() != UDP.DHCP_CLIENT_PORT) {
203 return;
204 }
205
206 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
207 processDhcp(context, dhcpPacket);
208 }
209
210 private void processDhcp(PacketContext context, DHCP dhcpPacket) {
211 if (dhcpPacket == null) {
212 log.trace("DHCP packet without payload received, do nothing");
213 return;
214 }
215
Jonathan Hart18031442018-01-24 16:45:12 -0800216 DHCP.MsgType inPacketType = dhcpPacket.getPacketType();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800217 if (inPacketType == null || dhcpPacket.getClientHardwareAddress() == null) {
218 log.trace("Malformed DHCP packet received, ignore it");
219 return;
220 }
221
222 MacAddress clientMac = MacAddress.valueOf(dhcpPacket.getClientHardwareAddress());
223 Host reqHost = hostService.getHost(HostId.hostId(clientMac));
224 if (reqHost == null) {
225 log.debug("DHCP packet from unknown host, ignore it");
226 return;
227 }
228
229 Instance reqInstance = Instance.of(reqHost);
230 Ethernet ethPacket = context.inPacket().parsed();
231 switch (inPacketType) {
232 case DHCPDISCOVER:
233 log.trace("DHCP DISCOVER received from {}", reqHost.id());
234 Ethernet discoverReply = buildReply(
235 ethPacket,
236 (byte) DHCPOFFER.getValue(),
237 reqInstance);
238 sendReply(context, discoverReply);
239 log.trace("DHCP OFFER({}) is sent to {}",
240 reqInstance.ipAddress(), reqHost.id());
241 break;
242 case DHCPREQUEST:
243 log.trace("DHCP REQUEST received from {}", reqHost.id());
244 Ethernet requestReply = buildReply(
245 ethPacket,
246 (byte) DHCPACK.getValue(),
247 reqInstance);
248 sendReply(context, requestReply);
249 log.trace("DHCP ACK({}) is sent to {}",
250 reqInstance.ipAddress(), reqHost.id());
251 break;
252 case DHCPRELEASE:
253 log.trace("DHCP RELEASE received from {}", reqHost.id());
254 // do nothing
255 break;
256 default:
Jonathan Hart18031442018-01-24 16:45:12 -0800257 log.warn("Unknown packet type {}", inPacketType);
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800258 break;
259 }
260 }
261
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800262 private Ethernet buildReply(Ethernet ethRequest, byte packetType,
263 Instance reqInstance) {
Hyunsun Moon187bf532017-01-19 10:57:40 +0900264 ServiceNetwork snet = snetService.serviceNetwork(reqInstance.netId());
265 Ip4Address serverIp = snet.serviceIp().getIp4Address();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800266
267 Ethernet ethReply = new Ethernet();
268 ethReply.setSourceMACAddress(dhcpServerMac);
269 ethReply.setDestinationMACAddress(ethRequest.getSourceMAC());
270 ethReply.setEtherType(Ethernet.TYPE_IPV4);
271
272 IPv4 ipv4Request = (IPv4) ethRequest.getPayload();
273 IPv4 ipv4Reply = new IPv4();
274 ipv4Reply.setSourceAddress(serverIp.toInt());
275 ipv4Reply.setDestinationAddress(reqInstance.ipAddress().toInt());
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900276 ipv4Reply.setTtl(DEFAULT_PACKET_TTL);
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800277
278 UDP udpRequest = (UDP) ipv4Request.getPayload();
279 UDP udpReply = new UDP();
280 udpReply.setSourcePort((byte) UDP.DHCP_SERVER_PORT);
281 udpReply.setDestinationPort((byte) UDP.DHCP_CLIENT_PORT);
282
283 DHCP dhcpRequest = (DHCP) udpRequest.getPayload();
284 DHCP dhcpReply = buildDhcpReply(
Hyunsun Moon187bf532017-01-19 10:57:40 +0900285 dhcpRequest, packetType, reqInstance.ipAddress(), snet);
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800286
Angelos Mimidis93fa3722018-04-23 16:37:55 +0200287 // Overwrite the DstIP and DstMac if broadcast flag is set in DHCP header.
288 // This Fix alligns the ONOS-VTN app with the DHCP RFC
289 if ((dhcpRequest.getFlags() & 0x8000) != 0) {
290 ipv4Reply.setDestinationAddress(IP_BROADCAST.toInt());
291 ethReply.setDestinationMACAddress(MacAddress.BROADCAST);
292 }
293 // End of DHCP Fix.
294
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800295 udpReply.setPayload(dhcpReply);
296 ipv4Reply.setPayload(udpReply);
297 ethReply.setPayload(ipv4Reply);
298
299 return ethReply;
300 }
301
302 private void sendReply(PacketContext context, Ethernet ethReply) {
303 if (ethReply == null) {
304 return;
305 }
306 ConnectPoint srcPoint = context.inPacket().receivedFrom();
307 TrafficTreatment treatment = DefaultTrafficTreatment
308 .builder()
309 .setOutput(srcPoint.port())
310 .build();
311
312 packetService.emit(new DefaultOutboundPacket(
313 srcPoint.deviceId(),
314 treatment,
315 ByteBuffer.wrap(ethReply.serialize())));
316 context.block();
317 }
318
319 private DHCP buildDhcpReply(DHCP request, byte msgType, Ip4Address yourIp,
Hyunsun Moon187bf532017-01-19 10:57:40 +0900320 ServiceNetwork snet) {
321 Ip4Address serverIp = snet.serviceIp().getIp4Address();
322 int subnetPrefixLen = snet.subnet().prefixLength();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800323
324 DHCP dhcpReply = new DHCP();
325 dhcpReply.setOpCode(DHCP.OPCODE_REPLY);
326 dhcpReply.setHardwareType(DHCP.HWTYPE_ETHERNET);
327 dhcpReply.setHardwareAddressLength((byte) 6);
328 dhcpReply.setTransactionId(request.getTransactionId());
329 dhcpReply.setFlags(request.getFlags());
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800330 dhcpReply.setServerIPAddress(serverIp.toInt());
Angelos Mimidis93fa3722018-04-23 16:37:55 +0200331 dhcpReply.setYourIPAddress(yourIp.toInt());
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800332 dhcpReply.setClientHardwareAddress(request.getClientHardwareAddress());
333
Jonathan Hart18031442018-01-24 16:45:12 -0800334 List<DhcpOption> options = Lists.newArrayList();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800335 // message type
Jonathan Hart18031442018-01-24 16:45:12 -0800336 DhcpOption option = new DhcpOption();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800337 option.setCode(OptionCode_MessageType.getValue());
338 option.setLength((byte) 1);
339 byte[] optionData = {msgType};
340 option.setData(optionData);
341 options.add(option);
342
343 // server identifier
Jonathan Hart18031442018-01-24 16:45:12 -0800344 option = new DhcpOption();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800345 option.setCode(OptionCode_DHCPServerIp.getValue());
346 option.setLength((byte) 4);
347 option.setData(serverIp.toOctets());
348 options.add(option);
349
350 // lease time
Jonathan Hart18031442018-01-24 16:45:12 -0800351 option = new DhcpOption();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800352 option.setCode(OptionCode_LeaseTime.getValue());
353 option.setLength((byte) 4);
354 option.setData(DHCP_DATA_LEASE_INFINITE);
355 options.add(option);
356
357 // subnet mask
358 Ip4Address subnetMask = Ip4Address.makeMaskPrefix(subnetPrefixLen);
Jonathan Hart18031442018-01-24 16:45:12 -0800359 option = new DhcpOption();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800360 option.setCode(OptionCode_SubnetMask.getValue());
361 option.setLength((byte) 4);
362 option.setData(subnetMask.toOctets());
363 options.add(option);
364
365 // broadcast address
366 Ip4Address broadcast = Ip4Address.makeMaskedAddress(yourIp, subnetPrefixLen);
Jonathan Hart18031442018-01-24 16:45:12 -0800367 option = new DhcpOption();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800368 option.setCode(OptionCode_BroadcastAddress.getValue());
369 option.setLength((byte) 4);
370 option.setData(broadcast.toOctets());
371 options.add(option);
372
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800373 // domain server
Jonathan Hart18031442018-01-24 16:45:12 -0800374 option = new DhcpOption();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800375 option.setCode(OptionCode_DomainServer.getValue());
376 option.setLength((byte) 4);
377 option.setData(DEFAULT_DNS.toOctets());
378 options.add(option);
379
380 // TODO fix MTU value to be configurable
Jonathan Hart18031442018-01-24 16:45:12 -0800381 option = new DhcpOption();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800382 option.setCode(DHCP_OPTION_MTU);
383 option.setLength((byte) 2);
384 option.setData(DHCP_DATA_MTU_DEFAULT);
385 options.add(option);
386
387 // router address
Hyunsun Moon187bf532017-01-19 10:57:40 +0900388 if (snet.type() != MANAGEMENT_LOCAL && snet.type() != MANAGEMENT_HOST) {
Jonathan Hart18031442018-01-24 16:45:12 -0800389 option = new DhcpOption();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800390 option.setCode(OptionCode_RouterAddress.getValue());
391 option.setLength((byte) 4);
392 option.setData(serverIp.toOctets());
393 options.add(option);
394 }
395
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800396 // classless static routes
Hyunsun Moon187bf532017-01-19 10:57:40 +0900397 byte[] data = getClasslessStaticRoutesData(snet);
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800398 if (data.length >= 5) {
Jonathan Hart18031442018-01-24 16:45:12 -0800399 option = new DhcpOption();
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800400 option.setCode(DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
401 option.setLength((byte) data.length);
402 option.setData(data);
403 options.add(option);
404 }
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800405
406 // end option
Jonathan Hart18031442018-01-24 16:45:12 -0800407 option = new DhcpOption();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800408 option.setCode(OptionCode_END.getValue());
409 option.setLength((byte) 1);
410 options.add(option);
411
412 dhcpReply.setOptions(options);
413 return dhcpReply;
414 }
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800415
Hyunsun Moon187bf532017-01-19 10:57:40 +0900416 private byte[] getClasslessStaticRoutesData(ServiceNetwork snet) {
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800417 List<Byte> result = Lists.newArrayList();
Hyunsun Moon187bf532017-01-19 10:57:40 +0900418 List<Byte> router = Bytes.asList(snet.serviceIp().toOctets());
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800419
420 // static routes for the providers
Hyunsun Moon187bf532017-01-19 10:57:40 +0900421 Set<ServiceNetwork> providers = snet.providers().keySet().stream()
422 .map(provider -> snetService.serviceNetwork(provider))
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800423 .filter(Objects::nonNull)
424 .collect(Collectors.toSet());
425
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900426 providers.forEach(provider -> {
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800427 result.add((byte) provider.subnet().prefixLength());
428 result.addAll(getSignificantOctets(provider.subnet()));
429 result.addAll(router);
430 });
431
432 // static routes for the bidirectional subscribers
Hyunsun Moon187bf532017-01-19 10:57:40 +0900433 Set<ServiceNetwork> subscribers = snetService.serviceNetworks().stream()
434 .filter(net -> isBidirectionalProvider(net, snet.id()))
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800435 .collect(Collectors.toSet());
436
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900437 subscribers.forEach(subscriber -> {
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800438 result.add((byte) subscriber.subnet().prefixLength());
439 result.addAll(getSignificantOctets(subscriber.subnet()));
440 result.addAll(router);
441 });
442
443 return Bytes.toArray(result);
444 }
445
Hyunsun Moon187bf532017-01-19 10:57:40 +0900446 private boolean isBidirectionalProvider(ServiceNetwork snet, NetworkId targetNetId) {
447 return snet.providers().entrySet().stream()
448 .filter(p -> Objects.equals(p.getKey(), targetNetId))
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900449 .anyMatch(p -> p.getValue() == BIDIRECTIONAL);
Hyunsun Moon187bf532017-01-19 10:57:40 +0900450 }
451
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800452 private List<Byte> getSignificantOctets(IpPrefix ipPrefix) {
453 int numOfOctets = ipPrefix.prefixLength() / 8;
454 if (ipPrefix.prefixLength() % 8 != 0) {
455 numOfOctets += 1;
456 }
457 byte[] result = Arrays.copyOfRange(ipPrefix.address().toOctets(), 0, numOfOctets);
458 return Bytes.asList(result);
459 }
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800460 }
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800461}
Angelos Mimidis93fa3722018-04-23 16:37:55 +0200462