blob: e63cdcf6bacb0b46edd88c75d4ecd973cda7d8df [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");
100 private static final byte DEFAULT_PACKET_TTL = (byte) 127;
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800101 private static final byte[] DHCP_DATA_LEASE_INFINITE =
102 ByteBuffer.allocate(4).putInt(-1).array();
103 private static final byte[] DHCP_DATA_MTU_DEFAULT =
104 ByteBuffer.allocate(2).putShort((short) 1450).array();
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected CoreService coreService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900110 protected ComponentConfigService configService;
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected PacketService packetService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected HostService hostService;
117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon187bf532017-01-19 10:57:40 +0900119 protected ServiceNetworkService snetService;
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800120
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900121 @Property(name = DHCP_SERVER_MAC, value = DEFAULT_GATEWAY_MAC_STR,
122 label = "Fake MAC address for DHCP server interface")
123 private String dhcpServerMac = DEFAULT_GATEWAY_MAC_STR;
124
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800125 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800126
127 private ApplicationId appId;
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800128
129 @Activate
130 protected void activate() {
131 appId = coreService.registerApplication(Constants.CORDVTN_APP_ID);
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900132 configService.registerProperties(getClass());
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800133 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
134 requestPackets();
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900135
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800136 log.info("Started");
137 }
138
139 @Deactivate
140 protected void deactivate() {
141 packetService.removeProcessor(packetProcessor);
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900142 configService.unregisterProperties(getClass(), false);
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800143 cancelPackets();
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900144
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800145 log.info("Stopped");
146 }
147
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900148 @Modified
149 protected void modified(ComponentContext context) {
150 Dictionary<?, ?> properties = context.getProperties();
151 String updatedMac;
152
153 updatedMac = Tools.get(properties, DHCP_SERVER_MAC);
154 if (!Strings.isNullOrEmpty(updatedMac) && !updatedMac.equals(dhcpServerMac)) {
155 dhcpServerMac = updatedMac;
156 }
157
158 log.info("Modified");
159 }
160
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800161 private void requestPackets() {
162 TrafficSelector selector = DefaultTrafficSelector.builder()
163 .matchEthType(Ethernet.TYPE_IPV4)
164 .matchIPProtocol(IPv4.PROTOCOL_UDP)
165 .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
166 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
167 .build();
168 packetService.requestPackets(selector, PacketPriority.CONTROL, appId);
169 }
170
171 private void cancelPackets() {
172 TrafficSelector selector = DefaultTrafficSelector.builder()
173 .matchEthType(Ethernet.TYPE_IPV4)
174 .matchIPProtocol(IPv4.PROTOCOL_UDP)
175 .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
176 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
177 .build();
178 packetService.cancelPackets(selector, PacketPriority.CONTROL, appId);
179 }
180
181 private class InternalPacketProcessor implements PacketProcessor {
182
183 @Override
184 public void process(PacketContext context) {
185 if (context.isHandled()) {
186 return;
187 }
188
189 Ethernet ethPacket = context.inPacket().parsed();
190 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_IPV4) {
191 return;
192 }
Jonathan Hart18031442018-01-24 16:45:12 -0800193
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800194 IPv4 ipv4Packet = (IPv4) ethPacket.getPayload();
195 if (ipv4Packet.getProtocol() != IPv4.PROTOCOL_UDP) {
196 return;
197 }
Jonathan Hart18031442018-01-24 16:45:12 -0800198
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800199 UDP udpPacket = (UDP) ipv4Packet.getPayload();
200 if (udpPacket.getDestinationPort() != UDP.DHCP_SERVER_PORT ||
201 udpPacket.getSourcePort() != UDP.DHCP_CLIENT_PORT) {
202 return;
203 }
204
205 DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
206 processDhcp(context, dhcpPacket);
207 }
208
209 private void processDhcp(PacketContext context, DHCP dhcpPacket) {
210 if (dhcpPacket == null) {
211 log.trace("DHCP packet without payload received, do nothing");
212 return;
213 }
214
Jonathan Hart18031442018-01-24 16:45:12 -0800215 DHCP.MsgType inPacketType = dhcpPacket.getPacketType();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800216 if (inPacketType == null || dhcpPacket.getClientHardwareAddress() == null) {
217 log.trace("Malformed DHCP packet received, ignore it");
218 return;
219 }
220
221 MacAddress clientMac = MacAddress.valueOf(dhcpPacket.getClientHardwareAddress());
222 Host reqHost = hostService.getHost(HostId.hostId(clientMac));
223 if (reqHost == null) {
224 log.debug("DHCP packet from unknown host, ignore it");
225 return;
226 }
227
228 Instance reqInstance = Instance.of(reqHost);
229 Ethernet ethPacket = context.inPacket().parsed();
230 switch (inPacketType) {
231 case DHCPDISCOVER:
232 log.trace("DHCP DISCOVER received from {}", reqHost.id());
233 Ethernet discoverReply = buildReply(
234 ethPacket,
235 (byte) DHCPOFFER.getValue(),
236 reqInstance);
237 sendReply(context, discoverReply);
238 log.trace("DHCP OFFER({}) is sent to {}",
239 reqInstance.ipAddress(), reqHost.id());
240 break;
241 case DHCPREQUEST:
242 log.trace("DHCP REQUEST received from {}", reqHost.id());
243 Ethernet requestReply = buildReply(
244 ethPacket,
245 (byte) DHCPACK.getValue(),
246 reqInstance);
247 sendReply(context, requestReply);
248 log.trace("DHCP ACK({}) is sent to {}",
249 reqInstance.ipAddress(), reqHost.id());
250 break;
251 case DHCPRELEASE:
252 log.trace("DHCP RELEASE received from {}", reqHost.id());
253 // do nothing
254 break;
255 default:
Jonathan Hart18031442018-01-24 16:45:12 -0800256 log.warn("Unknown packet type {}", inPacketType);
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800257 break;
258 }
259 }
260
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800261 private Ethernet buildReply(Ethernet ethRequest, byte packetType,
262 Instance reqInstance) {
Hyunsun Moon187bf532017-01-19 10:57:40 +0900263 ServiceNetwork snet = snetService.serviceNetwork(reqInstance.netId());
264 Ip4Address serverIp = snet.serviceIp().getIp4Address();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800265
266 Ethernet ethReply = new Ethernet();
267 ethReply.setSourceMACAddress(dhcpServerMac);
268 ethReply.setDestinationMACAddress(ethRequest.getSourceMAC());
269 ethReply.setEtherType(Ethernet.TYPE_IPV4);
270
271 IPv4 ipv4Request = (IPv4) ethRequest.getPayload();
272 IPv4 ipv4Reply = new IPv4();
273 ipv4Reply.setSourceAddress(serverIp.toInt());
274 ipv4Reply.setDestinationAddress(reqInstance.ipAddress().toInt());
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900275 ipv4Reply.setTtl(DEFAULT_PACKET_TTL);
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800276
277 UDP udpRequest = (UDP) ipv4Request.getPayload();
278 UDP udpReply = new UDP();
279 udpReply.setSourcePort((byte) UDP.DHCP_SERVER_PORT);
280 udpReply.setDestinationPort((byte) UDP.DHCP_CLIENT_PORT);
281
282 DHCP dhcpRequest = (DHCP) udpRequest.getPayload();
283 DHCP dhcpReply = buildDhcpReply(
Hyunsun Moon187bf532017-01-19 10:57:40 +0900284 dhcpRequest, packetType, reqInstance.ipAddress(), snet);
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800285
286 udpReply.setPayload(dhcpReply);
287 ipv4Reply.setPayload(udpReply);
288 ethReply.setPayload(ipv4Reply);
289
290 return ethReply;
291 }
292
293 private void sendReply(PacketContext context, Ethernet ethReply) {
294 if (ethReply == null) {
295 return;
296 }
297 ConnectPoint srcPoint = context.inPacket().receivedFrom();
298 TrafficTreatment treatment = DefaultTrafficTreatment
299 .builder()
300 .setOutput(srcPoint.port())
301 .build();
302
303 packetService.emit(new DefaultOutboundPacket(
304 srcPoint.deviceId(),
305 treatment,
306 ByteBuffer.wrap(ethReply.serialize())));
307 context.block();
308 }
309
310 private DHCP buildDhcpReply(DHCP request, byte msgType, Ip4Address yourIp,
Hyunsun Moon187bf532017-01-19 10:57:40 +0900311 ServiceNetwork snet) {
312 Ip4Address serverIp = snet.serviceIp().getIp4Address();
313 int subnetPrefixLen = snet.subnet().prefixLength();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800314
315 DHCP dhcpReply = new DHCP();
316 dhcpReply.setOpCode(DHCP.OPCODE_REPLY);
317 dhcpReply.setHardwareType(DHCP.HWTYPE_ETHERNET);
318 dhcpReply.setHardwareAddressLength((byte) 6);
319 dhcpReply.setTransactionId(request.getTransactionId());
320 dhcpReply.setFlags(request.getFlags());
321 dhcpReply.setYourIPAddress(yourIp.toInt());
322 dhcpReply.setServerIPAddress(serverIp.toInt());
323 dhcpReply.setClientHardwareAddress(request.getClientHardwareAddress());
324
Jonathan Hart18031442018-01-24 16:45:12 -0800325 List<DhcpOption> options = Lists.newArrayList();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800326 // message type
Jonathan Hart18031442018-01-24 16:45:12 -0800327 DhcpOption option = new DhcpOption();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800328 option.setCode(OptionCode_MessageType.getValue());
329 option.setLength((byte) 1);
330 byte[] optionData = {msgType};
331 option.setData(optionData);
332 options.add(option);
333
334 // server identifier
Jonathan Hart18031442018-01-24 16:45:12 -0800335 option = new DhcpOption();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800336 option.setCode(OptionCode_DHCPServerIp.getValue());
337 option.setLength((byte) 4);
338 option.setData(serverIp.toOctets());
339 options.add(option);
340
341 // lease time
Jonathan Hart18031442018-01-24 16:45:12 -0800342 option = new DhcpOption();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800343 option.setCode(OptionCode_LeaseTime.getValue());
344 option.setLength((byte) 4);
345 option.setData(DHCP_DATA_LEASE_INFINITE);
346 options.add(option);
347
348 // subnet mask
349 Ip4Address subnetMask = Ip4Address.makeMaskPrefix(subnetPrefixLen);
Jonathan Hart18031442018-01-24 16:45:12 -0800350 option = new DhcpOption();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800351 option.setCode(OptionCode_SubnetMask.getValue());
352 option.setLength((byte) 4);
353 option.setData(subnetMask.toOctets());
354 options.add(option);
355
356 // broadcast address
357 Ip4Address broadcast = Ip4Address.makeMaskedAddress(yourIp, subnetPrefixLen);
Jonathan Hart18031442018-01-24 16:45:12 -0800358 option = new DhcpOption();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800359 option.setCode(OptionCode_BroadcastAddress.getValue());
360 option.setLength((byte) 4);
361 option.setData(broadcast.toOctets());
362 options.add(option);
363
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800364 // domain server
Jonathan Hart18031442018-01-24 16:45:12 -0800365 option = new DhcpOption();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800366 option.setCode(OptionCode_DomainServer.getValue());
367 option.setLength((byte) 4);
368 option.setData(DEFAULT_DNS.toOctets());
369 options.add(option);
370
371 // TODO fix MTU value to be configurable
Jonathan Hart18031442018-01-24 16:45:12 -0800372 option = new DhcpOption();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800373 option.setCode(DHCP_OPTION_MTU);
374 option.setLength((byte) 2);
375 option.setData(DHCP_DATA_MTU_DEFAULT);
376 options.add(option);
377
378 // router address
Hyunsun Moon187bf532017-01-19 10:57:40 +0900379 if (snet.type() != MANAGEMENT_LOCAL && snet.type() != MANAGEMENT_HOST) {
Jonathan Hart18031442018-01-24 16:45:12 -0800380 option = new DhcpOption();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800381 option.setCode(OptionCode_RouterAddress.getValue());
382 option.setLength((byte) 4);
383 option.setData(serverIp.toOctets());
384 options.add(option);
385 }
386
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800387 // classless static routes
Hyunsun Moon187bf532017-01-19 10:57:40 +0900388 byte[] data = getClasslessStaticRoutesData(snet);
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800389 if (data.length >= 5) {
Jonathan Hart18031442018-01-24 16:45:12 -0800390 option = new DhcpOption();
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800391 option.setCode(DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
392 option.setLength((byte) data.length);
393 option.setData(data);
394 options.add(option);
395 }
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800396
397 // end option
Jonathan Hart18031442018-01-24 16:45:12 -0800398 option = new DhcpOption();
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800399 option.setCode(OptionCode_END.getValue());
400 option.setLength((byte) 1);
401 options.add(option);
402
403 dhcpReply.setOptions(options);
404 return dhcpReply;
405 }
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800406
Hyunsun Moon187bf532017-01-19 10:57:40 +0900407 private byte[] getClasslessStaticRoutesData(ServiceNetwork snet) {
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800408 List<Byte> result = Lists.newArrayList();
Hyunsun Moon187bf532017-01-19 10:57:40 +0900409 List<Byte> router = Bytes.asList(snet.serviceIp().toOctets());
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800410
411 // static routes for the providers
Hyunsun Moon187bf532017-01-19 10:57:40 +0900412 Set<ServiceNetwork> providers = snet.providers().keySet().stream()
413 .map(provider -> snetService.serviceNetwork(provider))
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800414 .filter(Objects::nonNull)
415 .collect(Collectors.toSet());
416
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900417 providers.forEach(provider -> {
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800418 result.add((byte) provider.subnet().prefixLength());
419 result.addAll(getSignificantOctets(provider.subnet()));
420 result.addAll(router);
421 });
422
423 // static routes for the bidirectional subscribers
Hyunsun Moon187bf532017-01-19 10:57:40 +0900424 Set<ServiceNetwork> subscribers = snetService.serviceNetworks().stream()
425 .filter(net -> isBidirectionalProvider(net, snet.id()))
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800426 .collect(Collectors.toSet());
427
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900428 subscribers.forEach(subscriber -> {
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800429 result.add((byte) subscriber.subnet().prefixLength());
430 result.addAll(getSignificantOctets(subscriber.subnet()));
431 result.addAll(router);
432 });
433
434 return Bytes.toArray(result);
435 }
436
Hyunsun Moon187bf532017-01-19 10:57:40 +0900437 private boolean isBidirectionalProvider(ServiceNetwork snet, NetworkId targetNetId) {
438 return snet.providers().entrySet().stream()
439 .filter(p -> Objects.equals(p.getKey(), targetNetId))
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900440 .anyMatch(p -> p.getValue() == BIDIRECTIONAL);
Hyunsun Moon187bf532017-01-19 10:57:40 +0900441 }
442
Hyunsun Moon0984cbd2016-12-01 17:34:11 -0800443 private List<Byte> getSignificantOctets(IpPrefix ipPrefix) {
444 int numOfOctets = ipPrefix.prefixLength() / 8;
445 if (ipPrefix.prefixLength() % 8 != 0) {
446 numOfOctets += 1;
447 }
448 byte[] result = Arrays.copyOfRange(ipPrefix.address().toOctets(), 0, numOfOctets);
449 return Bytes.asList(result);
450 }
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800451 }
Hyunsun Moon28b358a2016-11-28 13:23:05 -0800452}