MVPN RFC6514 Extendend communities
[bgpcep.git] / bgp / parser-spi / src / main / java / org / opendaylight / protocol / bgp / parser / spi / pojo / SimpleAttributeRegistry.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 io.netty.buffer.ByteBuf;
14 import java.util.ArrayList;
15 import java.util.LinkedHashMap;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Map.Entry;
19 import java.util.TreeMap;
20 import java.util.concurrent.atomic.AtomicReference;
21 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
22 import org.opendaylight.protocol.bgp.parser.BGPError;
23 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
24 import org.opendaylight.protocol.bgp.parser.spi.AttributeParser;
25 import org.opendaylight.protocol.bgp.parser.spi.AttributeRegistry;
26 import org.opendaylight.protocol.bgp.parser.spi.AttributeSerializer;
27 import org.opendaylight.protocol.bgp.parser.spi.PeerSpecificParserConstraint;
28 import org.opendaylight.protocol.concepts.AbstractRegistration;
29 import org.opendaylight.protocol.concepts.HandlerRegistry;
30 import org.opendaylight.protocol.util.BitArray;
31 import org.opendaylight.protocol.util.ByteArray;
32 import org.opendaylight.protocol.util.Values;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.Attributes;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.AttributesBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.attributes.UnrecognizedAttributes;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.attributes.UnrecognizedAttributesBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.attributes.UnrecognizedAttributesKey;
38 import org.opendaylight.yangtools.yang.binding.DataContainer;
39 import org.opendaylight.yangtools.yang.binding.DataObject;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 final class SimpleAttributeRegistry implements AttributeRegistry {
44
45     private static final class RawAttribute {
46         private final AttributeParser parser;
47         private final ByteBuf buffer;
48
49         public RawAttribute(final AttributeParser parser, final ByteBuf buffer) {
50             this.parser = requireNonNull(parser);
51             this.buffer = requireNonNull(buffer);
52         }
53     }
54
55     private static final Logger LOG = LoggerFactory.getLogger(SimpleAttributeRegistry.class);
56     private static final int OPTIONAL_BIT = 0;
57     private static final int TRANSITIVE_BIT = 1;
58     private static final int PARTIAL_BIT = 2;
59     private static final int EXTENDED_LENGTH_BIT = 3;
60     private final HandlerRegistry<DataContainer, AttributeParser, AttributeSerializer> handlers = new HandlerRegistry<>();
61     private final Map<AbstractRegistration, AttributeSerializer> serializers = new LinkedHashMap<>();
62     private final AtomicReference<Iterable<AttributeSerializer>> roSerializers =
63         new AtomicReference<>(this.serializers.values());
64     private final List<UnrecognizedAttributes> unrecognizedAttributes = new ArrayList<>();
65
66
67     AutoCloseable registerAttributeParser(final int attributeType, final AttributeParser parser) {
68         Preconditions.checkArgument(attributeType >= 0 && attributeType <= Values.UNSIGNED_BYTE_MAX_VALUE);
69         return this.handlers.registerParser(attributeType, parser);
70     }
71
72     synchronized AutoCloseable registerAttributeSerializer(final Class<? extends DataObject> paramClass, final AttributeSerializer serializer) {
73         final AbstractRegistration reg = this.handlers.registerSerializer(paramClass, serializer);
74
75         this.serializers.put(reg, serializer);
76         return new AbstractRegistration() {
77             @Override
78             protected void removeRegistration() {
79                 synchronized (SimpleAttributeRegistry.this) {
80                     SimpleAttributeRegistry.this.serializers.remove(reg);
81                     SimpleAttributeRegistry.this.roSerializers.set(SimpleAttributeRegistry.this.serializers.values());
82                 }
83                 reg.close();
84             }
85         };
86     }
87
88     private void addAttribute(final ByteBuf buffer, final Map<Integer, RawAttribute> attributes)
89             throws BGPDocumentedException {
90         final BitArray flags = BitArray.valueOf(buffer.readByte());
91         final int type = buffer.readUnsignedByte();
92         final int len = (flags.get(EXTENDED_LENGTH_BIT)) ? buffer.readUnsignedShort() : buffer.readUnsignedByte();
93         if (!attributes.containsKey(type)) {
94             final AttributeParser parser = this.handlers.getParser(type);
95             if (parser == null) {
96                 processUnrecognized(flags, type, buffer, len);
97             } else {
98                 attributes.put(type, new RawAttribute(parser, buffer.readSlice(len)));
99             }
100         } else {
101             LOG.debug("Ignoring duplicate attribute type {}", type);
102         }
103     }
104
105     private void processUnrecognized(final BitArray flags, final int type, final ByteBuf buffer, final int len) throws BGPDocumentedException {
106         if (!flags.get(OPTIONAL_BIT)) {
107             throw new BGPDocumentedException("Well known attribute not recognized.", BGPError.WELL_KNOWN_ATTR_NOT_RECOGNIZED);
108         }
109         final UnrecognizedAttributes unrecognizedAttribute = new UnrecognizedAttributesBuilder()
110             .setKey(new UnrecognizedAttributesKey((short) type))
111             .setPartial(flags.get(PARTIAL_BIT))
112             .setTransitive(flags.get(TRANSITIVE_BIT))
113             .setType((short) type)
114             .setValue(ByteArray.readBytes(buffer, len)).build();
115         this.unrecognizedAttributes.add(unrecognizedAttribute);
116         LOG.debug("Unrecognized attribute were parsed: {}", unrecognizedAttribute);
117     }
118
119     @Override
120     public Attributes parseAttributes(final ByteBuf buffer, final PeerSpecificParserConstraint constraint)
121             throws BGPDocumentedException, BGPParsingException {
122         final Map<Integer, RawAttribute> attributes = new TreeMap<>();
123         while (buffer.isReadable()) {
124             addAttribute(buffer, attributes);
125         }
126         /*
127          * TreeMap guarantees that we will be invoking the parser in the order
128          * of increasing attribute type.
129          */
130         final AttributesBuilder builder = new AttributesBuilder();
131         for (final Entry<Integer, RawAttribute> e : attributes.entrySet()) {
132             LOG.debug("Parsing attribute type {}", e.getKey());
133
134             final RawAttribute a = e.getValue();
135             a.parser.parseAttribute(a.buffer, builder, constraint);
136         }
137         builder.setUnrecognizedAttributes(this.unrecognizedAttributes);
138         return builder.build();
139     }
140
141     @Override
142     public void serializeAttribute(final DataObject attribute,final ByteBuf byteAggregator) {
143         for (final AttributeSerializer serializer : this.roSerializers.get()) {
144             serializer.serializeAttribute(attribute, byteAggregator);
145         }
146     }
147 }