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
9 package org.opendaylight.protocol.bmp.impl.app;
11 import static org.opendaylight.protocol.bmp.impl.app.TablesUtil.BMP_ATTRIBUTES_QNAME;
13 import com.google.common.collect.ImmutableMap;
14 import java.util.ArrayList;
15 import java.util.List;
18 import java.util.stream.Collectors;
19 import javax.annotation.Nonnull;
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.mdsal.binding.dom.codec.api.BindingCodecTree;
24 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
25 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.ipv4.prefixes.DestinationIpv4Builder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.ipv4.prefixes.destination.ipv4.Ipv4Prefixes;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.ipv4.prefixes.destination.ipv4.Ipv4PrefixesBuilder;
29 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;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.UpdateMessage;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.Attributes1;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.Attributes2;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpReachNlri;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpReachNlriBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpUnreachNlri;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpUnreachNlriBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.Ipv4AddressFamily;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.UnicastSubsequentAddressFamily;
42 import org.opendaylight.yangtools.yang.common.QName;
43 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
44 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
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.impl.schema.ImmutableNodes;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
51 final class BmpRibInWriter {
53 private static final Logger LOG = LoggerFactory.getLogger(BmpRibInWriter.class);
55 private static final LeafNode<Boolean> ATTRIBUTES_UPTODATE_FALSE =
56 ImmutableNodes.leafNode(QName.create(BMP_ATTRIBUTES_QNAME, "uptodate"), Boolean.FALSE);
57 private static final LeafNode<Boolean> ATTRIBUTES_UPTODATE_TRUE =
58 ImmutableNodes.leafNode(ATTRIBUTES_UPTODATE_FALSE.getNodeType(), Boolean.TRUE);
60 private final DOMTransactionChain chain;
61 private final Map<TablesKey, TableContext> tables;
64 private BmpRibInWriter(final YangInstanceIdentifier tablesRoot, final DOMTransactionChain chain,
65 final RIBExtensionConsumerContext ribExtensions,
66 final Set<TablesKey> tableTypes, final BindingCodecTree tree) {
68 final DOMDataWriteTransaction tx = this.chain.newWriteOnlyTransaction();
69 this.tables = createTableInstance(tableTypes, tablesRoot, tx, ribExtensions, tree).build();
71 LOG.debug("New RIB table {} structure installed.", tablesRoot.toString());
75 public static BmpRibInWriter create(@Nonnull final YangInstanceIdentifier tablesRootPath,
76 @Nonnull final DOMTransactionChain chain,
77 @Nonnull final RIBExtensionConsumerContext extensions, @Nonnull final Set<TablesKey> tableTypes,
78 @Nonnull final BindingCodecTree tree) {
79 return new BmpRibInWriter(tablesRootPath, chain, extensions, tableTypes, tree);
83 * Write on DS Adj-RIBs-In.
85 public void onMessage(final UpdateMessage message) {
87 if (!checkEndOfRib(message)) {
88 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path
89 .attributes.Attributes attrs = message.getAttributes();
90 MpReachNlri mpReach = null;
91 if (message.getNlri() != null) {
92 mpReach = prefixesToMpReach(message);
93 } else if (attrs != null && attrs.getAugmentation(Attributes1.class) != null) {
94 mpReach = attrs.getAugmentation(Attributes1.class).getMpReachNlri();
96 if (mpReach != null) {
97 addRoutes(mpReach, attrs);
101 MpUnreachNlri mpUnreach = null;
102 if (message.getWithdrawnRoutes() != null) {
103 mpUnreach = prefixesToMpUnreach(message);
104 } else if (attrs != null && attrs.getAugmentation(Attributes2.class) != null) {
105 mpUnreach = attrs.getAugmentation(Attributes2.class).getMpUnreachNlri();
107 if (mpUnreach != null) {
108 removeRoutes(mpUnreach);
114 * Create new table instance.
116 private static ImmutableMap.Builder<TablesKey, TableContext> createTableInstance(final Set<TablesKey> tableTypes,
117 final YangInstanceIdentifier yangTableRootIId, final DOMDataWriteTransaction tx,
118 final RIBExtensionConsumerContext ribExtensions, final BindingCodecTree tree) {
120 final ImmutableMap.Builder<TablesKey, TableContext> tb = ImmutableMap.builder();
121 for (final TablesKey k : tableTypes) {
122 final RIBSupport rs = ribExtensions.getRIBSupport(k);
124 LOG.warn("No support for table type {}, skipping it", k);
127 final InstanceIdentifierBuilder idb = YangInstanceIdentifier.builder(yangTableRootIId);
128 final NodeIdentifierWithPredicates key = TablesUtil.toYangTablesKey(k);
129 idb.nodeWithKey(key.getNodeType(), key.getKeyValues());
130 final TableContext ctx = new TableContext(rs, idb.build(), tree);
133 tx.put(LogicalDatastoreType.OPERATIONAL, ctx.getTableId().node(BMP_ATTRIBUTES_QNAME)
134 .node(ATTRIBUTES_UPTODATE_FALSE.getNodeType()), ATTRIBUTES_UPTODATE_FALSE);
135 LOG.debug("Created table instance {}", ctx.getTableId());
141 private synchronized void addRoutes(final MpReachNlri nlri, final org.opendaylight.yang.gen.v1.urn.opendaylight
142 .params.xml.ns.yang.bgp.message.rev180329.path.attributes.Attributes attributes) {
143 final TablesKey key = new TablesKey(nlri.getAfi(), nlri.getSafi());
144 final TableContext ctx = this.tables.get(key);
147 LOG.debug("No table for {}, not accepting NLRI {}", key, nlri);
151 final DOMDataWriteTransaction tx = this.chain.newWriteOnlyTransaction();
152 ctx.writeRoutes(tx, nlri, attributes);
153 LOG.trace("Write routes {}", nlri);
157 private synchronized void removeRoutes(final MpUnreachNlri nlri) {
158 final TablesKey key = new TablesKey(nlri.getAfi(), nlri.getSafi());
159 final TableContext ctx = this.tables.get(key);
162 LOG.debug("No table for {}, not accepting NLRI {}", key, nlri);
165 LOG.trace("Removing routes {}", nlri);
166 final DOMDataWriteTransaction tx = this.chain.newWriteOnlyTransaction();
167 ctx.removeRoutes(tx, nlri);
172 * Creates MPReach for the prefixes to be handled in the same way as linkstate routes.
174 * @param message Update message containing prefixes in NLRI
175 * @return MpReachNlri with prefixes from the nlri field
177 private static MpReachNlri prefixesToMpReach(final UpdateMessage message) {
178 final List<Ipv4Prefixes> prefixes = message.getNlri().stream()
179 .map(n -> new Ipv4PrefixesBuilder().setPrefix(n.getPrefix()).setPathId(n.getPathId()).build())
180 .collect(Collectors.toList());
181 final MpReachNlriBuilder b = new MpReachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(
182 UnicastSubsequentAddressFamily.class).setAdvertizedRoutes(
183 new AdvertizedRoutesBuilder().setDestinationType(
184 new DestinationIpv4CaseBuilder().setDestinationIpv4(
185 new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build());
186 if (message.getAttributes() != null) {
187 b.setCNextHop(message.getAttributes().getCNextHop());
193 * Create MPUnreach for the prefixes to be handled in the same way as linkstate routes.
195 * @param message Update message containing withdrawn routes
196 * @return MpUnreachNlri with prefixes from the withdrawn routes field
198 private static MpUnreachNlri prefixesToMpUnreach(final UpdateMessage message) {
199 final List<Ipv4Prefixes> prefixes = new ArrayList<>();
200 message.getWithdrawnRoutes().forEach(
201 w -> prefixes.add(new Ipv4PrefixesBuilder().setPrefix(w.getPrefix()).setPathId(w.getPathId()).build()));
202 return new MpUnreachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class)
203 .setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(
204 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.update
205 .attributes.mp.unreach.nlri.withdrawn.routes.destination.type
206 .DestinationIpv4CaseBuilder().setDestinationIpv4(new DestinationIpv4Builder()
207 .setIpv4Prefixes(prefixes).build()).build()).build()).build();
211 * For each received Update message, the upd sync variable needs to be updated to true, for particular AFI/SAFI
212 * combination. Currently we only assume Unicast SAFI. From the Update message we have to extract the AFI. Each
213 * Update message can contain BGP Object with one type of AFI. If the object is BGP Link, BGP Node or a BGPPrefix
214 * the AFI is Linkstate. In case of BGPRoute, the AFI depends on the IP Address of the prefix.
216 * @param msg received Update message
218 private boolean checkEndOfRib(final UpdateMessage msg) {
219 TablesKey type = new TablesKey(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
220 boolean isEOR = false;
221 if (msg.getNlri() == null && msg.getWithdrawnRoutes() == null) {
222 if (msg.getAttributes() != null) {
223 if (msg.getAttributes().getAugmentation(Attributes1.class) != null) {
224 final Attributes1 pa = msg.getAttributes().getAugmentation(Attributes1.class);
225 if (pa.getMpReachNlri() != null) {
226 type = new TablesKey(pa.getMpReachNlri().getAfi(), pa.getMpReachNlri().getSafi());
228 } else if (msg.getAttributes().getAugmentation(Attributes2.class) != null) {
229 final Attributes2 pa = msg.getAttributes().getAugmentation(Attributes2.class);
230 if (pa.getMpUnreachNlri() != null) {
231 type = new TablesKey(pa.getMpUnreachNlri().getAfi(), pa.getMpUnreachNlri().getSafi());
233 if (pa.getMpUnreachNlri().getWithdrawnRoutes() == null) {
234 // EOR message contains only MPUnreach attribute and no NLRI
239 // true for empty Update Message
245 markTableUptodated(type);
246 LOG.debug("BMP Synchronization finished for table {} ", type);
252 private synchronized void markTableUptodated(final TablesKey tableTypes) {
253 final DOMDataWriteTransaction tx = this.chain.newWriteOnlyTransaction();
254 final TableContext ctxPre = this.tables.get(tableTypes);
255 tx.merge(LogicalDatastoreType.OPERATIONAL, ctxPre.getTableId().node(BMP_ATTRIBUTES_QNAME)
256 .node(ATTRIBUTES_UPTODATE_TRUE.getNodeType()),
257 ATTRIBUTES_UPTODATE_TRUE);