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