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