449f9f9a587c68a655a01390fae47752c9aeeea0
[lispflowmapping.git] / mappingservice / lisp-proto / src / main / java / org / opendaylight / lispflowmapping / lisp / serializer / MapRequestSerializer.java
1 /*
2  * Copyright (c) 2014 Contextream, 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 package org.opendaylight.lispflowmapping.lisp.serializer;
9
10 import java.net.InetAddress;
11 import java.nio.ByteBuffer;
12 import java.util.ArrayList;
13 import org.apache.commons.lang3.BooleanUtils;
14 import org.opendaylight.lispflowmapping.lisp.serializer.address.LispAddressSerializer;
15 import org.opendaylight.lispflowmapping.lisp.serializer.address.LispAddressSerializerContext;
16 import org.opendaylight.lispflowmapping.lisp.serializer.exception.LispSerializationException;
17 import org.opendaylight.lispflowmapping.lisp.util.ByteUtil;
18 import org.opendaylight.lispflowmapping.lisp.util.LispAddressUtil;
19 import org.opendaylight.lispflowmapping.lisp.util.MaskUtil;
20 import org.opendaylight.lispflowmapping.lisp.util.NumberUtil;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.MapRequest;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.MessageType;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.list.EidItem;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.list.EidItemBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.maprequest.ItrRloc;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.maprequest.ItrRlocBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.maprequest.SourceEidBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.maprequestnotification.MapRequestBuilder;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 /**
33  * This class deals with deserializing map request from udp to the java object.
34  */
35 public final class MapRequestSerializer {
36
37     private static final MapRequestSerializer INSTANCE = new MapRequestSerializer();
38     protected static final Logger LOG = LoggerFactory.getLogger(MapRequestSerializer.class);
39
40     // Private constructor prevents instantiation from other classes
41     private MapRequestSerializer() {
42     }
43
44     public static MapRequestSerializer getInstance() {
45         return INSTANCE;
46     }
47
48     public ByteBuffer serialize(MapRequest mapRequest) {
49         int size = Length.HEADER_SIZE;
50         if (mapRequest.getSourceEid() != null && mapRequest.getSourceEid().getEid() != null) {
51             size += LispAddressSerializer.getInstance().getAddressSize(mapRequest.getSourceEid().getEid());
52         } else {
53             size += 2;
54         }
55         if (mapRequest.getItrRloc() != null) {
56             for (ItrRloc address : mapRequest.getItrRloc()) {
57                 size += LispAddressSerializer.getInstance().getAddressSize(address.getRloc());
58             }
59         }
60         if (mapRequest.getEidItem() != null) {
61             for (EidItem record : mapRequest.getEidItem()) {
62                 size += 2 + LispAddressSerializer.getInstance().getAddressSize(record.getEid());
63             }
64         }
65         ByteBuffer requestBuffer = ByteBuffer.allocate(size);
66         requestBuffer.put((byte) ((byte) (MessageType.MapRequest.getIntValue() << 4)
67                 | ByteUtil.boolToBit(BooleanUtils.isTrue(mapRequest.isAuthoritative()), Flags.AUTHORITATIVE)
68                 | ByteUtil.boolToBit(BooleanUtils.isTrue(mapRequest.isMapDataPresent()), Flags.MAP_DATA_PRESENT)
69                 | ByteUtil.boolToBit(BooleanUtils.isTrue(mapRequest.isProbe()), Flags.PROBE) | ByteUtil.boolToBit(
70                 BooleanUtils.isTrue(mapRequest.isSmr()), Flags.SMR)));
71         requestBuffer.put((byte) (ByteUtil.boolToBit(BooleanUtils.isTrue(mapRequest.isPitr()), Flags.PITR)
72                 | ByteUtil.boolToBit(BooleanUtils.isTrue(mapRequest.isSmrInvoked()), Flags.SMR_INVOKED)));
73         if (mapRequest.getItrRloc() != null) {
74             int irc = mapRequest.getItrRloc().size();
75             if (irc > 0) {
76                 irc--;
77             }
78             requestBuffer.put((byte) (irc));
79         } else {
80             requestBuffer.put((byte) 0);
81
82         }
83         if (mapRequest.getEidItem() != null) {
84             requestBuffer.put((byte) mapRequest.getEidItem().size());
85         } else {
86             requestBuffer.put((byte) 0);
87
88         }
89         requestBuffer.putLong(NumberUtil.asLong(mapRequest.getNonce()));
90         if (mapRequest.getSourceEid() != null && mapRequest.getSourceEid().getEid() != null) {
91             LispAddressSerializer.getInstance().serialize(requestBuffer, mapRequest.getSourceEid().getEid());
92         } else {
93             requestBuffer.putShort((short) 0);
94         }
95         if (mapRequest.getItrRloc() != null) {
96             for (ItrRloc address : mapRequest.getItrRloc()) {
97                 LispAddressSerializer.getInstance().serialize(requestBuffer, address.getRloc());
98             }
99         }
100         if (mapRequest.getEidItem() != null) {
101             for (EidItem record : mapRequest.getEidItem()) {
102                 requestBuffer.put((byte) 0);
103                 requestBuffer.put((byte) MaskUtil.getMaskForAddress(record.getEid().getAddress()));
104                 LispAddressSerializer.getInstance().serialize(requestBuffer, record.getEid());
105             }
106         }
107         if (mapRequest.getMapReply() != null) {
108             ByteBuffer replyBuffer = ByteBuffer.allocate(MappingRecordSerializer.getInstance()
109                     .getSerializationSize(mapRequest.getMapReply().getMappingRecord()));
110             MappingRecordSerializer.getInstance().serialize(replyBuffer, mapRequest.getMapReply().getMappingRecord());
111             ByteBuffer combinedBuffer = ByteBuffer.allocate(requestBuffer.capacity() + replyBuffer.capacity());
112             combinedBuffer.put(requestBuffer.array());
113             combinedBuffer.put(replyBuffer.array());
114             return combinedBuffer;
115         }
116         return requestBuffer;
117     }
118
119     @SuppressWarnings("checkstyle:IllegalCatch")
120     public MapRequest deserialize(ByteBuffer requestBuffer, InetAddress sourceRloc) {
121         try {
122             final byte typeAndFlags = requestBuffer.get();
123             final int type = typeAndFlags >> 4;
124             if (MessageType.forValue(type) != MessageType.MapRequest) {
125                 throw new LispSerializationException("Expected Map-Request packet (type 1), but was type " + type);
126             }
127
128             MapRequestBuilder builder = new MapRequestBuilder();
129             builder.setAuthoritative(ByteUtil.extractBit(typeAndFlags, Flags.AUTHORITATIVE));
130             builder.setMapDataPresent(ByteUtil.extractBit(typeAndFlags, Flags.MAP_DATA_PRESENT));
131             builder.setProbe(ByteUtil.extractBit(typeAndFlags, Flags.PROBE));
132             builder.setSmr(ByteUtil.extractBit(typeAndFlags, Flags.SMR));
133
134             final byte moreFlags = requestBuffer.get();
135             builder.setPitr(ByteUtil.extractBit(moreFlags, Flags.PITR));
136             builder.setSmrInvoked(ByteUtil.extractBit(moreFlags, Flags.SMR_INVOKED));
137
138             final int itrCount = ByteUtil.getUnsignedByte(requestBuffer) + 1;
139             final int recordCount = ByteUtil.getUnsignedByte(requestBuffer);
140             builder.setNonce(requestBuffer.getLong());
141             LispAddressSerializerContext ctx = new LispAddressSerializerContext(
142                     LispAddressSerializerContext.MASK_LEN_MISSING);
143             builder.setSourceEid(new SourceEidBuilder().setEid(
144                     LispAddressSerializer.getInstance().deserializeEid(requestBuffer, ctx)).build());
145
146             if (builder.getItrRloc() == null) {
147                 builder.setItrRloc(new ArrayList<ItrRloc>());
148             }
149             for (int i = 0; i < itrCount; i++) {
150                 builder.getItrRloc().add(new ItrRlocBuilder().setRloc(
151                         LispAddressSerializer.getInstance().deserializeRloc(requestBuffer)).build());
152             }
153
154             if (builder.getEidItem() == null) {
155                 builder.setEidItem(new ArrayList<EidItem>());
156             }
157             for (int i = 0; i < recordCount; i++) {
158                 builder.getEidItem().add(new EidItemBuilder().setEid(
159                         EidRecordSerializer.getInstance().deserialize(requestBuffer)).build());
160             }
161             if (builder.isMapDataPresent() && requestBuffer.hasRemaining()) {
162                 try {
163                     builder.setMapReply(new org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105
164                             .maprequest.MapReplyBuilder().setMappingRecord(
165                             MappingRecordSerializer.getInstance().deserialize(requestBuffer)).build()).build();
166                 } catch (RuntimeException re) {
167                     LOG.warn("Couldn't deserialize Map-Reply encapsulated in Map-Request", re);
168                 }
169             }
170             builder.setSourceRloc(LispAddressUtil.addressBinaryFromInet(sourceRloc));
171             return builder.build();
172         } catch (RuntimeException re) {
173             throw new LispSerializationException("Couldn't deserialize Map-Request (len="
174                     + requestBuffer.capacity() + ")", re);
175         }
176     }
177
178     public interface Flags {
179         byte AUTHORITATIVE = 0x08;
180         byte MAP_DATA_PRESENT = 0x04;
181         byte PROBE = 0x02;
182         byte SMR = 0x01;
183
184         byte PITR = (byte) 0x80;
185         byte SMR_INVOKED = 0x40;
186     }
187
188     private interface Length {
189         int HEADER_SIZE = 12;
190     }
191
192 }