BUG-1116: Finish up egress path API changes
[bgpcep.git] / bgp / rib-impl / src / main / java / org / opendaylight / protocol / bgp / rib / impl / RIBImpl.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.impl;
9
10 import com.google.common.base.Objects;
11 import com.google.common.base.Objects.ToStringHelper;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import com.google.common.collect.ImmutableList;
15 import com.google.common.util.concurrent.FutureCallback;
16 import com.google.common.util.concurrent.Futures;
17
18 import java.util.Collections;
19 import java.util.List;
20 import java.util.concurrent.ConcurrentHashMap;
21 import java.util.concurrent.ConcurrentMap;
22 import java.util.concurrent.ExecutionException;
23
24 import javax.annotation.concurrent.ThreadSafe;
25
26 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
27 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
28 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
29 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
30 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
31 import org.opendaylight.protocol.bgp.rib.impl.spi.AdjRIBsOut;
32 import org.opendaylight.protocol.bgp.rib.impl.spi.AdjRIBsOutRegistration;
33 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
34 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
35 import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsIn;
36 import org.opendaylight.protocol.bgp.rib.spi.BGPObjectComparator;
37 import org.opendaylight.protocol.bgp.rib.spi.Peer;
38 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
39 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Update;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.UpdateBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.Nlri;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributes;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.WithdrawnRoutes;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes1;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes2;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.destination.destination.type.DestinationIpv4CaseBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.destination.destination.type.destination.ipv4._case.DestinationIpv4Builder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlri;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlriBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlri;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlriBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRibBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRibBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.Ipv4AddressFamily;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.UnicastSubsequentAddressFamily;
69 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
72
73 @ThreadSafe
74 public final class RIBImpl extends DefaultRibReference implements AutoCloseable, RIB {
75     private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
76     private static final Update EOR = new UpdateBuilder().build();
77     private static final TablesKey IPV4_UNICAST_TABLE = new TablesKey(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
78     private final ConcurrentMap<Peer, AdjRIBsOut> ribOuts = new ConcurrentHashMap<>();
79     private final ReconnectStrategyFactory tcpStrategyFactory;
80     private final ReconnectStrategyFactory sessionStrategyFactory;
81     private final BGPObjectComparator comparator;
82     private final BGPDispatcher dispatcher;
83     private final DataBroker dps;
84     private final AsNumber localAs;
85     private final Ipv4Address bgpIdentifier;
86     private final List<BgpTableType> localTables;
87     private final RIBTables tables;
88
89     public RIBImpl(final RibId ribId, final AsNumber localAs, final Ipv4Address localBgpId, final RIBExtensionConsumerContext extensions,
90             final BGPDispatcher dispatcher, final ReconnectStrategyFactory tcpStrategyFactory,
91             final ReconnectStrategyFactory sessionStrategyFactory, final DataBroker dps, final List<BgpTableType> localTables) {
92         super(InstanceIdentifier.builder(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))).toInstance());
93         this.dps = Preconditions.checkNotNull(dps);
94         this.localAs = Preconditions.checkNotNull(localAs);
95         this.comparator = new BGPObjectComparator(localAs);
96         this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
97         this.dispatcher = Preconditions.checkNotNull(dispatcher);
98         this.sessionStrategyFactory = Preconditions.checkNotNull(sessionStrategyFactory);
99         this.tcpStrategyFactory = Preconditions.checkNotNull(tcpStrategyFactory);
100         this.localTables = ImmutableList.copyOf(localTables);
101         this.tables = new RIBTables(extensions);
102
103         LOG.debug("Instantiating RIB table {} at {}", ribId, getInstanceIdentifier());
104
105         final ReadWriteTransaction trans = dps.newReadWriteTransaction();
106         Optional<Rib> o;
107         try {
108             o = trans.read(LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier()).get();
109         } catch (InterruptedException | ExecutionException e) {
110             throw new IllegalStateException("Failed to read topology", e);
111         }
112         Preconditions.checkState(!o.isPresent(), "Data provider conflict detected on object {}", getInstanceIdentifier());
113
114         // put empty BgpRib if not exists
115         trans.merge(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.builder(BgpRib.class).build(), new BgpRibBuilder().build());
116         trans.put(LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier(), new RibBuilder().setKey(new RibKey(ribId)).setId(ribId).setLocRib(
117                 new LocRibBuilder().setTables(Collections.<Tables> emptyList()).build()).build());
118
119         for (BgpTableType t : localTables) {
120             final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
121             if (this.tables.create(trans, this, key) == null) {
122                 LOG.debug("Did not create local table for unhandled table type {}", t);
123             }
124         }
125
126         Futures.addCallback(trans.submit(), new FutureCallback<Void>() {
127             @Override
128             public void onSuccess(final Void result) {
129                 LOG.trace("Change committed successfully");
130             }
131
132             @Override
133             public void onFailure(final Throwable t) {
134                 LOG.error("Failed to initiate RIB {}", getInstanceIdentifier(), t);
135             }
136         });
137     }
138
139     synchronized void initTables(final byte[] remoteBgpId) {
140     }
141
142     @Override
143     public synchronized void updateTables(final Peer peer, final Update message) {
144         final AdjRIBsTransactionImpl trans = new AdjRIBsTransactionImpl(ribOuts, this.comparator, this.dps.newWriteOnlyTransaction());
145
146         if (!EOR.equals(message)) {
147             final WithdrawnRoutes wr = message.getWithdrawnRoutes();
148             if (wr != null) {
149                 final AdjRIBsIn<?, ?> ari = this.tables.get(IPV4_UNICAST_TABLE);
150                 if (ari != null) {
151                     ari.removeRoutes(
152                             trans,
153                             peer,
154                             new MpUnreachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class).setWithdrawnRoutes(
155                                     new WithdrawnRoutesBuilder().setDestinationType(
156                                             new DestinationIpv4CaseBuilder().setDestinationIpv4(
157                                                     new DestinationIpv4Builder().setIpv4Prefixes(wr.getWithdrawnRoutes()).build()).build()).build()).build());
158                 } else {
159                     LOG.debug("Not removing objects from unhandled IPv4 Unicast");
160                 }
161             }
162
163             final PathAttributes attrs = message.getPathAttributes();
164             if (attrs != null) {
165                 final PathAttributes2 mpu = attrs.getAugmentation(PathAttributes2.class);
166                 if (mpu != null) {
167                     final MpUnreachNlri nlri = mpu.getMpUnreachNlri();
168
169                     final AdjRIBsIn<?, ?> ari = this.tables.get(new TablesKey(nlri.getAfi(), nlri.getSafi()));
170                     if (ari != null) {
171                         ari.removeRoutes(trans, peer, nlri);
172                     } else {
173                         LOG.debug("Not removing objects from unhandled NLRI {}", nlri);
174                     }
175                 }
176             }
177
178             final Nlri ar = message.getNlri();
179             if (ar != null) {
180                 final AdjRIBsIn<?, ?> ari = this.tables.get(IPV4_UNICAST_TABLE);
181                 if (ari != null) {
182                     final MpReachNlriBuilder b = new MpReachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(
183                             UnicastSubsequentAddressFamily.class).setAdvertizedRoutes(
184                                     new AdvertizedRoutesBuilder().setDestinationType(
185                                             new DestinationIpv4CaseBuilder().setDestinationIpv4(
186                                                     new DestinationIpv4Builder().setIpv4Prefixes(ar.getNlri()).build()).build()).build());
187                     if (attrs != null) {
188                         b.setCNextHop(attrs.getCNextHop());
189                     }
190
191                     ari.addRoutes(trans, peer, b.build(), attrs);
192                 } else {
193                     LOG.debug("Not adding objects from unhandled IPv4 Unicast");
194                 }
195             }
196
197             if (attrs != null) {
198                 final PathAttributes1 mpr = attrs.getAugmentation(PathAttributes1.class);
199                 if (mpr != null) {
200                     final MpReachNlri nlri = mpr.getMpReachNlri();
201
202                     final AdjRIBsIn<?, ?> ari = this.tables.get(new TablesKey(nlri.getAfi(), nlri.getSafi()));
203                     if (ari != null) {
204                         if (message.equals(ari.endOfRib())) {
205                             ari.markUptodate(trans, peer);
206                         } else {
207                             ari.addRoutes(trans, peer, nlri, attrs);
208                         }
209                     } else {
210                         LOG.debug("Not adding objects from unhandled NLRI {}", nlri);
211                     }
212                 }
213             }
214         } else {
215             final AdjRIBsIn<?, ?> ari = this.tables.get(IPV4_UNICAST_TABLE);
216             if (ari != null) {
217                 ari.markUptodate(trans, peer);
218             } else {
219                 LOG.debug("End-of-RIB for IPv4 Unicast ignored");
220             }
221         }
222
223         Futures.addCallback(trans.commit(), new FutureCallback<Void>() {
224             @Override
225             public void onSuccess(final Void result) {
226                 LOG.debug("RIB modification successfully committed.");
227             }
228
229             @Override
230             public void onFailure(final Throwable t) {
231                 LOG.error("Failed to commit RIB modification", t);
232             }
233         });
234     }
235
236     @Override
237     public synchronized void clearTable(final Peer peer, final TablesKey key) {
238         final AdjRIBsIn<?, ?> ari = this.tables.get(key);
239         if (ari != null) {
240             final AdjRIBsTransactionImpl trans = new AdjRIBsTransactionImpl(ribOuts, comparator, this.dps.newWriteOnlyTransaction());
241             ari.clear(trans, peer);
242
243             Futures.addCallback(trans.commit(), new FutureCallback<Void>() {
244                 @Override
245                 public void onSuccess(final Void result) {
246                     LOG.trace("Table {} cleared successfully", key);
247                 }
248
249                 @Override
250                 public void onFailure(final Throwable t) {
251                     LOG.error("Failed to clear table {}", key, t);
252                 }
253             });
254         }
255     }
256
257     @Override
258     public String toString() {
259         return addToStringAttributes(Objects.toStringHelper(this)).toString();
260     }
261
262     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
263         return toStringHelper;
264     }
265
266     @Override
267     public void close() throws InterruptedException, ExecutionException {
268         final WriteTransaction t = this.dps.newWriteOnlyTransaction();
269         t.delete(LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier());
270         t.submit().get();
271     }
272
273     @Override
274     public AsNumber getLocalAs() {
275         return this.localAs;
276     }
277
278     @Override
279     public Ipv4Address getBgpIdentifier() {
280         return this.bgpIdentifier;
281     }
282
283     @Override
284     public List<? extends BgpTableType> getLocalTables() {
285         return this.localTables;
286     }
287
288     @Override
289     public ReconnectStrategyFactory getTcpStrategyFactory() {
290         return this.tcpStrategyFactory;
291     }
292
293     @Override
294     public ReconnectStrategyFactory getSessionStrategyFactory() {
295         return this.sessionStrategyFactory;
296     }
297
298     @Override
299     public BGPDispatcher getDispatcher() {
300         return this.dispatcher;
301     }
302
303     @Override
304     public void initTable(final Peer bgpPeer, final TablesKey key) {
305         // FIXME: BUG-196: support graceful restart
306     }
307
308     @Override
309     public AdjRIBsOutRegistration registerRIBsOut(final Peer peer, final AdjRIBsOut aro) {
310         final AdjRIBsOutRegistration reg = new AdjRIBsOutRegistration(aro) {
311             @Override
312             protected void removeRegistration() {
313                 ribOuts.remove(peer, aro);
314             }
315         };
316
317         ribOuts.put(peer, aro);
318         // FIXME: schedule a walk over all the tables
319         return reg;
320     }
321 }