Merge "Bug 611 - NlriReg supports serialization"
[bgpcep.git] / bgp / parser-spi / src / main / java / org / opendaylight / protocol / bgp / parser / spi / pojo / SimpleNlriRegistry.java
1 /*
2  * Copyright (c) 2013 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 package org.opendaylight.protocol.bgp.parser.spi.pojo;
9
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.Iterables;
12 import com.google.common.primitives.UnsignedBytes;
13
14 import io.netty.buffer.ByteBuf;
15 import io.netty.buffer.Unpooled;
16
17 import java.util.concurrent.ConcurrentHashMap;
18 import java.util.concurrent.ConcurrentMap;
19
20 import org.opendaylight.protocol.bgp.concepts.util.NextHopUtil;
21 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
22 import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
23 import org.opendaylight.protocol.bgp.parser.spi.AddressFamilyRegistry;
24 import org.opendaylight.protocol.bgp.parser.spi.NlriParser;
25 import org.opendaylight.protocol.bgp.parser.spi.NlriRegistry;
26 import org.opendaylight.protocol.bgp.parser.spi.NlriSerializer;
27 import org.opendaylight.protocol.bgp.parser.spi.SubsequentAddressFamilyRegistry;
28 import org.opendaylight.protocol.concepts.AbstractRegistration;
29 import org.opendaylight.protocol.util.ByteArray;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlri;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlriBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlri;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlriBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.AddressFamily;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.SubsequentAddressFamily;
37 import org.opendaylight.yangtools.yang.binding.DataObject;
38
39 final class SimpleNlriRegistry implements NlriRegistry {
40
41     private static final int RESERVED = 1;
42
43     private final ConcurrentMap<BgpTableType, NlriParser> handlers = new ConcurrentHashMap<>();
44     private final ConcurrentMap<Class<? extends DataObject>, NlriSerializer> serializers = new ConcurrentHashMap<>();
45     private final SubsequentAddressFamilyRegistry safiReg;
46     private final AddressFamilyRegistry afiReg;
47
48     public SimpleNlriRegistry(final AddressFamilyRegistry afiReg, final SubsequentAddressFamilyRegistry safiReg) {
49         this.afiReg = Preconditions.checkNotNull(afiReg);
50         this.safiReg = Preconditions.checkNotNull(safiReg);
51     }
52
53     private static BgpTableType createKey(final Class<? extends AddressFamily> afi,
54             final Class<? extends SubsequentAddressFamily> safi) {
55         Preconditions.checkNotNull(afi);
56         Preconditions.checkNotNull(safi);
57         return new BgpTableTypeImpl(afi, safi);
58     }
59
60     synchronized AutoCloseable registerNlriSerializer(final Class<? extends DataObject> nlriClass, final NlriSerializer serializer){
61         final NlriParser prev = this.handlers.get(nlriClass);
62         Preconditions.checkState(prev == null, "Serializer already bound to class " + prev);
63
64         this.serializers.put(nlriClass, serializer);
65         final Object lock = this;
66         return new AbstractRegistration() {
67             @Override
68             protected void removeRegistration() {
69                 synchronized (lock) {
70                     SimpleNlriRegistry.this.serializers.remove(nlriClass);
71                 }
72             }
73         };
74     }
75
76     synchronized AutoCloseable registerNlriParser(final Class<? extends AddressFamily> afi,
77             final Class<? extends SubsequentAddressFamily> safi, final NlriParser parser) {
78         final BgpTableType key = createKey(afi, safi);
79         final NlriParser prev = this.handlers.get(key);
80         Preconditions.checkState(prev == null, "AFI/SAFI is already bound to parser " + prev);
81
82         this.handlers.put(key, parser);
83         final Object lock = this;
84         return new AbstractRegistration() {
85             @Override
86             protected void removeRegistration() {
87                 synchronized (lock) {
88                     SimpleNlriRegistry.this.handlers.remove(key);
89                 }
90             }
91         };
92     }
93
94     private Class<? extends AddressFamily> getAfi(final ByteBuf buffer) throws BGPParsingException {
95         final int afiVal = buffer.readUnsignedShort();
96         final Class<? extends AddressFamily> afi = this.afiReg.classForFamily(afiVal);
97         if (afi == null) {
98             throw new BGPParsingException("Address Family Identifier: '" + afiVal + "' not supported.");
99         }
100         return afi;
101     }
102
103     private Class<? extends SubsequentAddressFamily> getSafi(final ByteBuf buffer) throws BGPParsingException {
104         final int safiVal = UnsignedBytes.toInt(buffer.readByte());
105         final Class<? extends SubsequentAddressFamily> safi = this.safiReg.classForFamily(safiVal);
106         if (safi == null) {
107             throw new BGPParsingException("Subsequent Address Family Identifier: '" + safiVal + "' not supported.");
108         }
109         return safi;
110     }
111
112     @Override
113     public MpUnreachNlri parseMpUnreach(final ByteBuf buffer) throws BGPParsingException {
114         final MpUnreachNlriBuilder builder = new MpUnreachNlriBuilder();
115         builder.setAfi(getAfi(buffer));
116         builder.setSafi(getSafi(buffer));
117
118         final NlriParser parser = this.handlers.get(createKey(builder.getAfi(), builder.getSafi()));
119         final ByteBuf nlri = buffer.slice();
120         parser.parseNlri(nlri, builder);
121         return builder.build();
122     }
123
124     @Override
125     public void serializeMpReach(MpReachNlri mpReachNlri, ByteBuf byteAggregator) {
126
127         byteAggregator.writeShort(this.afiReg.numberForClass(mpReachNlri.getAfi()));
128         byteAggregator.writeByte(this.safiReg.numberForClass(mpReachNlri.getSafi()));
129
130         ByteBuf nextHopBuffer = Unpooled.buffer();
131         NextHopUtil.serializeNextHopSimple(mpReachNlri.getCNextHop(), nextHopBuffer);
132
133         byteAggregator.writeByte(nextHopBuffer.writerIndex());
134         byteAggregator.writeBytes(nextHopBuffer);
135         byteAggregator.writeZero(RESERVED);
136     }
137
138     @Override
139     public void serializeMpUnReach(MpUnreachNlri mpUnreachNlri, ByteBuf byteAggregator) {
140
141         byteAggregator.writeShort(this.afiReg.numberForClass(mpUnreachNlri.getAfi()));
142         byteAggregator.writeByte(this.safiReg.numberForClass(mpUnreachNlri.getSafi()));
143     }
144
145     @Override
146     public Iterable<NlriSerializer> getSerializers() {
147         return Iterables.unmodifiableIterable(this.serializers.values());
148     }
149
150     @Override
151     public MpReachNlri parseMpReach(final ByteBuf buffer) throws BGPParsingException {
152         final MpReachNlriBuilder builder = new MpReachNlriBuilder();
153         builder.setAfi(getAfi(buffer));
154         builder.setSafi(getSafi(buffer));
155
156         final NlriParser parser = this.handlers.get(createKey(builder.getAfi(), builder.getSafi()));
157
158         final int nextHopLength = UnsignedBytes.toInt(buffer.readByte());
159         final byte[] nextHop = ByteArray.readBytes(buffer, nextHopLength);
160         buffer.skipBytes(RESERVED);
161
162         final ByteBuf nlri = buffer.slice();
163         parser.parseNlri(nlri, nextHop, builder);
164         return builder.build();
165     }
166 }