2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.protocol.bmp.impl.app;
10 import static org.opendaylight.protocol.bmp.impl.app.TablesUtil.BMP_ATTRIBUTES_QNAME;
12 import com.google.common.collect.ImmutableMap;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.MoreExecutors;
15 import java.util.ArrayList;
16 import java.util.List;
19 import java.util.stream.Collectors;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTree;
22 import org.opendaylight.mdsal.common.api.CommitInfo;
23 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
24 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
25 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
26 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.ipv4.prefixes.DestinationIpv4Builder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.ipv4.prefixes.destination.ipv4.Ipv4Prefixes;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.ipv4.prefixes.destination.ipv4.Ipv4PrefixesBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationIpv4CaseBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.UpdateMessage;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.AttributesReach;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.AttributesUnreach;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.reach.MpReachNlri;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.reach.MpReachNlriBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.reach.mp.reach.nlri.AdvertizedRoutesBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.unreach.MpUnreachNlri;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.unreach.MpUnreachNlriBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.unreach.mp.unreach.nlri.WithdrawnRoutesBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.Ipv4AddressFamily;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.UnicastSubsequentAddressFamily;
43 import org.opendaylight.yangtools.yang.common.QName;
44 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
45 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
46 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
47 import org.opendaylight.yangtools.yang.data.spi.node.ImmutableNodes;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
51 final class BmpRibInWriter {
52 private static final Logger LOG = LoggerFactory.getLogger(BmpRibInWriter.class);
54 private static final LeafNode<Boolean> ATTRIBUTES_UPTODATE_FALSE =
55 ImmutableNodes.leafNode(QName.create(BMP_ATTRIBUTES_QNAME, "uptodate").intern(), Boolean.FALSE);
56 private static final LeafNode<Boolean> ATTRIBUTES_UPTODATE_TRUE =
57 ImmutableNodes.leafNode(ATTRIBUTES_UPTODATE_FALSE.name(), Boolean.TRUE);
59 private final DOMTransactionChain chain;
60 private final Map<TablesKey, TableContext> tables;
63 private BmpRibInWriter(final YangInstanceIdentifier tablesRoot, final DOMTransactionChain chain,
64 final RIBExtensionConsumerContext ribExtensions,
65 final Set<TablesKey> tableTypes, final BindingCodecTree tree) {
67 final DOMDataTreeWriteTransaction tx = this.chain.newWriteOnlyTransaction();
68 tables = createTableInstance(tableTypes, tablesRoot, tx, ribExtensions, tree).build();
70 LOG.debug("New RIB table {} structure installed.", tablesRoot.toString());
71 tx.commit().addCallback(new FutureCallback<CommitInfo>() {
73 public void onSuccess(final CommitInfo result) {
74 LOG.trace("Successful commit");
78 public void onFailure(final Throwable trw) {
79 LOG.error("Failed commit", trw);
81 }, MoreExecutors.directExecutor());
84 public static BmpRibInWriter create(final @NonNull YangInstanceIdentifier tablesRootPath,
85 final @NonNull DOMTransactionChain chain,
86 final @NonNull RIBExtensionConsumerContext extensions, final @NonNull Set<TablesKey> tableTypes,
87 final @NonNull BindingCodecTree tree) {
88 return new BmpRibInWriter(tablesRootPath, chain, extensions, tableTypes, tree);
92 * Write on DS Adj-RIBs-In.
94 public void onMessage(final UpdateMessage message) {
96 if (!checkEndOfRib(message)) {
97 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path
98 .attributes.Attributes attrs = message.getAttributes();
99 MpReachNlri mpReach = null;
100 if (message.getNlri() != null) {
101 mpReach = prefixesToMpReach(message);
102 } else if (attrs != null && attrs.augmentation(AttributesReach.class) != null) {
103 mpReach = attrs.augmentation(AttributesReach.class).getMpReachNlri();
105 if (mpReach != null) {
106 addRoutes(mpReach, attrs);
110 MpUnreachNlri mpUnreach = null;
111 if (message.getWithdrawnRoutes() != null) {
112 mpUnreach = prefixesToMpUnreach(message);
113 } else if (attrs != null && attrs.augmentation(AttributesUnreach.class) != null) {
114 mpUnreach = attrs.augmentation(AttributesUnreach.class).getMpUnreachNlri();
116 if (mpUnreach != null) {
117 removeRoutes(mpUnreach);
123 * Create new table instance.
125 private static ImmutableMap.Builder<TablesKey, TableContext> createTableInstance(final Set<TablesKey> tableTypes,
126 final YangInstanceIdentifier yangTableRootIId, final DOMDataTreeWriteTransaction tx,
127 final RIBExtensionConsumerContext ribExtensions, final BindingCodecTree tree) {
128 final var identityCodec = tree.getIdentityCodec();
130 final ImmutableMap.Builder<TablesKey, TableContext> tb = ImmutableMap.builder();
131 for (final TablesKey tableType : tableTypes) {
132 final var rs = ribExtensions.getRIBSupport(tableType);
134 LOG.warn("No support for table type {}, skipping it", tableType);
138 final var domTableKey = NodeIdentifierWithPredicates.of(TablesUtil.BMP_TABLES_QNAME, ImmutableMap.of(
139 TablesUtil.BMP_AFI_QNAME, identityCodec.fromBinding(tableType.getAfi()),
140 TablesUtil.BMP_SAFI_QNAME, identityCodec.fromBinding(tableType.getSafi())));
141 final TableContext ctx = new TableContext(rs, yangTableRootIId.node(domTableKey).toOptimized(), tree);
144 tx.put(LogicalDatastoreType.OPERATIONAL, ctx.getTableId().node(BMP_ATTRIBUTES_QNAME)
145 .node(ATTRIBUTES_UPTODATE_FALSE.name()), ATTRIBUTES_UPTODATE_FALSE);
146 LOG.debug("Created table instance {}", ctx.getTableId());
147 tb.put(tableType, ctx);
152 private synchronized void addRoutes(final MpReachNlri nlri, final org.opendaylight.yang.gen.v1.urn.opendaylight
153 .params.xml.ns.yang.bgp.message.rev200120.path.attributes.Attributes attributes) {
154 final TablesKey key = new TablesKey(nlri.getAfi(), nlri.getSafi());
155 final TableContext ctx = tables.get(key);
158 LOG.debug("No table for {}, not accepting NLRI {}", key, nlri);
162 final DOMDataTreeWriteTransaction tx = chain.newWriteOnlyTransaction();
163 ctx.writeRoutes(tx, nlri, attributes);
164 LOG.trace("Write routes {}", nlri);
165 tx.commit().addCallback(new FutureCallback<CommitInfo>() {
167 public void onSuccess(final CommitInfo result) {
168 LOG.trace("Successful commit");
172 public void onFailure(final Throwable trw) {
173 LOG.error("Failed commit", trw);
175 }, MoreExecutors.directExecutor());
179 * Creates MPReach for the prefixes to be handled in the same way as linkstate routes.
181 * @param message Update message containing prefixes in NLRI
182 * @return MpReachNlri with prefixes from the nlri field
184 private static MpReachNlri prefixesToMpReach(final UpdateMessage message) {
185 final List<Ipv4Prefixes> prefixes = message.getNlri().stream()
186 .map(n -> new Ipv4PrefixesBuilder().setPrefix(n.getPrefix()).setPathId(n.getPathId()).build())
187 .collect(Collectors.toList());
188 final MpReachNlriBuilder b = new MpReachNlriBuilder().setAfi(Ipv4AddressFamily.VALUE).setSafi(
189 UnicastSubsequentAddressFamily.VALUE).setAdvertizedRoutes(
190 new AdvertizedRoutesBuilder().setDestinationType(
191 new DestinationIpv4CaseBuilder().setDestinationIpv4(
192 new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build());
193 if (message.getAttributes() != null) {
194 b.setCNextHop(message.getAttributes().getCNextHop());
199 private synchronized void removeRoutes(final MpUnreachNlri nlri) {
200 final TablesKey key = new TablesKey(nlri.getAfi(), nlri.getSafi());
201 final TableContext ctx = tables.get(key);
204 LOG.debug("No table for {}, not accepting NLRI {}", key, nlri);
207 LOG.trace("Removing routes {}", nlri);
208 final DOMDataTreeWriteTransaction tx = chain.newWriteOnlyTransaction();
209 ctx.removeRoutes(tx, nlri);
210 tx.commit().addCallback(new FutureCallback<CommitInfo>() {
212 public void onSuccess(final CommitInfo result) {
213 LOG.trace("Successful commit");
217 public void onFailure(final Throwable trw) {
218 LOG.error("Failed commit", trw);
220 }, MoreExecutors.directExecutor());
224 * Create MPUnreach for the prefixes to be handled in the same way as linkstate routes.
226 * @param message Update message containing withdrawn routes
227 * @return MpUnreachNlri with prefixes from the withdrawn routes field
229 private static MpUnreachNlri prefixesToMpUnreach(final UpdateMessage message) {
230 final List<Ipv4Prefixes> prefixes = new ArrayList<>();
231 message.getWithdrawnRoutes().forEach(
232 w -> prefixes.add(new Ipv4PrefixesBuilder().setPrefix(w.getPrefix()).setPathId(w.getPathId()).build()));
233 return new MpUnreachNlriBuilder().setAfi(Ipv4AddressFamily.VALUE).setSafi(UnicastSubsequentAddressFamily.VALUE)
234 .setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(
235 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.update
236 .attributes.mp.unreach.nlri.withdrawn.routes.destination.type
237 .DestinationIpv4CaseBuilder().setDestinationIpv4(new DestinationIpv4Builder()
238 .setIpv4Prefixes(prefixes).build()).build()).build()).build();
242 * For each received Update message, the upd sync variable needs to be updated to true, for particular AFI/SAFI
243 * combination. Currently we only assume Unicast SAFI. From the Update message we have to extract the AFI. Each
244 * Update message can contain BGP Object with one type of AFI. If the object is BGP Link, BGP Node or a BGPPrefix
245 * the AFI is Linkstate. In case of BGPRoute, the AFI depends on the IP Address of the prefix.
247 * @param msg received Update message
249 private boolean checkEndOfRib(final UpdateMessage msg) {
250 TablesKey type = new TablesKey(Ipv4AddressFamily.VALUE, UnicastSubsequentAddressFamily.VALUE);
251 boolean isEOR = false;
252 if (msg.getNlri() == null && msg.getWithdrawnRoutes() == null) {
253 if (msg.getAttributes() != null) {
254 if (msg.getAttributes().augmentation(AttributesReach.class) != null) {
255 final AttributesReach pa = msg.getAttributes().augmentation(AttributesReach.class);
256 if (pa.getMpReachNlri() != null) {
257 type = new TablesKey(pa.getMpReachNlri().getAfi(), pa.getMpReachNlri().getSafi());
259 } else if (msg.getAttributes().augmentation(AttributesUnreach.class) != null) {
260 final AttributesUnreach pa = msg.getAttributes().augmentation(AttributesUnreach.class);
261 if (pa.getMpUnreachNlri() != null) {
262 type = new TablesKey(pa.getMpUnreachNlri().getAfi(), pa.getMpUnreachNlri().getSafi());
264 if (pa.getMpUnreachNlri().getWithdrawnRoutes() == null) {
265 // EOR message contains only MPUnreach attribute and no NLRI
270 // true for empty Update Message
276 markTableUptodated(type);
277 LOG.debug("BMP Synchronization finished for table {} ", type);
283 private synchronized void markTableUptodated(final TablesKey tableTypes) {
284 final DOMDataTreeWriteTransaction tx = chain.newWriteOnlyTransaction();
285 final TableContext ctxPre = tables.get(tableTypes);
286 tx.merge(LogicalDatastoreType.OPERATIONAL, ctxPre.getTableId().node(BMP_ATTRIBUTES_QNAME)
287 .node(ATTRIBUTES_UPTODATE_TRUE.name()), ATTRIBUTES_UPTODATE_TRUE);
288 tx.commit().addCallback(new FutureCallback<CommitInfo>() {
290 public void onSuccess(final CommitInfo result) {
291 LOG.trace("Successful commit");
295 public void onFailure(final Throwable trw) {
296 LOG.error("Failed commit", trw);
298 }, MoreExecutors.directExecutor());