/* * Copyright (c) 2014 Contextream, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.lispflowmapping.lisp.serializer; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang3.BooleanUtils; import org.opendaylight.lispflowmapping.lisp.serializer.exception.LispSerializationException; import org.opendaylight.lispflowmapping.lisp.util.ByteUtil; import org.opendaylight.lispflowmapping.lisp.util.NumberUtil; import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.MapNotify; import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.MessageType; import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.SiteId; import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.XtrId; import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapnotifymessage.MapNotifyBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecordBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.list.MappingRecordItem; import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.list.MappingRecordItemBuilder; /** * This class deals with serializing map notify from the java object to udp. */ public final class MapNotifySerializer { private static final MapNotifySerializer INSTANCE = new MapNotifySerializer(); // Private constructor prevents instantiation from other classes private MapNotifySerializer() { } public static MapNotifySerializer getInstance() { return INSTANCE; } public ByteBuffer serialize(MapNotify mapNotify) { int size = Length.HEADER_SIZE; if (mapNotify.getAuthenticationData() != null) { size += mapNotify.getAuthenticationData().length; } if (mapNotify.isXtrSiteIdPresent() != null && mapNotify.isXtrSiteIdPresent()) { size += org.opendaylight.lispflowmapping.lisp.serializer.MapRegisterSerializer.Length.XTRID_SIZE + org.opendaylight.lispflowmapping.lisp.serializer.MapRegisterSerializer.Length.SITEID_SIZE; } for (MappingRecordItem mappingRecord : mapNotify.getMappingRecordItem()) { size += MappingRecordSerializer.getInstance().getSerializationSize(mappingRecord.getMappingRecord()); } ByteBuffer replyBuffer = ByteBuffer.allocate(size); replyBuffer.put((byte) ((byte) (MessageType.MapNotify.getIntValue() << 4) | ByteUtil.boolToBit(BooleanUtils.isTrue(mapNotify.isXtrSiteIdPresent()), Flags.XTRSITEID))); replyBuffer.position(replyBuffer.position() + Length.RES); replyBuffer.put(ByteUtil.boolToBit(BooleanUtils.isTrue(mapNotify.isMergeEnabled()), Flags.MERGE_ENABLED)); if (mapNotify.getMappingRecordItem() != null) { replyBuffer.put((byte) mapNotify.getMappingRecordItem().size()); } else { replyBuffer.put((byte) 0); } replyBuffer.putLong(NumberUtil.asLong(mapNotify.getNonce())); replyBuffer.putShort(NumberUtil.asShort(mapNotify.getKeyId())); if (mapNotify.getAuthenticationData() != null) { replyBuffer.putShort((short) mapNotify.getAuthenticationData().length); replyBuffer.put(mapNotify.getAuthenticationData()); } else { replyBuffer.putShort((short) 0); } if (mapNotify.getMappingRecordItem() != null) { for (MappingRecordItem mappingRecord : mapNotify.getMappingRecordItem()) { MappingRecordSerializer.getInstance().serialize(replyBuffer, mappingRecord.getMappingRecord()); } } if (mapNotify.isXtrSiteIdPresent() != null && mapNotify.isXtrSiteIdPresent()) { replyBuffer.put(mapNotify.getXtrId().getValue()); replyBuffer.put(mapNotify.getSiteId().getValue()); } replyBuffer.clear(); return replyBuffer; } @SuppressWarnings("checkstyle:IllegalCatch") public MapNotify deserialize(ByteBuffer notifyBuffer) { try { MapNotifyBuilder builder = new MapNotifyBuilder(); builder.setMappingRecordItem(new ArrayList()); byte typeAndFlags = notifyBuffer.get(); boolean xtrSiteIdPresent = ByteUtil.extractBit(typeAndFlags, Flags.XTRSITEID); builder.setXtrSiteIdPresent(xtrSiteIdPresent); notifyBuffer.position(notifyBuffer.position() + Length.RES); builder.setMergeEnabled(ByteUtil.extractBit(notifyBuffer.get(), Flags.MERGE_ENABLED)); byte recordCount = (byte) ByteUtil.getUnsignedByte(notifyBuffer); builder.setNonce(notifyBuffer.getLong()); builder.setKeyId(notifyBuffer.getShort()); short authenticationLength = notifyBuffer.getShort(); byte[] authenticationData = new byte[authenticationLength]; notifyBuffer.get(authenticationData); builder.setAuthenticationData(authenticationData); if (xtrSiteIdPresent) { List mrbs = new ArrayList(); for (int i = 0; i < recordCount; i++) { mrbs.add(MappingRecordSerializer.getInstance().deserializeToBuilder(notifyBuffer)); } byte[] xtrIdBuf = new byte[MapRegisterSerializer.Length.XTRID_SIZE]; notifyBuffer.get(xtrIdBuf); XtrId xtrId = new XtrId(xtrIdBuf); byte[] siteIdBuf = new byte[MapRegisterSerializer.Length.SITEID_SIZE]; notifyBuffer.get(siteIdBuf); SiteId siteId = new SiteId(siteIdBuf); builder.setXtrId(xtrId); builder.setSiteId(siteId); for (MappingRecordBuilder mrb : mrbs) { mrb.setXtrId(xtrId); mrb.setSiteId(siteId); builder.getMappingRecordItem().add(new MappingRecordItemBuilder().setMappingRecord( mrb.build()).build()); } } else { for (int i = 0; i < recordCount; i++) { builder.getMappingRecordItem().add(new MappingRecordItemBuilder().setMappingRecord( MappingRecordSerializer.getInstance().deserialize(notifyBuffer)).build()); } } notifyBuffer.limit(notifyBuffer.position()); return builder.build(); } catch (RuntimeException re) { throw new LispSerializationException("Couldn't deserialize Map-Notify (len=" + notifyBuffer.capacity() + ")", re); } } private interface Flags { byte XTRSITEID = 0x08; byte MERGE_ENABLED = 0x04; } private interface Length { int HEADER_SIZE = 16; int RES = 1; } }