2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.protocol.bgp.parser.spi.pojo;
10 import static com.google.common.base.Preconditions.checkState;
11 import static java.util.Objects.requireNonNull;
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.Optional;
19 import java.util.concurrent.ConcurrentHashMap;
20 import java.util.concurrent.ConcurrentMap;
21 import org.opendaylight.bgp.concepts.NextHopUtil;
22 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
23 import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
24 import org.opendaylight.protocol.bgp.parser.spi.AddressFamilyRegistry;
25 import org.opendaylight.protocol.bgp.parser.spi.NextHopParserSerializer;
26 import org.opendaylight.protocol.bgp.parser.spi.NlriParser;
27 import org.opendaylight.protocol.bgp.parser.spi.NlriRegistry;
28 import org.opendaylight.protocol.bgp.parser.spi.NlriSerializer;
29 import org.opendaylight.protocol.bgp.parser.spi.PeerSpecificParserConstraint;
30 import org.opendaylight.protocol.bgp.parser.spi.SubsequentAddressFamilyRegistry;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.BgpTableType;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpReachNlri;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpReachNlriBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpUnreachNlri;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpUnreachNlriBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.AddressFamily;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.SubsequentAddressFamily;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.next.hop.CNextHop;
40 import org.opendaylight.yangtools.concepts.AbstractRegistration;
41 import org.opendaylight.yangtools.concepts.Registration;
42 import org.opendaylight.yangtools.yang.binding.DataObject;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
46 final class SimpleNlriRegistry implements NlriRegistry {
48 private static final int RESERVED = 1;
49 private static final String PARSER_NOT_FOUND = "Nlri parser not found for table type {}";
50 private static final Logger LOG = LoggerFactory.getLogger(SimpleNlriRegistry.class);
52 private final ConcurrentMap<BgpTableType, NlriParser> handlers = new ConcurrentHashMap<>();
53 private final ConcurrentMap<Class<? extends DataObject>, NlriSerializer> serializers = new ConcurrentHashMap<>();
54 private final ConcurrentMap<BgpTableType, NextHopParserSerializer> nextHopParsers = new ConcurrentHashMap<>();
55 private final ConcurrentMap<Entry<Class<? extends CNextHop>, BgpTableType>,
56 NextHopParserSerializer> nextHopSerializers = new ConcurrentHashMap<>();
57 private final SubsequentAddressFamilyRegistry safiReg;
58 private final AddressFamilyRegistry afiReg;
60 SimpleNlriRegistry(final AddressFamilyRegistry afiReg, final SubsequentAddressFamilyRegistry safiReg) {
61 this.afiReg = requireNonNull(afiReg);
62 this.safiReg = requireNonNull(safiReg);
65 private static BgpTableType createKey(final Class<? extends AddressFamily> afi,
66 final Class<? extends SubsequentAddressFamily> safi) {
69 return new BgpTableTypeImpl(afi, safi);
72 synchronized Registration registerNlriSerializer(final Class<? extends DataObject> nlriClass,
73 final NlriSerializer serializer) {
74 final NlriSerializer prev = this.serializers.get(nlriClass);
75 checkState(prev == null, "Serializer already bound to class " + prev);
77 this.serializers.put(nlriClass, serializer);
79 final Object lock = this;
80 return new AbstractRegistration() {
82 protected void removeRegistration() {
84 SimpleNlriRegistry.this.serializers.remove(nlriClass);
90 synchronized Registration registerNlriParser(final Class<? extends AddressFamily> afi,
91 final Class<? extends SubsequentAddressFamily> safi, final NlriParser parser,
92 final NextHopParserSerializer nextHopSerializer, final Class<? extends CNextHop> cnextHopClass,
93 final Class<? extends CNextHop>... cnextHopClassList) {
94 final BgpTableType key = createKey(afi, safi);
95 final NlriParser prev = this.handlers.get(key);
96 checkState(prev == null, "AFI/SAFI is already bound to parser " + prev);
98 this.handlers.put(key, parser);
99 this.nextHopParsers.put(key,nextHopSerializer);
101 if (cnextHopClass != null) {
102 final Entry<Class<? extends CNextHop>, BgpTableType> nhKey = new SimpleEntry<>(cnextHopClass, key);
103 this.nextHopSerializers.put(nhKey, nextHopSerializer);
104 for (final Class<? extends CNextHop> cnextHop : cnextHopClassList) {
105 final Entry<Class<? extends CNextHop>, BgpTableType> nhKeys = new SimpleEntry<>(cnextHop, key);
106 this.nextHopSerializers.put(nhKeys, nextHopSerializer);
110 final Object lock = this;
111 return new AbstractRegistration() {
113 protected void removeRegistration() {
114 synchronized (lock) {
115 SimpleNlriRegistry.this.handlers.remove(key);
116 SimpleNlriRegistry.this.nextHopParsers.remove(key);
117 if (cnextHopClass != null) {
118 final Entry<Class<? extends CNextHop>, BgpTableType> nhKey
119 = new SimpleEntry<>(cnextHopClass, key);
120 SimpleNlriRegistry.this.nextHopSerializers.remove(nhKey);
121 for (final Class<? extends CNextHop> cnextHop : cnextHopClassList) {
122 final Entry<Class<? extends CNextHop>, BgpTableType> nhKeys
123 = new SimpleEntry<>(cnextHop, key);
124 SimpleNlriRegistry.this.nextHopSerializers.remove(nhKeys);
132 private Class<? extends AddressFamily> getAfi(final ByteBuf buffer) throws BGPParsingException {
133 final int afiVal = buffer.readUnsignedShort();
134 final Class<? extends AddressFamily> afi = this.afiReg.classForFamily(afiVal);
136 throw new BGPParsingException("Address Family Identifier: '" + afiVal + "' not supported.");
141 private Class<? extends SubsequentAddressFamily> getSafi(final ByteBuf buffer) throws BGPParsingException {
142 final int safiVal = buffer.readUnsignedByte();
143 final Class<? extends SubsequentAddressFamily> safi = this.safiReg.classForFamily(safiVal);
145 throw new BGPParsingException("Subsequent Address Family Identifier: '" + safiVal + "' not supported.");
151 public MpUnreachNlri parseMpUnreach(final ByteBuf buffer, final PeerSpecificParserConstraint constraint)
152 throws BGPParsingException {
153 final MpUnreachNlriBuilder builder = new MpUnreachNlriBuilder();
154 builder.setAfi(getAfi(buffer));
155 builder.setSafi(getSafi(buffer));
157 if (buffer.isReadable()) {
158 final ByteBuf nlri = buffer.slice();
159 final BgpTableType key = createKey(builder.getAfi(), builder.getSafi());
160 final NlriParser parser = this.handlers.get(key);
161 if (parser == null) {
162 LOG.warn(PARSER_NOT_FOUND, key);
164 parser.parseNlri(nlri, builder, constraint);
167 return builder.build();
171 public void serializeMpReach(final MpReachNlri mpReachNlri, final ByteBuf byteAggregator) {
172 final Class<? extends AddressFamily> afi = mpReachNlri.getAfi();
173 final Class<? extends SubsequentAddressFamily> safi = mpReachNlri.getSafi();
174 byteAggregator.writeShort(this.afiReg.numberForClass(afi));
175 byteAggregator.writeByte(this.safiReg.numberForClass(safi));
177 final CNextHop cNextHop = mpReachNlri.getCNextHop();
178 if (cNextHop != null) {
179 final Entry<Class<? extends CNextHop>, BgpTableType> key = new SimpleEntry(
180 cNextHop.implementedInterface(), new BgpTableTypeImpl(afi, safi));
181 final NextHopParserSerializer nextHopSerializer = this.nextHopSerializers.get(key);
182 final ByteBuf nextHopBuffer = Unpooled.buffer();
183 nextHopSerializer.serializeNextHop(cNextHop, nextHopBuffer);
184 byteAggregator.writeByte(nextHopBuffer.writerIndex());
185 byteAggregator.writeBytes(nextHopBuffer);
188 byteAggregator.writeByte(0);
190 byteAggregator.writeZero(RESERVED);
194 public void serializeMpUnReach(final MpUnreachNlri mpUnreachNlri, final ByteBuf byteAggregator) {
195 byteAggregator.writeShort(this.afiReg.numberForClass(mpUnreachNlri.getAfi()));
196 byteAggregator.writeByte(this.safiReg.numberForClass(mpUnreachNlri.getSafi()));
200 public Iterable<NlriSerializer> getSerializers() {
201 return Iterables.unmodifiableIterable(this.serializers.values());
205 public MpReachNlri parseMpReach(final ByteBuf buffer, final PeerSpecificParserConstraint constraint)
206 throws BGPParsingException {
207 final MpReachNlriBuilder builder = new MpReachNlriBuilder();
208 final Class<? extends AddressFamily> afi = getAfi(buffer);
209 final Class<? extends SubsequentAddressFamily> safi = getSafi(buffer);
211 builder.setSafi(safi);
213 final BgpTableType key = createKey(builder.getAfi(), builder.getSafi());
215 final int nextHopLength = buffer.readUnsignedByte();
216 if (nextHopLength != 0) {
217 final NextHopParserSerializer nextHopParser = this.nextHopParsers.get(key);
218 if (nextHopParser != null) {
219 builder.setCNextHop(nextHopParser.parseNextHop(buffer.readSlice(nextHopLength)));
221 builder.setCNextHop(NextHopUtil.parseNextHop(buffer.readSlice(nextHopLength)));
222 LOG.warn("NexHop Parser/Serializer for AFI/SAFI ({},{}) not bound",afi,safi);
225 buffer.skipBytes(RESERVED);
227 final ByteBuf nlri = buffer.slice();
228 final NlriParser parser = this.handlers.get(key);
229 if (parser == null) {
230 LOG.warn(PARSER_NOT_FOUND, key);
232 parser.parseNlri(nlri, builder, constraint);
234 return builder.build();
238 public Optional<MpUnreachNlri> convertMpReachToMpUnReach(final MpReachNlri mpReachNlri,
239 final MpUnreachNlri mpUnreachNlri) {
240 if (mpUnreachNlri == null) {
241 return Optional.of(new MpUnreachNlriBuilder()
242 .setWithdrawnRoutes(new WithdrawnRoutesBuilder()
243 .setDestinationType(mpReachNlri.getAdvertizedRoutes().getDestinationType())
248 final BgpTableType key = createKey(mpUnreachNlri.getAfi(), mpUnreachNlri.getSafi());
249 final NlriParser parser = this.handlers.get(key);
250 if (parser == null) {
251 LOG.debug("Parser for {} not found", key);
252 return Optional.empty();
255 final MpUnreachNlriBuilder builder = new MpUnreachNlriBuilder(mpUnreachNlri);
256 return parser.convertMpReachToMpUnReach(mpReachNlri, builder) ? Optional.of(builder.build()) : Optional.empty();