Merge "Introducing method byteBufForAddress."
[bgpcep.git] / bgp / rib-spi / src / main / java / org / opendaylight / protocol / bgp / rib / spi / AbstractAdjRIBs.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.rib.spi;
9
10 import com.google.common.base.Objects;
11 import com.google.common.base.Objects.ToStringHelper;
12 import com.google.common.base.Preconditions;
13 import java.util.HashMap;
14 import java.util.Iterator;
15 import java.util.Map;
16 import java.util.Map.Entry;
17 import javax.annotation.Nullable;
18 import javax.annotation.concurrent.GuardedBy;
19 import javax.annotation.concurrent.ThreadSafe;
20 import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.PathAttributes;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Update;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.UpdateBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributesBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes1;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes1Builder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes2;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes2Builder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlriBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlriBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.Route;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
35 import org.opendaylight.yangtools.yang.binding.Identifiable;
36 import org.opendaylight.yangtools.yang.binding.Identifier;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 @ThreadSafe
43 public abstract class AbstractAdjRIBs<I, D extends Identifiable<K> & Route, K extends Identifier<D>> implements AdjRIBsIn<I, D>, RouteEncoder {
44     protected abstract static class RIBEntryData<I, D extends Identifiable<K> & Route, K extends Identifier<D>> {
45         private final PathAttributes attributes;
46         private final Peer peer;
47
48         protected RIBEntryData(final Peer peer, final PathAttributes attributes) {
49             this.attributes = Preconditions.checkNotNull(attributes);
50             this.peer = Preconditions.checkNotNull(peer);
51         }
52
53         public PathAttributes getPathAttributes() {
54             return this.attributes;
55         }
56
57         public Peer getPeer() {
58             return this.peer;
59         }
60
61         /**
62          * Create a data object given the key and target instance identifier.
63          *
64          * @param key Route key
65          * @param id Data store target identifier
66          * @return Data object to be written to the data store.
67          */
68         protected abstract D getDataObject(I key, K id);
69
70         @Override
71         public final String toString() {
72             return addToStringAttributes(Objects.toStringHelper(this)).toString();
73         }
74
75         protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
76             return toStringHelper.add("attributes", this.attributes);
77         }
78     }
79
80     private static final Logger LOG = LoggerFactory.getLogger(AbstractAdjRIBs.class);
81     private final KeyedInstanceIdentifier<Tables, TablesKey> basePath;
82     private final BgpTableType tableType;
83     private final Update eor;
84
85     @GuardedBy("this")
86     private final Map<I, RIBEntry<I, D, K>> entries = new HashMap<>();
87
88     @GuardedBy("this")
89     private final Map<Peer, Boolean> peers = new HashMap<>();
90
91     protected AbstractAdjRIBs(final KeyedInstanceIdentifier<Tables, TablesKey> basePath) {
92         this.basePath = Preconditions.checkNotNull(basePath);
93         this.tableType = new BgpTableTypeImpl(basePath.getKey().getAfi(), basePath.getKey().getSafi());
94         this.eor = new UpdateBuilder().setPathAttributes(new PathAttributesBuilder().addAugmentation(
95             PathAttributes1.class, new PathAttributes1Builder().setMpReachNlri(new MpReachNlriBuilder(this.tableType)
96                 .build()).build()).build()).build();
97     }
98
99     @Override
100     public final synchronized void clear(final AdjRIBsTransaction trans, final Peer peer) {
101         final Iterator<Entry<I, RIBEntry<I, D, K>>> i = this.entries.entrySet().iterator();
102         while (i.hasNext()) {
103             final Entry<I, RIBEntry<I, D, K>> e = i.next();
104
105             if (e.getValue().removeState(trans, peer)) {
106                 i.remove();
107             }
108         }
109
110         this.peers.remove(peer);
111         trans.setUptodate(getBasePath(), !this.peers.values().contains(Boolean.FALSE));
112     }
113
114     public final synchronized void addAllEntries(final AdjRIBsTransaction trans) {
115         for (final Entry<I, RIBEntry<I, D, K>> e : this.entries.entrySet()) {
116             final RIBEntry<I, D, K> entry = e.getValue();
117             final RIBEntryData<I, D, K> state = entry.currentState;
118             trans.advertise(this, e.getKey(), entry.name, state.peer, state.getDataObject(entry.getKey(), entry.name.getKey()));
119         }
120     }
121
122     /**
123      * Construct a datastore identifier for an entry key.
124      *
125      * @param basePath datastore base path under which the entry to be stored
126      * @param id object identifier
127      * @return Data store identifier, may not be null
128      *
129      * @deprecated Please override {@link #identifierForKey(Object)} instead. The basePath
130      *             argument is constant for a particular instance and is the one your
131      *             constructor specifies.
132      */
133     @Deprecated
134     protected abstract KeyedInstanceIdentifier<D, K> identifierForKey(InstanceIdentifier<Tables> basePath, I id);
135
136     /**
137      * Return the base path specified at construction time.
138      *
139      * @return Base path.
140      */
141     protected final KeyedInstanceIdentifier<Tables, TablesKey> getBasePath() {
142         return basePath;
143     }
144
145     /**
146      * Construct a datastore identifier for an entry key.
147      *
148      * @param id object identifier
149      * @return Data store identifier, may not be null
150      */
151     protected KeyedInstanceIdentifier<D, K> identifierForKey(final I id) {
152         return identifierForKey(getBasePath(), id);
153     }
154
155     public void addWith(final MpUnreachNlriBuilder builder, final InstanceIdentifier<?> key) {
156         this.addWithdrawal(builder, keyForIdentifier(this.routeIdentifier(key)));
157     }
158
159     /**
160      * Transform a withdrawn identifier into a the corresponding NLRI in MP_UNREACH attribute.
161      *
162      * @param id Route key
163      */
164     protected abstract void addWithdrawal(MpUnreachNlriBuilder builder, I id);
165
166     /**
167      * Creates router identifier out of instance identifier
168      * @param id instance identifier
169      * @return router identifier
170      */
171     @Nullable
172     public abstract KeyedInstanceIdentifier<D, K> routeIdentifier(InstanceIdentifier<?> id);
173
174     /**
175      * Craates route key out of instance identifier
176      * @param id instance identifier
177      * @return route key
178      */
179     public abstract I keyForIdentifier(KeyedInstanceIdentifier<D, K> id);
180
181     /**
182      * Common backend for {@link AdjRIBsIn#addRoutes()} implementations.
183      * If a new route is added, check first for its existence in Map of entries.
184      * If the route is already there, change it's state. Then check for peer in
185      * Map of peers, if it's not there, add it.
186      *
187      * @param trans Transaction context
188      * @param peer Originating peer
189      * @param id Data store instance identifier
190      * @param data Data object to be written
191      */
192     protected final synchronized void add(final AdjRIBsTransaction trans, final Peer peer, final I id, final RIBEntryData<I, D, K> data) {
193         LOG.debug("Adding state {} for {} peer {}", data, id, peer);
194
195         RIBEntry<I, D, K> e = this.entries.get(Preconditions.checkNotNull(id));
196         if (e == null) {
197             e = new RIBEntry<I, D, K>(this, id);
198             this.entries.put(id, e);
199         }
200
201         e.setState(trans, peer, data);
202         if (!this.peers.containsKey(peer)) {
203             this.peers.put(peer, Boolean.FALSE);
204             trans.setUptodate(getBasePath(), Boolean.FALSE);
205         }
206     }
207
208     /**
209      * Common backend for {@link AdjRIBsIn#removeRoutes()} implementations.
210      *
211      * @param trans Transaction context
212      * @param peer Originating peer
213      * @param id Data store instance identifier
214      */
215     protected final synchronized void remove(final AdjRIBsTransaction trans, final Peer peer, final I id) {
216         final RIBEntry<I, D, K> e = this.entries.get(id);
217         if (e != null && e.removeState(trans, peer)) {
218             LOG.debug("Removed last state, removing entry for {}", id);
219             this.entries.remove(id);
220         }
221     }
222
223     @Override
224     public final void markUptodate(final AdjRIBsTransaction trans, final Peer peer) {
225         this.peers.put(peer, Boolean.TRUE);
226         trans.setUptodate(getBasePath(), !this.peers.values().contains(Boolean.FALSE));
227     }
228
229     @Override
230     public final Update endOfRib() {
231         return this.eor;
232     }
233
234     @Override
235     public Update updateMessageFor(final Object key, final Route route) {
236         final UpdateBuilder ub = new UpdateBuilder();
237         final PathAttributesBuilder pab = new PathAttributesBuilder();
238
239         if (route != null) {
240             final MpReachNlriBuilder reach = new MpReachNlriBuilder(this.tableType);
241
242             addAdvertisement(reach, (D)route);
243             pab.fieldsFrom(route.getAttributes());
244             pab.addAugmentation(PathAttributes1.class, new PathAttributes1Builder().setMpReachNlri(reach.build()).build()).build();
245         } else {
246             final MpUnreachNlriBuilder unreach = new MpUnreachNlriBuilder(this.tableType);
247             addWithdrawal(unreach, (I)key);
248             pab.addAugmentation(PathAttributes2.class, new PathAttributes2Builder().setMpUnreachNlri(unreach.build()).build()).build();
249         }
250
251         ub.setPathAttributes(pab.build());
252         return ub.build();
253     }
254
255 }