Testtools should not be bundles
[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 java.util.concurrent.ConcurrentHashMap;
11 import java.util.concurrent.ConcurrentMap;
12
13 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
14 import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
15 import org.opendaylight.protocol.bgp.parser.spi.AddressFamilyRegistry;
16 import org.opendaylight.protocol.bgp.parser.spi.NlriParser;
17 import org.opendaylight.protocol.bgp.parser.spi.NlriRegistry;
18 import org.opendaylight.protocol.bgp.parser.spi.SubsequentAddressFamilyRegistry;
19 import org.opendaylight.protocol.concepts.AbstractRegistration;
20 import org.opendaylight.protocol.util.ByteArray;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.BgpTableType;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.update.path.attributes.MpReachNlri;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.update.path.attributes.MpReachNlriBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.update.path.attributes.MpUnreachNlri;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.update.path.attributes.MpUnreachNlriBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.AddressFamily;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.SubsequentAddressFamily;
28
29 import com.google.common.base.Preconditions;
30 import com.google.common.primitives.UnsignedBytes;
31
32 final class SimpleNlriRegistry implements NlriRegistry {
33         private final ConcurrentMap<BgpTableType, NlriParser> handlers = new ConcurrentHashMap<>();
34         private final SubsequentAddressFamilyRegistry safiReg;
35         private final AddressFamilyRegistry afiReg;
36
37         public SimpleNlriRegistry(final AddressFamilyRegistry afiReg, final SubsequentAddressFamilyRegistry safiReg) {
38                 this.afiReg = Preconditions.checkNotNull(afiReg);
39                 this.safiReg = Preconditions.checkNotNull(safiReg);
40         }
41
42         private static BgpTableType createKey(final Class<? extends AddressFamily> afi,
43                         final Class<? extends SubsequentAddressFamily> safi) {
44                 Preconditions.checkNotNull(afi);
45                 Preconditions.checkNotNull(safi);
46                 return new BgpTableTypeImpl(afi, safi);
47         }
48
49         synchronized AutoCloseable registerNlriParser(final Class<? extends AddressFamily> afi,
50                         final Class<? extends SubsequentAddressFamily> safi, final NlriParser parser) {
51                 final BgpTableType key = createKey(afi, safi);
52                 final NlriParser prev = handlers.get(key);
53                 Preconditions.checkState(prev == null, "AFI/SAFI is already bound to parser " + prev);
54
55                 handlers.put(key, parser);
56                 final Object lock = this;
57                 return new AbstractRegistration() {
58                         @Override
59                         protected void removeRegistration() {
60                                 synchronized (lock) {
61                                         handlers.remove(key);
62                                 }
63                         }
64                 };
65         }
66
67         private Class<? extends AddressFamily> getAfi(final byte[] header) throws BGPParsingException {
68                 final int afiVal = UnsignedBytes.toInt(header[0]) * 256 + UnsignedBytes.toInt(header[1]);
69                 final Class<? extends AddressFamily> afi = afiReg.classForFamily(afiVal);
70                 if (afi == null) {
71                         throw new BGPParsingException("Address Family Identifier: '" + afiVal + "' not supported.");
72                 }
73
74                 return afi;
75         }
76
77         private Class<? extends SubsequentAddressFamily> getSafi(final byte[] header) throws BGPParsingException {
78                 final int safiVal = UnsignedBytes.toInt(header[2]);
79                 final Class<? extends SubsequentAddressFamily> safi = safiReg.classForFamily(safiVal);
80                 if (safi == null) {
81                         throw new BGPParsingException("Subsequent Address Family Identifier: '" + safiVal + "' not supported.");
82                 }
83
84                 return safi;
85         }
86
87         @Override
88         public MpUnreachNlri parseMpUnreach(final byte[] bytes) throws BGPParsingException {
89                 final MpUnreachNlriBuilder builder = new MpUnreachNlriBuilder();
90                 builder.setAfi(getAfi(bytes));
91                 builder.setSafi(getSafi(bytes));
92
93                 final NlriParser parser = handlers.get(createKey(builder.getAfi(), builder.getSafi()));
94                 parser.parseNlri(ByteArray.subByte(bytes, 3, bytes.length - 3), builder);
95
96                 return builder.build();
97         }
98
99         @Override
100         public MpReachNlri parseMpReach(final byte[] bytes) throws BGPParsingException {
101                 final MpReachNlriBuilder builder = new MpReachNlriBuilder();
102                 builder.setAfi(getAfi(bytes));
103                 builder.setSafi(getSafi(bytes));
104
105                 final NlriParser parser = handlers.get(createKey(builder.getAfi(), builder.getSafi()));
106
107                 final int nextHopLength = UnsignedBytes.toInt(bytes[3]);
108                 int byteOffset = 4;
109
110                 final byte[] nextHop = ByteArray.subByte(bytes, byteOffset, nextHopLength);
111                 byteOffset += nextHopLength + 1;
112
113                 final byte[] nlri = ByteArray.subByte(bytes, byteOffset, bytes.length - byteOffset);
114                 parser.parseNlri(nlri, nextHop, builder);
115
116                 return builder.build();
117         }
118 }