1ccf05d47030ba875d9e91b947d14cca7fa72207
[lispflowmapping.git] / integrationtest / src / test / java / org / opendaylight / lispflowmapping / integrationtest / MappingServiceIntegrationTestUtil.java
1 /*
2  * Copyright (c) 2017 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.lispflowmapping.integrationtest;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.fail;
13
14 import java.net.DatagramPacket;
15 import java.net.DatagramSocket;
16 import java.net.InetAddress;
17 import java.net.InetSocketAddress;
18 import java.net.SocketException;
19 import java.net.SocketTimeoutException;
20 import java.net.UnknownHostException;
21 import java.nio.ByteBuffer;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.List;
27 import org.opendaylight.lispflowmapping.interfaces.lisp.IFlowMapping;
28 import org.opendaylight.lispflowmapping.interfaces.mappingservice.IMappingService;
29 import org.opendaylight.lispflowmapping.lisp.serializer.MapNotifySerializer;
30 import org.opendaylight.lispflowmapping.lisp.serializer.MapReplySerializer;
31 import org.opendaylight.lispflowmapping.lisp.serializer.MapRequestSerializer;
32 import org.opendaylight.lispflowmapping.lisp.type.LispMessage;
33 import org.opendaylight.lispflowmapping.lisp.util.ByteUtil;
34 import org.opendaylight.lispflowmapping.lisp.util.LispAddressStringifier;
35 import org.opendaylight.lispflowmapping.lisp.util.LispAddressUtil;
36 import org.opendaylight.lispflowmapping.lisp.util.MaskUtil;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.Address;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.Ipv4BinaryAfi;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.Ipv6BinaryAfi;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv4Binary;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv4BinaryBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv4PrefixBinary;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv6Binary;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv6BinaryBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv6PrefixBinary;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.MapNotify;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.MapReply;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.MapRequest;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.MessageType;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.SiteId;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.XtrId;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.Eid;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.EidBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.list.EidItem;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.list.EidItemBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.locatorrecords.LocatorRecordBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.locatorrecords.LocatorRecordKey;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping._record.container.MappingRecord;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping._record.container.MappingRecordBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping._record.list.MappingRecordItemBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping._record.list.MappingRecordItemKey;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapregistermessage.MapRegisterBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.maprequest.ItrRloc;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.maprequest.ItrRlocBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.maprequest.ItrRlocKey;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.maprequest.SourceEidBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.maprequestnotification.MapRequestBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.rloc.container.Rloc;
69 import org.opendaylight.yangtools.yang.common.Uint8;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
72
73 final class MappingServiceIntegrationTestUtil {
74     private static final Logger LOG = LoggerFactory.getLogger(MappingServiceIntegrationTestUtil.class);
75
76     // Socket related method constants
77     static final String SEND_ADDRESS = "127.0.0.1";
78     static final String RECEIVE_ADDRESS = "127.0.0.2";
79     static final int NUM_OF_ATTEMPTS_TO_CREATE_SOCKET = 2;
80     static final int DEFAULT_SOCKET_TIMEOUT = 6000;
81     static final int SHORT_SOCKET_TIMEOUT = 250;
82
83     // Packet creation method constants
84     static final String DEFAULT_IPV4_EID_STRING = "192.0.2.1";
85     static final Eid DEFAULT_IPV4_EID = LispAddressUtil.asIpv4Eid(DEFAULT_IPV4_EID_STRING);
86     static final String DEFAULT_IPV4_EID_PREFIX_STRING = "192.0.2.1/32";
87     static final Eid DEFAULT_IPV4_EID_PREFIX = LispAddressUtil.asIpv4PrefixBinaryEid(DEFAULT_IPV4_EID_PREFIX_STRING);
88     static final String DEFAULT_IPV4_RLOC_STRING = "172.16.0.1";
89     static final Rloc DEFAULT_IPV4_RLOC = LispAddressUtil.asIpv4Rloc(DEFAULT_IPV4_RLOC_STRING);
90     static final Rloc DEFAULT_IPV4_ITR_RLOC = LispAddressUtil.asIpv4Rloc(RECEIVE_ADDRESS);
91     static final byte[] DEFAULT_SITE_ID_BYTES = new byte[]{0, 1, 2, 3, 4, 5, 6, 7};
92     static final SiteId DEFAULT_SITE_ID = new SiteId(DEFAULT_SITE_ID_BYTES);
93     static final byte[] DEFAULT_XTR_ID_BYTES = new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
94     static final XtrId DEFAULT_XTR_ID = new XtrId(DEFAULT_XTR_ID_BYTES);
95
96     // Utility class, should not be instantiated
97     private MappingServiceIntegrationTestUtil() {
98     }
99
100     /*
101      *   SOCKET RELATED METHODS
102      */
103
104     /**
105      * Create and return a UDP socket listening on the given port.
106      *
107      * @param port listening port
108      * @return the created socket
109      */
110     static DatagramSocket initSocket(int port) {
111         for (int i=0; i < NUM_OF_ATTEMPTS_TO_CREATE_SOCKET; i++) {
112             try {
113                 LOG.debug("Binding socket on {}:{}", RECEIVE_ADDRESS, port);
114                 return new DatagramSocket(new InetSocketAddress(RECEIVE_ADDRESS, port));
115             } catch (SocketException e) {
116                 LOG.error("Can't initialize socket for {}:{}", RECEIVE_ADDRESS, port, e);
117             }
118         }
119         fail();
120         return null;
121     }
122
123     /**
124      * Set the destination address and port of a UDP packet
125      * @param packet the packet to be set up
126      * @param port destination port
127      * @throws UnknownHostException when SEND_ADDRESS cannot be converted to InetAddress
128      */
129     static void initPacketAddress(DatagramPacket packet, int port) throws UnknownHostException {
130         packet.setAddress(InetAddress.getByName(SEND_ADDRESS));
131         packet.setPort(port);
132     }
133
134     /**
135      * Send a packet.
136      * @param datagramSocket use this socket for sending the packet
137      * @param bytesToSend the packet contents
138      * @param port destination port
139      */
140     static void sendPacket(DatagramSocket datagramSocket, byte[] bytesToSend, int port) {
141         try {
142             DatagramPacket packet = new DatagramPacket(bytesToSend, bytesToSend.length);
143             initPacketAddress(packet, port);
144             LOG.trace("Sending packet to {}:{}", packet.getAddress(), port);
145             datagramSocket.send(packet);
146         } catch (Throwable t) {
147             fail();
148         }
149     }
150
151     /**
152      * Receive a packet on a UDP socket with a set timeout and return it.
153      *
154      * @param datagramSocket the listening socket where we expect the packet
155      * @param timeout timeout to wait for the packet to be received in milliseconds
156      * @return the packet
157      * @throws SocketTimeoutException when timout expires without receiving a packet on the socket
158      */
159     static ByteBuffer receivePacket(DatagramSocket datagramSocket, int timeout) throws SocketTimeoutException {
160         try {
161             byte[] buffer = new byte[4096];
162             DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length);
163             LOG.trace("Waiting for packet from socket...");
164             datagramSocket.setSoTimeout(timeout);
165             datagramSocket.receive(receivePacket);
166             LOG.trace("Received packet from socket!");
167             return ByteBuffer.wrap(receivePacket.getData());
168         } catch (SocketTimeoutException ste) {
169             throw ste;
170         } catch (Throwable t) {
171             fail();
172             return null;
173         }
174     }
175
176     /**
177      * Receive a packet on a UDP socket with a set timeout and return it.
178      *
179      * @param datagramSocket the listening socket where we expect the packet
180      * @return the packet
181      * @throws SocketTimeoutException when timout expires without receiving a packet on the socket
182      */
183     static ByteBuffer receivePacket(DatagramSocket datagramSocket) throws SocketTimeoutException {
184         return receivePacket(datagramSocket, DEFAULT_SOCKET_TIMEOUT);
185     }
186
187     /**
188      * Read packets on a UDP socket with a set timeout until the given type is received and return it.
189      *
190      * @param datagramSocket the listening socket where we expect the packet
191      * @param timeout timeout to wait for the packet to be received in milliseconds
192      * @param type the expected packet type
193      * @return the packet
194      * @throws SocketTimeoutException when timout expires without receiving a packet on the socket
195      */
196     static ByteBuffer receiveSpecificPacketType(DatagramSocket datagramSocket, int timeout, MessageType type)
197             throws SocketTimeoutException {
198         while (true) {
199             ByteBuffer packet = receivePacket(datagramSocket, timeout);
200             if (checkType(packet, type)) {
201                 return packet;
202             }
203         }
204     }
205
206     /**
207      * Read packets on a UDP socket with a set timeout until a Map-Request is received and return it.
208      *
209      * @param datagramSocket the listening socket where we expect the packet
210      * @return the Map-Request
211      * @throws SocketTimeoutException
212      */
213     static MapRequest receiveMapRequest(DatagramSocket datagramSocket, int timeout) throws SocketTimeoutException {
214         ByteBuffer packet = receiveSpecificPacketType(datagramSocket, timeout, MessageType.MapRequest);
215         return MapRequestSerializer.getInstance().deserialize(packet, null);
216     }
217
218     /**
219      * Read packets on a UDP socket with a set timeout until a Map-Reply is received and return it.
220      *
221      * @param datagramSocket the listening socket where we expect the packet
222      * @return the Map-Reply
223      * @throws SocketTimeoutException
224      */
225     static MapReply receiveMapReply(DatagramSocket datagramSocket, int timeout) throws SocketTimeoutException {
226         ByteBuffer packet = receiveSpecificPacketType(datagramSocket, timeout, MessageType.MapReply);
227         return MapReplySerializer.getInstance().deserialize(packet);
228     }
229
230     /**
231      * Read packets on a UDP socket with a set timeout until a Map-Notify is received and return it.
232      *
233      * @param datagramSocket the listening socket where we expect the packet
234      * @return the Map-Notify
235      * @throws SocketTimeoutException
236      */
237     static MapNotify receiveMapNotify(DatagramSocket datagramSocket, int timeout) throws SocketTimeoutException {
238         ByteBuffer packet = receiveSpecificPacketType(datagramSocket, timeout, MessageType.MapNotify);
239         return MapNotifySerializer.getInstance().deserialize(packet);
240     }
241
242     /**
243      * Check if a buffer assumed to be a LISP control packet is of the given type.
244      *
245      * @param packet buffer containing the packet data
246      * @param type LISP control packet type
247      * @return true if the packet is of the given type
248      */
249     static boolean checkType(ByteBuffer packet, MessageType type) {
250         final int receivedType = ByteUtil.getUnsignedByte(packet, LispMessage.Pos.TYPE) >> 4;
251         MessageType messageType = MessageType.forValue(receivedType);
252         LOG.trace("Packet type: {}", messageType);
253         return messageType == type;
254     }
255
256     /**
257      * Receive all outstanding packets on the socket so we can start clean.
258      *
259      * @param datagramSocket the listening socket which we want to drain
260      */
261     static void drainSocket(DatagramSocket datagramSocket) {
262         while (true) {
263             try {
264                 receivePacket(datagramSocket, SHORT_SOCKET_TIMEOUT);
265             } catch (SocketTimeoutException ste) {
266                 return;
267             }
268         }
269     }
270
271     /**
272      * Try to receive a packet on the socket, and expect that it will time out. Otherwise fail.
273      *
274      * @param datagramSocket the listening socket where we don't expect the packet
275      */
276     static void assertNoMorePackets(DatagramSocket datagramSocket) {
277         try {
278             receivePacket(datagramSocket, SHORT_SOCKET_TIMEOUT);
279             fail("Packet received, when none expected!");
280         } catch (SocketTimeoutException ste) {
281             LOG.debug("No more packets, just as expected, great!");
282         }
283     }
284
285     /**
286      * Try to receive a specific packet type on the socket, and expect that it will time out. Otherwise fail.
287      *
288      * @param datagramSocket the listening socket where we don't expect the packet
289      * @param type the non-expected packet type
290      */
291     static void assertNoMoreSpecificTypePackets(DatagramSocket datagramSocket, MessageType type) {
292         try {
293             receiveSpecificPacketType(datagramSocket, SHORT_SOCKET_TIMEOUT, type);
294             fail(type + " packet received, when none expected!");
295         } catch (SocketTimeoutException ste) {
296             LOG.debug("No more {} packets, just as expected, great!", type);
297         }
298     }
299
300     /**
301      * Try to receive an SMR on the socket, and expect that it will time out. Otherwise fail.
302      *
303      * @param datagramSocket the listening socket where we don't expect the packet
304      */
305     static void assertNoMoreSMRs(DatagramSocket datagramSocket, IMappingService mappingService) {
306         try {
307             MapRequest mr = receiveMapRequest(datagramSocket, SHORT_SOCKET_TIMEOUT);
308             if (mr.getSmr()) {
309                 if (mappingService != null) {
310                     printMapCacheState(mappingService);
311                 }
312                 fail("Unexpected SMR received for " + LispAddressStringifier.getString(mr.getSourceEid().getEid()));
313             } else {
314                 fail("Unexpected Map-Request (non-SMR) received");
315             }
316         } catch (SocketTimeoutException ste) {
317             LOG.debug("No more SMR packets, just as expected, great!");
318         }
319     }
320
321     /**
322      * Read packets from the given socket until a Map-Request is found. Assert that the request is an SMR, and the
323      * Source EID field contains the given IPv4 EID. Note that the source EID does not have a mask length. If a
324      * reference to the LISP Mapping Service is passed, send an SMR-invoked Map-Request, to simulate what would happen
325      * in the real world. If a reference to the Mapping Service is passed, the internal state of the map caches and
326      * subscribers is logged.
327      *
328      * @param socket the receive socket
329      * @param lms reference to the LISP Mapping Service, if present, an SMR-invoked Map-Request is sent in reply to the
330      *            SMR
331      * @param ms reference to the Mapping System, if present, the internal state of map-caches and subscribers is logged
332      * @param vni the VNI for the expected EID
333      * @param eids the expected EIDs, as an IPv4 string, without mask length
334      */
335     static void checkSmr(DatagramSocket socket, IFlowMapping lms, IMappingService ms, long vni, String ... eids) {
336         LOG.debug("checkSmr: expecting {} SMRs: {}", eids.length, eids);
337         List<MapRequest> mapRequests = receiveExpectedSmrs(socket, eids.length);
338
339         assertNoMoreSMRs(socket, ms);
340
341         HashMap<Eid, Integer> eidSet = prepareExpectedEids(vni, eids);
342         for(MapRequest mapRequest : mapRequests) {
343             LOG.trace("Solicit Map-Request: {}", mapRequest);
344             Eid originalSourceEid = mapRequest.getEidItem().get(0).getEid();
345             assertEquals(DEFAULT_IPV4_EID_PREFIX, originalSourceEid);
346             Eid smrEid = mapRequest.getSourceEid().getEid();
347             int counterDecremented = eidSet.get(smrEid) - 1;
348             if (counterDecremented < 0) {
349                 fail("checkSmr: SMR contains EID " + LispAddressStringifier.getString(smrEid) +
350                         ", which is not in the list of expected EIDs: " + eidSet);
351             } else {
352                 LOG.debug("checkSmr: successfully received expected SMR for {}",
353                         LispAddressStringifier.getString(smrEid));
354             }
355
356             if (lms != null) {
357                 sendSMRInvokedMapRequestMessage(mapRequest, lms);
358                 // TODO Capture the reply to the SMR-invoked Map-Request and assert on the expected result
359             }
360         }
361
362         if (ms != null) {
363             printMapCacheState(ms);
364         }
365     }
366
367     /**
368      * Receive a given number of SMR packets on the given UDP socket or fail.
369      *
370      * @param datagramSocket the receive socket
371      * @param count the number of expected SMRs
372      * @return the list of received SMRs
373      */
374     static List<MapRequest> receiveExpectedSmrs(DatagramSocket datagramSocket, int count) {
375         LOG.debug("Expecting {} SMRs ", count);
376         List<MapRequest> mapRequests = new ArrayList<>();
377         int i = 0;
378         try {
379             while (i < count) {
380                 MapRequest mapRequest = receiveMapRequest(datagramSocket, DEFAULT_SOCKET_TIMEOUT);
381                 LOG.trace("Solicit Map-Request: {}", mapRequest);
382                 assertEquals(true, mapRequest.getSmr());
383                 if (mapRequest.getEidItem().isEmpty()) {
384                     fail("Empty SMR received (no EID record)!");
385                 }
386                 mapRequests.add(mapRequest);
387                 i++;
388             }
389         } catch (SocketTimeoutException ste) {
390             fail("Expected " + count + " SMRs, received " + i);
391         }
392         return mapRequests;
393     }
394
395     /**
396      * Create a Set of Eid objects in a given VNI from a variable length argument of EIDs as String
397      *
398      * @param vni the VNI of the EIDs
399      * @param eids the list of EIDs, as an IPv4 string, without mask length
400      * @return a HasMap of Eid objects and the number of their occurrences
401      */
402     static HashMap<Eid, Integer> prepareExpectedEids(long vni, String ... eids) {
403         final HashMap<Eid, Integer> eidSet = new HashMap<>();
404         for (String eidString : eids) {
405             Eid eid = LispAddressUtil.asIpv4Eid(eidString, vni);
406             eidSet.putIfAbsent(eid, 0);
407             int counterIncremented = eidSet.get(eid) + 1;
408             eidSet.put(eid, counterIncremented);
409         }
410         return eidSet;
411     }
412
413     /**
414      * This method expects a SMR Map-Request as input, which it will turn into a SMR-invoked Map-Request and use the
415      * LISP mapping service to send it
416      *
417      * @param mapRequest the SMR Map-Request
418      * @param lms referencs to the LISP Mapping Service
419      */
420     static void sendSMRInvokedMapRequestMessage(MapRequest mapRequest, IFlowMapping lms) {
421         Eid eid = addMaximumPrefixIfNecessary(mapRequest.getSourceEid().getEid());
422         final EidItemBuilder eidItemBuilder = new EidItemBuilder();
423         eidItemBuilder.setEid(eid);
424         eidItemBuilder.setEidItemId(LispAddressStringifier.getString(eid));
425         final List<EidItem> eidItem = Collections.singletonList(eidItemBuilder.build());
426
427         final MapRequestBuilder mapRequestBuilder = new MapRequestBuilder(mapRequest);
428         mapRequestBuilder.setSmr(false);
429         mapRequestBuilder.setSmrInvoked(true);
430         mapRequestBuilder.setItrRloc(getDefaultItrRlocList(LispAddressUtil.asIpv4Rloc(RECEIVE_ADDRESS)));
431         mapRequestBuilder.setEidItem(eidItem);
432         for (EidItem srcEid : mapRequest.getEidItem()) {
433             mapRequestBuilder.setSourceEid(new SourceEidBuilder().setEid(
434                     removePrefixIfNecessary(srcEid.getEid())).build());
435             LOG.debug("Sending SMR-invoked Map-Request for EID {}, Source EID {}",
436                     LispAddressStringifier.getString(eid),
437                     LispAddressStringifier.getString(srcEid.getEid()));
438             lms.handleMapRequest(mapRequestBuilder.build());
439         }
440     }
441
442     /**
443      * Since the Source EID field from a Map-Request packet does not have a prefix length field, IPv4 and IPv6 addresses
444      * are serialized into Ipv4Binary and Ipv6Binary objects. However, when we want to use the addresses in a
445      * SMR-invoked Map-Request, we need to use an Ipv4PrefixBinary or Ipv6PrefixBinary object respectively, since that's
446      * what the EID item field would be deserialized into.
447      */
448     static Eid addMaximumPrefixIfNecessary(Eid eid) {
449         Address address = eid.getAddress();
450         if (address instanceof Ipv4Binary) {
451             return LispAddressUtil.asIpv4PrefixBinaryEid(
452                     eid, ((Ipv4Binary) address).getIpv4Binary().getValue(), MaskUtil.IPV4_MAX_MASK);
453         } else if (address instanceof Ipv6Binary) {
454             return LispAddressUtil.asIpv6PrefixBinaryEid(
455                     eid, ((Ipv6Binary) address).getIpv6Binary().getValue(), MaskUtil.IPV6_MAX_MASK);
456         }
457         return eid;
458     }
459
460     static Eid removePrefixIfNecessary(Eid eid) {
461         EidBuilder eb = new EidBuilder(eid);
462         Address address = eid.getAddress();
463         if (address instanceof Ipv4PrefixBinary) {
464             Ipv4Binary convertedEid = new Ipv4BinaryBuilder().setIpv4Binary(((Ipv4PrefixBinary) address)
465                     .getIpv4AddressBinary()).build();
466             return eb.setAddress(convertedEid).setAddressType(Ipv4BinaryAfi.class).build();
467         } else if (address instanceof Ipv6PrefixBinary) {
468             Ipv6Binary convertedEid = new Ipv6BinaryBuilder().setIpv6Binary(((Ipv6PrefixBinary) address)
469                     .getIpv6AddressBinary()).build();
470             return eb.setAddress(convertedEid).setAddressType(Ipv6BinaryAfi.class).build();
471         }
472         return eid;
473     }
474
475     /*
476      * PACKETS CREATION METHODS
477      *
478      * In general we return "Builders" so that the caller can customize the fields, but that means it also needs to
479      * call .build() on the received objects.
480      */
481
482     /* Map-Request */
483
484     /**
485      * Create a default MapRequestBuilder object.
486      *
487      * @param eid the requested EID
488      * @return the MapRequestBuilder object
489      */
490     static MapRequestBuilder getDefaultMapRequestBuilder(Eid eid) {
491         MapRequestBuilder mrBuilder = new MapRequestBuilder()
492                 .setAuthoritative(false)
493                 .setEidItem(new ArrayList<>())
494                 .setItrRloc(new ArrayList<>())
495                 .setMapDataPresent(true)
496                 .setNonce((long) 4)
497                 .setPitr(false)
498                 .setProbe(false)
499                 .setSmr(false)
500                 .setSmrInvoked(false)
501                 .setSourceEid(new SourceEidBuilder().setEid(DEFAULT_IPV4_EID).build())
502                 .setItrRloc(getDefaultItrRlocList(DEFAULT_IPV4_ITR_RLOC));
503
504         mrBuilder.getEidItem()
505                 .add(new EidItemBuilder().setEidItemId(LispAddressStringifier.getString(eid)).setEid(eid).build());
506
507         return mrBuilder;
508     }
509
510     /**
511      * Create a default ItrRloc List.
512      *
513      * @param rloc the single Rloc to be added to the list
514      * @return the ItrRloc List object
515      */
516     static List<ItrRloc> getDefaultItrRlocList(Rloc rloc) {
517         if (rloc == null) {
518             rloc = DEFAULT_IPV4_ITR_RLOC;
519         }
520
521         final List<ItrRloc> itrRlocList = new ArrayList<>();
522         final ItrRloc itrRloc = new ItrRlocBuilder()
523                 .withKey(new ItrRlocKey(LispAddressStringifier.getString(rloc)))
524                 .setItrRlocId(LispAddressStringifier.getString(rloc))
525                 .setRloc(rloc).build();
526         itrRlocList.add(itrRloc);
527
528         return itrRlocList;
529     }
530
531     /* Map-Register */
532
533     /**
534      * Create a default MapRegisterBuilder object with a non-empty default LocatorRecord.
535      *
536      * @param eid EID for the single mapping record, if null, a default will be added
537      * @return the MapRegisterBuilder object
538      */
539     static MapRegisterBuilder getDefaultMapRegisterBuilder(Eid eid) {
540         MapRegisterBuilder mapRegisterBuilder = getDefaultMapRegisterBuilder(eid, null);
541         mapRegisterBuilder.setMappingRecordItem(new ArrayList<>());
542         mapRegisterBuilder.getMappingRecordItem().add(getDefaultMappingRecordItemBuilder(eid,
543                 DEFAULT_IPV4_RLOC).build());
544
545         return mapRegisterBuilder;
546     }
547
548     /**
549      * Create a default MapRegisterBuilder object.
550      *
551      * @param eid EID for the single mapping record, if null, a default will be added
552      * @param rloc RLOC for the single mapping record, if null, no locator record will be added
553      * @return the MapRegisterBuilder object
554      */
555     static MapRegisterBuilder getDefaultMapRegisterBuilder(Eid eid, Rloc rloc) {
556         final MapRegisterBuilder mapRegisterBuilder = new MapRegisterBuilder()
557                 .setProxyMapReply(true)
558                 .setWantMapNotify(true)
559                 .setKeyId((short) 0)
560                 .setMappingRecordItem(new ArrayList<>())
561                 .setMergeEnabled(true)
562                 .setNonce(8L)
563                 .setSiteId(DEFAULT_SITE_ID)
564                 .setXtrId(DEFAULT_XTR_ID)
565                 .setXtrSiteIdPresent(true);
566         mapRegisterBuilder.getMappingRecordItem().add(getDefaultMappingRecordItemBuilder(eid, rloc).build());
567
568         return mapRegisterBuilder;
569     }
570
571     /**
572      * Create a default MappingRecordItemBuilder object.
573      *
574      * @param eid EID for the mapping record, if null, a default will be added
575      * @param rloc RLOC for the mapping record, if null, no locator record will be added
576      * @return the MappingRecordItemBuilder object
577      */
578     static MappingRecordItemBuilder getDefaultMappingRecordItemBuilder(Eid eid, Rloc rloc) {
579         return new MappingRecordItemBuilder()
580                 .withKey(new MappingRecordItemKey(LispAddressStringifier.getString(eid)))
581                 .setMappingRecord(getDefaultMappingRecordBuilder(eid, rloc).build());
582     }
583
584     /**
585      * Create a default MappingRecordBuilder object with a single default locator record.
586      *
587      * @param eid EID for the mapping record, if null, a default will be added
588      * @return the MappingRecordBuilder object
589      */
590     static MappingRecordBuilder getDefaultMappingRecordBuilder(Eid eid) {
591         return getDefaultMappingRecordBuilder(eid, DEFAULT_IPV4_RLOC);
592     }
593
594     /**
595      * Create a default MappingRecordBuilder object.
596      *
597      * @param eid EID for the mapping record, if null, a default will be added
598      * @param rloc RLOC for the mapping record, if null, no locator record will be added
599      * @return the MappingRecordBuilder object
600      */
601     static MappingRecordBuilder getDefaultMappingRecordBuilder(Eid eid, Rloc rloc) {
602         return getDefaultMappingRecordBuilder(eid, Arrays.asList(rloc));
603     }
604
605     /**
606      * Create a default MappingRecordBuilder object.
607      *
608      * @param eid EID for the mapping record, if null, a default will be added
609      * @param rlocs RLOCs for the mapping record, if null, no locator record will be added
610      * @return the MappingRecordBuilder object
611      */
612     static MappingRecordBuilder getDefaultMappingRecordBuilder(Eid eid, List<Rloc> rlocs) {
613         if (eid == null) {
614             eid = DEFAULT_IPV4_EID_PREFIX;
615             LOG.warn("getDefaultMappingRecordBuilder(): null EID received, using the default {}",
616                     DEFAULT_IPV4_EID_STRING);
617         }
618
619         MappingRecordBuilder mrb = new MappingRecordBuilder()
620                 .setEid(eid)
621                 .setAction(MappingRecord.Action.NoAction)
622                 .setAuthoritative(false)
623                 .setLocatorRecord(new ArrayList<>())
624                 .setMapVersion((short) 0)
625                 .setRecordTtl(60)
626                 .setSiteId(DEFAULT_SITE_ID)
627                 .setXtrId(DEFAULT_XTR_ID)
628                 .setTimestamp(System.currentTimeMillis());
629
630         // We want to allow for empty locator records, so we only add one if rloc is not null
631         if (rlocs != null) {
632             for (Rloc rloc : rlocs) {
633                 mrb.getLocatorRecord().add(getDefaultLocatorBuilder(rloc).build());
634             }
635         }
636
637         return mrb;
638     }
639
640     /**
641      * Create a default LocatorRecordBuilder object.
642      *
643      * @param rloc RLOC for the mapping record, if null, a default will be added
644      * @return the LocatorRecordBuilder object
645      */
646     static LocatorRecordBuilder getDefaultLocatorBuilder(Rloc rloc) {
647         if (rloc == null) {
648             rloc = DEFAULT_IPV4_RLOC;
649             LOG.warn("getDefaultLocatorBuilder(): null RLOC received, using the default {}", DEFAULT_IPV4_RLOC_STRING);
650         }
651
652         return new LocatorRecordBuilder()
653                 .setLocalLocator(true)
654                 .setMulticastPriority(Uint8.valueOf(255))
655                 .setMulticastWeight(Uint8.valueOf(0))
656                 .setPriority(Uint8.valueOf(1))
657                 .setRlocProbed(false)
658                 .setRouted(true)
659                 .setWeight(Uint8.valueOf(1))
660                 .withKey(new LocatorRecordKey(LispAddressStringifier.getString(rloc)))
661                 .setRloc(rloc);
662     }
663
664     /*
665      * MISCELLANEOUS METHODS
666      */
667
668     /**
669      * Log the current state of the map caches maintained internally by the mapping service in the DAO structures,
670      * including subscribers
671      *
672      * @param ms reference to the Mapping Service
673      */
674     static void printMapCacheState(IMappingService ms) {
675         LOG.debug("Map-cache state:\n{}", ms.prettyPrintMappings());
676         LOG.trace("Detailed map-cache state:\n{}", ms.printMappings());
677     }
678 }