Merge "Bug 611 - NlriReg supports serialization"
[bgpcep.git] / bgp / parser-spi / src / main / java / org / opendaylight / protocol / bgp / parser / spi / pojo / SimpleNlriRegistry.java
index 389b777f358b35096b8c0680a3d52ea202a65322..de17abfec7176b0da81989c064004cff5feb8ecc 100644 (file)
  */
 package org.opendaylight.protocol.bgp.parser.spi.pojo;
 
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+import com.google.common.primitives.UnsignedBytes;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
+import org.opendaylight.protocol.bgp.concepts.util.NextHopUtil;
 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
 import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
 import org.opendaylight.protocol.bgp.parser.spi.AddressFamilyRegistry;
 import org.opendaylight.protocol.bgp.parser.spi.NlriParser;
 import org.opendaylight.protocol.bgp.parser.spi.NlriRegistry;
+import org.opendaylight.protocol.bgp.parser.spi.NlriSerializer;
 import org.opendaylight.protocol.bgp.parser.spi.SubsequentAddressFamilyRegistry;
 import org.opendaylight.protocol.concepts.AbstractRegistration;
 import org.opendaylight.protocol.util.ByteArray;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.BgpTableType;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.update.path.attributes.MpReachNlri;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.update.path.attributes.MpReachNlriBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.update.path.attributes.MpUnreachNlri;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.update.path.attributes.MpUnreachNlriBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlriBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlriBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.AddressFamily;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.SubsequentAddressFamily;
-
-import com.google.common.base.Preconditions;
-import com.google.common.primitives.UnsignedBytes;
+import org.opendaylight.yangtools.yang.binding.DataObject;
 
 final class SimpleNlriRegistry implements NlriRegistry {
-       private final ConcurrentMap<BgpTableType, NlriParser> handlers = new ConcurrentHashMap<>();
-       private final SubsequentAddressFamilyRegistry safiReg;
-       private final AddressFamilyRegistry afiReg;
-
-       public SimpleNlriRegistry(final AddressFamilyRegistry afiReg, final SubsequentAddressFamilyRegistry safiReg) {
-               this.afiReg = Preconditions.checkNotNull(afiReg);
-               this.safiReg = Preconditions.checkNotNull(safiReg);
-       }
-
-       private static BgpTableType createKey(final Class<? extends AddressFamily> afi,
-                       final Class<? extends SubsequentAddressFamily> safi) {
-               Preconditions.checkNotNull(afi);
-               Preconditions.checkNotNull(safi);
-               return new BgpTableTypeImpl(afi, safi);
-       }
-
-       synchronized AutoCloseable registerNlriParser(final Class<? extends AddressFamily> afi,
-                       final Class<? extends SubsequentAddressFamily> safi, final NlriParser parser) {
-               final BgpTableType key = createKey(afi, safi);
-               final NlriParser prev = handlers.get(key);
-               Preconditions.checkState(prev == null, "AFI/SAFI is already bound to parser " + prev);
-
-               handlers.put(key, parser);
-               final Object lock = this;
-               return new AbstractRegistration() {
-                       @Override
-                       protected void removeRegistration() {
-                               synchronized (lock) {
-                                       handlers.remove(key);
-                               }
-                       }
-               };
-       }
-
-       private Class<? extends AddressFamily> getAfi(final byte[] header) throws BGPParsingException {
-               final int afiVal = UnsignedBytes.toInt(header[0]) * 256 + UnsignedBytes.toInt(header[1]);
-               final Class<? extends AddressFamily> afi = afiReg.classForFamily(afiVal);
-               if (afi == null) {
-                       throw new BGPParsingException("Address Family Identifier: '" + afiVal + "' not supported.");
-               }
-
-               return afi;
-       }
-
-       private Class<? extends SubsequentAddressFamily> getSafi(final byte[] header) throws BGPParsingException {
-               final int safiVal = UnsignedBytes.toInt(header[2]);
-               final Class<? extends SubsequentAddressFamily> safi = safiReg.classForFamily(safiVal);
-               if (safi == null) {
-                       throw new BGPParsingException("Subsequent Address Family Identifier: '" + safiVal + "' not supported.");
-               }
-
-               return safi;
-       }
-
-       @Override
-       public MpUnreachNlri parseMpUnreach(final byte[] bytes) throws BGPParsingException {
-               final MpUnreachNlriBuilder builder = new MpUnreachNlriBuilder();
-               builder.setAfi(getAfi(bytes));
-               builder.setSafi(getSafi(bytes));
-
-               final NlriParser parser = handlers.get(createKey(builder.getAfi(), builder.getSafi()));
-               parser.parseNlri(ByteArray.subByte(bytes, 3, bytes.length - 3), builder);
-
-               return builder.build();
-       }
-
-       @Override
-       public MpReachNlri parseMpReach(final byte[] bytes) throws BGPParsingException {
-               final MpReachNlriBuilder builder = new MpReachNlriBuilder();
-               builder.setAfi(getAfi(bytes));
-               builder.setSafi(getSafi(bytes));
-
-               final NlriParser parser = handlers.get(createKey(builder.getAfi(), builder.getSafi()));
-
-               final int nextHopLength = UnsignedBytes.toInt(bytes[3]);
-               int byteOffset = 4;
-
-               final byte[] nextHop = ByteArray.subByte(bytes, byteOffset, nextHopLength);
-               byteOffset += nextHopLength + 1;
-
-               final byte[] nlri = ByteArray.subByte(bytes, byteOffset, bytes.length - byteOffset);
-               parser.parseNlri(nlri, nextHop, builder);
-
-               return builder.build();
-       }
+
+    private static final int RESERVED = 1;
+
+    private final ConcurrentMap<BgpTableType, NlriParser> handlers = new ConcurrentHashMap<>();
+    private final ConcurrentMap<Class<? extends DataObject>, NlriSerializer> serializers = new ConcurrentHashMap<>();
+    private final SubsequentAddressFamilyRegistry safiReg;
+    private final AddressFamilyRegistry afiReg;
+
+    public SimpleNlriRegistry(final AddressFamilyRegistry afiReg, final SubsequentAddressFamilyRegistry safiReg) {
+        this.afiReg = Preconditions.checkNotNull(afiReg);
+        this.safiReg = Preconditions.checkNotNull(safiReg);
+    }
+
+    private static BgpTableType createKey(final Class<? extends AddressFamily> afi,
+            final Class<? extends SubsequentAddressFamily> safi) {
+        Preconditions.checkNotNull(afi);
+        Preconditions.checkNotNull(safi);
+        return new BgpTableTypeImpl(afi, safi);
+    }
+
+    synchronized AutoCloseable registerNlriSerializer(final Class<? extends DataObject> nlriClass, final NlriSerializer serializer){
+        final NlriParser prev = this.handlers.get(nlriClass);
+        Preconditions.checkState(prev == null, "Serializer already bound to class " + prev);
+
+        this.serializers.put(nlriClass, serializer);
+        final Object lock = this;
+        return new AbstractRegistration() {
+            @Override
+            protected void removeRegistration() {
+                synchronized (lock) {
+                    SimpleNlriRegistry.this.serializers.remove(nlriClass);
+                }
+            }
+        };
+    }
+
+    synchronized AutoCloseable registerNlriParser(final Class<? extends AddressFamily> afi,
+            final Class<? extends SubsequentAddressFamily> safi, final NlriParser parser) {
+        final BgpTableType key = createKey(afi, safi);
+        final NlriParser prev = this.handlers.get(key);
+        Preconditions.checkState(prev == null, "AFI/SAFI is already bound to parser " + prev);
+
+        this.handlers.put(key, parser);
+        final Object lock = this;
+        return new AbstractRegistration() {
+            @Override
+            protected void removeRegistration() {
+                synchronized (lock) {
+                    SimpleNlriRegistry.this.handlers.remove(key);
+                }
+            }
+        };
+    }
+
+    private Class<? extends AddressFamily> getAfi(final ByteBuf buffer) throws BGPParsingException {
+        final int afiVal = buffer.readUnsignedShort();
+        final Class<? extends AddressFamily> afi = this.afiReg.classForFamily(afiVal);
+        if (afi == null) {
+            throw new BGPParsingException("Address Family Identifier: '" + afiVal + "' not supported.");
+        }
+        return afi;
+    }
+
+    private Class<? extends SubsequentAddressFamily> getSafi(final ByteBuf buffer) throws BGPParsingException {
+        final int safiVal = UnsignedBytes.toInt(buffer.readByte());
+        final Class<? extends SubsequentAddressFamily> safi = this.safiReg.classForFamily(safiVal);
+        if (safi == null) {
+            throw new BGPParsingException("Subsequent Address Family Identifier: '" + safiVal + "' not supported.");
+        }
+        return safi;
+    }
+
+    @Override
+    public MpUnreachNlri parseMpUnreach(final ByteBuf buffer) throws BGPParsingException {
+        final MpUnreachNlriBuilder builder = new MpUnreachNlriBuilder();
+        builder.setAfi(getAfi(buffer));
+        builder.setSafi(getSafi(buffer));
+
+        final NlriParser parser = this.handlers.get(createKey(builder.getAfi(), builder.getSafi()));
+        final ByteBuf nlri = buffer.slice();
+        parser.parseNlri(nlri, builder);
+        return builder.build();
+    }
+
+    @Override
+    public void serializeMpReach(MpReachNlri mpReachNlri, ByteBuf byteAggregator) {
+
+        byteAggregator.writeShort(this.afiReg.numberForClass(mpReachNlri.getAfi()));
+        byteAggregator.writeByte(this.safiReg.numberForClass(mpReachNlri.getSafi()));
+
+        ByteBuf nextHopBuffer = Unpooled.buffer();
+        NextHopUtil.serializeNextHopSimple(mpReachNlri.getCNextHop(), nextHopBuffer);
+
+        byteAggregator.writeByte(nextHopBuffer.writerIndex());
+        byteAggregator.writeBytes(nextHopBuffer);
+        byteAggregator.writeZero(RESERVED);
+    }
+
+    @Override
+    public void serializeMpUnReach(MpUnreachNlri mpUnreachNlri, ByteBuf byteAggregator) {
+
+        byteAggregator.writeShort(this.afiReg.numberForClass(mpUnreachNlri.getAfi()));
+        byteAggregator.writeByte(this.safiReg.numberForClass(mpUnreachNlri.getSafi()));
+    }
+
+    @Override
+    public Iterable<NlriSerializer> getSerializers() {
+        return Iterables.unmodifiableIterable(this.serializers.values());
+    }
+
+    @Override
+    public MpReachNlri parseMpReach(final ByteBuf buffer) throws BGPParsingException {
+        final MpReachNlriBuilder builder = new MpReachNlriBuilder();
+        builder.setAfi(getAfi(buffer));
+        builder.setSafi(getSafi(buffer));
+
+        final NlriParser parser = this.handlers.get(createKey(builder.getAfi(), builder.getSafi()));
+
+        final int nextHopLength = UnsignedBytes.toInt(buffer.readByte());
+        final byte[] nextHop = ByteArray.readBytes(buffer, nextHopLength);
+        buffer.skipBytes(RESERVED);
+
+        final ByteBuf nlri = buffer.slice();
+        parser.parseNlri(nlri, nextHop, builder);
+        return builder.build();
+    }
 }