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