4b99349c2509daa1abf702e57bca1a60173b2850
[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 io.netty.buffer.ByteBuf;
13 import io.netty.buffer.Unpooled;
14 import java.util.AbstractMap;
15 import java.util.Map;
16 import java.util.concurrent.ConcurrentHashMap;
17 import java.util.concurrent.ConcurrentMap;
18 import org.opendaylight.bgp.concepts.NextHopUtil;
19 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
20 import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
21 import org.opendaylight.protocol.bgp.parser.spi.AddressFamilyRegistry;
22 import org.opendaylight.protocol.bgp.parser.spi.NextHopParserSerializer;
23 import org.opendaylight.protocol.bgp.parser.spi.NlriParser;
24 import org.opendaylight.protocol.bgp.parser.spi.NlriRegistry;
25 import org.opendaylight.protocol.bgp.parser.spi.NlriSerializer;
26 import org.opendaylight.protocol.bgp.parser.spi.PeerSpecificParserConstraint;
27 import org.opendaylight.protocol.bgp.parser.spi.SubsequentAddressFamilyRegistry;
28 import org.opendaylight.protocol.concepts.AbstractRegistration;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlri;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlriBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlri;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlriBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.AddressFamily;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.SubsequentAddressFamily;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.CNextHop;
37 import org.opendaylight.yangtools.yang.binding.DataObject;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 final class SimpleNlriRegistry implements NlriRegistry {
42
43     private static final int RESERVED = 1;
44     private static final int NEXT_HOP_LENGHT = 1;
45     private static final Logger LOG = LoggerFactory.getLogger(SimpleNlriRegistry.class);
46
47     private final ConcurrentMap<BgpTableType, NlriParser> handlers = new ConcurrentHashMap<>();
48     private final ConcurrentMap<Class<? extends DataObject>, NlriSerializer> serializers = new ConcurrentHashMap<>();
49     private final ConcurrentMap<BgpTableType, NextHopParserSerializer> nextHopParsers = new ConcurrentHashMap<>();
50     private final ConcurrentMap<Map.Entry<Class<? extends CNextHop>, BgpTableType>, NextHopParserSerializer> nextHopSerializers = new ConcurrentHashMap<>();
51     private final SubsequentAddressFamilyRegistry safiReg;
52     private final AddressFamilyRegistry afiReg;
53
54     public SimpleNlriRegistry(final AddressFamilyRegistry afiReg, final SubsequentAddressFamilyRegistry safiReg) {
55         this.afiReg = Preconditions.checkNotNull(afiReg);
56         this.safiReg = Preconditions.checkNotNull(safiReg);
57     }
58
59     private static BgpTableType createKey(final Class<? extends AddressFamily> afi,
60         final Class<? extends SubsequentAddressFamily> safi) {
61         Preconditions.checkNotNull(afi);
62         Preconditions.checkNotNull(safi);
63         return new BgpTableTypeImpl(afi, safi);
64     }
65
66     synchronized AutoCloseable registerNlriSerializer(final Class<? extends DataObject> nlriClass, final
67         NlriSerializer serializer){
68         final NlriSerializer prev = this.serializers.get(nlriClass);
69         Preconditions.checkState(prev == null, "Serializer already bound to class " + prev);
70
71         this.serializers.put(nlriClass, serializer);
72
73         final Object lock = this;
74         return new AbstractRegistration() {
75             @Override
76             protected void removeRegistration() {
77                 synchronized (lock) {
78                     SimpleNlriRegistry.this.serializers.remove(nlriClass);
79                 }
80             }
81         };
82     }
83
84     synchronized AutoCloseable registerNlriParser(final Class<? extends AddressFamily> afi,
85         final Class<? extends SubsequentAddressFamily> safi, final NlriParser parser,
86         final NextHopParserSerializer nextHopSerializer, final Class<? extends CNextHop> cNextHopClass,
87         final Class<? extends CNextHop>... cNextHopClassList) {
88         final BgpTableType key = createKey(afi, safi);
89         final NlriParser prev = this.handlers.get(key);
90         Preconditions.checkState(prev == null, "AFI/SAFI is already bound to parser " + prev);
91
92         this.handlers.put(key, parser);
93         this.nextHopParsers.put(key,nextHopSerializer);
94
95         if (cNextHopClass != null) {
96             final Map.Entry<Class<? extends CNextHop>, BgpTableType> nhKey = new AbstractMap.SimpleEntry(cNextHopClass, key);
97             this.nextHopSerializers.put(nhKey, nextHopSerializer);
98             for (final Class<? extends CNextHop> cNextHop : cNextHopClassList) {
99                 final Map.Entry<Class<? extends CNextHop>, BgpTableType> nhKeys = new AbstractMap.SimpleEntry(cNextHop, key);
100                 this.nextHopSerializers.put(nhKeys, nextHopSerializer);
101             }
102         }
103
104         final Object lock = this;
105         return new AbstractRegistration() {
106             @Override
107             protected void removeRegistration() {
108                 synchronized (lock) {
109                     SimpleNlriRegistry.this.handlers.remove(key);
110                     SimpleNlriRegistry.this.nextHopParsers.remove(key);
111                     if (cNextHopClass != null) {
112                         final Map.Entry<Class<? extends CNextHop>, BgpTableType> nhKey = new AbstractMap.SimpleEntry(cNextHopClass, key);
113                         SimpleNlriRegistry.this.nextHopSerializers.remove(nhKey);
114                         for (final Class<? extends CNextHop> cNextHop : cNextHopClassList) {
115                             final Map.Entry<Class<? extends CNextHop>, BgpTableType> nhKeys = new AbstractMap.SimpleEntry(cNextHop, key);
116                             SimpleNlriRegistry.this.nextHopSerializers.remove(nhKeys);
117                         }
118                     }
119                 }
120             }
121         };
122     }
123
124     private Class<? extends AddressFamily> getAfi(final ByteBuf buffer) throws BGPParsingException {
125         final int afiVal = buffer.readUnsignedShort();
126         final Class<? extends AddressFamily> afi = this.afiReg.classForFamily(afiVal);
127         if (afi == null) {
128             throw new BGPParsingException("Address Family Identifier: '" + afiVal + "' not supported.");
129         }
130         return afi;
131     }
132
133     private Class<? extends SubsequentAddressFamily> getSafi(final ByteBuf buffer) throws BGPParsingException {
134         final int safiVal = buffer.readUnsignedByte();
135         final Class<? extends SubsequentAddressFamily> safi = this.safiReg.classForFamily(safiVal);
136         if (safi == null) {
137             throw new BGPParsingException("Subsequent Address Family Identifier: '" + safiVal + "' not supported.");
138         }
139         return safi;
140     }
141
142     @Override
143     public MpUnreachNlri parseMpUnreach(final ByteBuf buffer) throws BGPParsingException {
144         return parseMpUnreach(buffer, null);
145     }
146
147     @Override
148     public MpUnreachNlri parseMpUnreach(final ByteBuf buffer, final PeerSpecificParserConstraint constraint)
149             throws BGPParsingException {
150         final MpUnreachNlriBuilder builder = new MpUnreachNlriBuilder();
151         builder.setAfi(getAfi(buffer));
152         builder.setSafi(getSafi(buffer));
153
154         final ByteBuf nlri = buffer.slice();
155         final BgpTableType key = createKey(builder.getAfi(), builder.getSafi());
156         final NlriParser parser = this.handlers.get(key);
157         parser.parseNlri(nlri, builder, constraint);
158         return builder.build();
159     }
160
161     @Override
162     public void serializeMpReach(final MpReachNlri mpReachNlri, final ByteBuf byteAggregator) {
163         final Class<? extends AddressFamily> afi = mpReachNlri.getAfi();
164         final Class<? extends SubsequentAddressFamily> safi = mpReachNlri.getSafi();
165         byteAggregator.writeShort(this.afiReg.numberForClass(afi));
166         byteAggregator.writeByte(this.safiReg.numberForClass(safi));
167
168         final CNextHop cNextHop = mpReachNlri.getCNextHop();
169         if (cNextHop != null) {
170             final Map.Entry<Class<? extends CNextHop>, BgpTableType> key = new AbstractMap.SimpleEntry(cNextHop.getImplementedInterface(),
171                 new BgpTableTypeImpl(afi, safi));
172             final NextHopParserSerializer nextHopSerializer = this.nextHopSerializers.get(key);
173             final ByteBuf nextHopBuffer = Unpooled.buffer();
174             if (nextHopSerializer == null) {
175                 //TODO Remove once deprecated registerNlriParser is removed
176                 LOG.warn("NexHop Parser/Serializer for AFI/SAFI ({},{}) not bound", afi, safi);
177                 NextHopUtil.serializeNextHop(cNextHop, nextHopBuffer);
178             } else {
179                 nextHopSerializer.serializeNextHop(cNextHop, nextHopBuffer);
180             }
181             byteAggregator.writeByte(nextHopBuffer.writerIndex());
182             byteAggregator.writeBytes(nextHopBuffer);
183
184         } else {
185             byteAggregator.writeZero(NEXT_HOP_LENGHT);
186         }
187         byteAggregator.writeZero(RESERVED);
188     }
189
190     @Override
191     public void serializeMpUnReach(final MpUnreachNlri mpUnreachNlri, final ByteBuf byteAggregator) {
192         byteAggregator.writeShort(this.afiReg.numberForClass(mpUnreachNlri.getAfi()));
193         byteAggregator.writeByte(this.safiReg.numberForClass(mpUnreachNlri.getSafi()));
194     }
195
196     @Override
197     public Iterable<NlriSerializer> getSerializers() {
198         return Iterables.unmodifiableIterable(this.serializers.values());
199     }
200
201     @Override
202     public MpReachNlri parseMpReach(final ByteBuf buffer) throws BGPParsingException {
203         return parseMpReach(buffer, null);
204     }
205
206     @Override
207     public MpReachNlri parseMpReach(final ByteBuf buffer, final PeerSpecificParserConstraint constraint)
208             throws BGPParsingException {
209         final MpReachNlriBuilder builder = new MpReachNlriBuilder();
210         final Class<? extends AddressFamily> afi = getAfi(buffer);
211         final Class<? extends SubsequentAddressFamily> safi = getSafi(buffer);
212         builder.setAfi(afi);
213         builder.setSafi(safi);
214
215         final BgpTableType key = createKey(builder.getAfi(), builder.getSafi());
216
217         final int nextHopLength = buffer.readUnsignedByte();
218         if (nextHopLength != 0) {
219             final NextHopParserSerializer nextHopParser = this.nextHopParsers.get(key);
220             if (nextHopParser != null) {
221                 builder.setCNextHop(nextHopParser.parseNextHop(buffer.readSlice(nextHopLength)));
222             } else {
223                 builder.setCNextHop(NextHopUtil.parseNextHop(buffer.readSlice(nextHopLength)));
224                 LOG.warn("NexHop Parser/Serializer for AFI/SAFI ({},{}) not bound",afi,safi);
225             }
226         }
227         buffer.skipBytes(RESERVED);
228
229         final ByteBuf nlri = buffer.slice();
230         final NlriParser parser = this.handlers.get(key);
231         parser.parseNlri(nlri, builder, constraint);
232         return builder.build();
233     }
234 }