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.bgp.rib.impl;
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.ImmutableMap;
12 import com.google.common.collect.ImmutableMap.Builder;
13 import java.util.Collection;
14 import java.util.Collections;
16 import java.util.Map.Entry;
18 import javax.annotation.Nonnull;
19 import javax.annotation.concurrent.NotThreadSafe;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
22 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
23 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
24 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.PathAttributes;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlri;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlri;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerRole;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.peer.AdjRibIn;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Attributes;
38 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
39 import org.opendaylight.yangtools.yang.common.QName;
40 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
41 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
42 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
43 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
44 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
45 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
46 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
47 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
48 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
49 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
54 * Writer of Adjacency-RIB-In for a single peer. An instance of this object
55 * is attached to each {@link BGPPeer} and {@link ApplicationPeer}.
58 final class AdjRibInWriter {
59 private static final Logger LOG = LoggerFactory.getLogger(AdjRibInWriter.class);
61 private static final LeafNode<Boolean> ATTRIBUTES_UPTODATE_FALSE = ImmutableNodes.leafNode(QName.create(Attributes.QNAME, "uptodate"), Boolean.FALSE);
62 private static final LeafNode<Boolean> ATTRIBUTES_UPTODATE_TRUE = ImmutableNodes.leafNode(ATTRIBUTES_UPTODATE_FALSE.getNodeType(), Boolean.TRUE);
63 private static final QName RIB_ID_QNAME = QName.cachedReference(QName.create(Rib.QNAME, "id"));
64 private static final QName AFI_QNAME = QName.cachedReference(QName.create(Tables.QNAME, "afi"));
65 private static final QName SAFI_QNAME = QName.cachedReference(QName.create(Tables.QNAME, "safi"));
66 private static final QName PEER_ID_QNAME = QName.cachedReference(QName.create(Peer.QNAME, "peer-id"));
67 private static final QName PEER_ROLE_QNAME = QName.cachedReference(QName.create(Peer.QNAME, "peer-role"));
68 private static final NodeIdentifier ADJRIBIN = new NodeIdentifier(AdjRibIn.QNAME);
69 private static final NodeIdentifier PEER_ID = new NodeIdentifier(PEER_ID_QNAME);
70 private static final NodeIdentifier PEER_ROLE = new NodeIdentifier(PEER_ROLE_QNAME);
71 private static final NodeIdentifier TABLES = new NodeIdentifier(Tables.QNAME);
73 // FIXME: is there a utility method to construct this?
74 private static final ContainerNode EMPTY_ADJRIBIN = Builders.containerBuilder().withNodeIdentifier(ADJRIBIN).addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build()).build();
76 private final Map<TablesKey, TableContext> tables;
77 private final YangInstanceIdentifier tablesRoot;
78 private final YangInstanceIdentifier ribPath;
79 private final DOMTransactionChain chain;
80 private final Ipv4Address peerId = null;
81 private final String role;
84 * FIXME: transaction chain has to be instantiated in caller, so it can terminate us when it fails.
86 private AdjRibInWriter(final YangInstanceIdentifier ribPath, final DOMTransactionChain chain, final String role, final YangInstanceIdentifier tablesRoot, final Map<TablesKey, TableContext> tables) {
87 this.ribPath = Preconditions.checkNotNull(ribPath);
88 this.chain = Preconditions.checkNotNull(chain);
89 this.tables = Preconditions.checkNotNull(tables);
90 this.role = Preconditions.checkNotNull(role);
91 this.tablesRoot = tablesRoot;
94 // We could use a codec, but this should be fine, too
95 private static String roleString(final PeerRole role) {
104 throw new IllegalArgumentException("Unhandled role " + role);
109 * Create a new writer using a transaction chain.
111 * @param role peer's role
112 * @param chain transaction chain
113 * @return A fresh writer instance
115 static AdjRibInWriter create(@Nonnull final RibKey key, @Nonnull final PeerRole role, @Nonnull final DOMTransactionChain chain) {
116 final InstanceIdentifierBuilder b = YangInstanceIdentifier.builder();
117 b.node(BgpRib.QNAME);
119 b.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, key.getId().getValue());
121 return new AdjRibInWriter(b.build(), chain, roleString(role), null, Collections.<TablesKey, TableContext>emptyMap());
125 * Transform this writer to a new writer, which is in charge of specified tables.
126 * Empty tables are created for new entries and old tables are deleted. Once this
127 * method returns, the old instance must not be reasonably used.
129 * @param newPeerId new peer BGP identifier
130 * @param registry RIB extension registry
131 * @param tableTypes New tables, must not be null
134 AdjRibInWriter transform(final Ipv4Address newPeerId, final RIBExtensionConsumerContext registry, final Set<TablesKey> tableTypes) {
135 final DOMDataWriteTransaction tx = chain.newWriteOnlyTransaction();
137 final YangInstanceIdentifier newTablesRoot;
138 if (!newPeerId.equals(this.peerId)) {
139 if (peerId != null) {
140 // Wipe old peer data completely
141 tx.delete(LogicalDatastoreType.OPERATIONAL, ribPath.node(Peer.QNAME).node(new NodeIdentifierWithPredicates(Peer.QNAME, PEER_ID_QNAME, peerId.getValue())));
144 // Install new empty peer structure
145 final NodeIdentifierWithPredicates peerKey = new NodeIdentifierWithPredicates(Peer.QNAME, PEER_ID_QNAME, newPeerId.getValue());
146 final YangInstanceIdentifier newPeerPath = ribPath.node(Peer.QNAME).node(peerKey);
148 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> pb = Builders.mapEntryBuilder();
149 pb.withNodeIdentifier(peerKey);
150 pb.withChild(ImmutableNodes.leafNode(PEER_ID, newPeerId.getValue()));
151 pb.withChild(ImmutableNodes.leafNode(PEER_ROLE, role));
152 pb.withChild(EMPTY_ADJRIBIN);
154 tx.put(LogicalDatastoreType.OPERATIONAL, newPeerPath, pb.build());
156 newTablesRoot = newPeerPath.node(EMPTY_ADJRIBIN.getIdentifier()).node(TABLES);
158 newTablesRoot = tablesRoot;
160 // Wipe tables which are not present in the new types
161 for (Entry<TablesKey, TableContext> e : tables.entrySet()) {
162 if (!tableTypes.contains(e.getKey())) {
163 e.getValue().removeTable(tx);
168 // Now create new table instances, potentially creating their empty entries
169 final Builder<TablesKey, TableContext> tb = ImmutableMap.builder();
170 for (TablesKey k : tableTypes) {
171 TableContext ctx = tables.get(k);
173 final RIBSupport rs = registry.getRIBSupport(k);
175 LOG.warn("No support for table type {}, skipping it", k);
179 // We will use table keys very often, make sure they are optimized
180 final InstanceIdentifierBuilder idb = YangInstanceIdentifier.builder(newTablesRoot);
182 // FIXME: use codec to translate the key
183 final Map<QName, Object> keyValues = ImmutableMap.<QName, Object>of(AFI_QNAME, BindingReflections.getQName(k.getAfi()), SAFI_QNAME, BindingReflections.getQName(k.getSafi()));
184 final NodeIdentifierWithPredicates key = new NodeIdentifierWithPredicates(Tables.QNAME, keyValues);
185 idb.nodeWithKey(key.getNodeType(), keyValues);
187 ctx = new TableContext(rs, idb.build());
190 tx.merge(LogicalDatastoreType.OPERATIONAL, ctx.getTableId().node(Attributes.QNAME).node(ATTRIBUTES_UPTODATE_FALSE.getNodeType()), ATTRIBUTES_UPTODATE_FALSE);
198 return new AdjRibInWriter(ribPath, chain, role, newTablesRoot, tb.build());
202 * Clean all routes in specified tables
204 * @param tableTypes Tables to clean.
206 void cleanTables(final Collection<TablesKey> tableTypes) {
207 final DOMDataWriteTransaction tx = chain.newWriteOnlyTransaction();
209 for (TablesKey k : tableTypes) {
210 LOG.debug("Clearing table {}", k);
211 tables.get(k).clearTable(tx);
217 void markTablesUptodate(final Collection<TablesKey> tableTypes) {
218 final DOMDataWriteTransaction tx = chain.newWriteOnlyTransaction();
220 for (TablesKey k : tableTypes) {
221 final TableContext ctx = tables.get(k);
222 tx.merge(LogicalDatastoreType.OPERATIONAL, ctx.getTableId().node(Attributes.QNAME).node(ATTRIBUTES_UPTODATE_TRUE.getNodeType()), ATTRIBUTES_UPTODATE_TRUE);
228 void updateRoutes(final MpReachNlri nlri, final PathAttributes attributes) {
229 final TablesKey key = new TablesKey(nlri.getAfi(), nlri.getSafi());
230 final TableContext ctx = tables.get(key);
232 LOG.debug("No table for {}, not accepting NLRI {}", key, nlri);
236 final DOMDataWriteTransaction tx = chain.newWriteOnlyTransaction();
237 ctx.writeRoutes(null, tx, nlri, attributes);
241 void removeRoutes(final MpUnreachNlri nlri) {
242 final TablesKey key = new TablesKey(nlri.getAfi(), nlri.getSafi());
243 final TableContext ctx = tables.get(key);
245 LOG.debug("No table for {}, not accepting NLRI {}", key, nlri);
249 final DOMDataWriteTransaction tx = chain.newWriteOnlyTransaction();
250 ctx.removeRoutes(null, tx, nlri);