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 javax.annotation.Nonnull;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
21 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
22 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTree;
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.rev130715.Ipv4Prefix;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.prefixes.DestinationIpv4Builder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.prefixes.destination.ipv4.Ipv4Prefixes;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.prefixes.destination.ipv4.Ipv4PrefixesBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.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.rev130919.UpdateMessage;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes1;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes2;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlri;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlriBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlri;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlriBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.Ipv4AddressFamily;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.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;
52 * Created by cgasparini on 21.5.2015.
54 final class BmpRibInWriter {
56 private static final Logger LOG = LoggerFactory.getLogger(BmpRibInWriter.class);
58 private static final LeafNode<Boolean> ATTRIBUTES_UPTODATE_FALSE = ImmutableNodes.leafNode(QName.create(BMP_ATTRIBUTES_QNAME, "uptodate"), Boolean.FALSE);
59 private static final LeafNode<Boolean> ATTRIBUTES_UPTODATE_TRUE = ImmutableNodes.leafNode(ATTRIBUTES_UPTODATE_FALSE.getNodeType(), Boolean.TRUE);
61 private final DOMTransactionChain chain;
62 private final Map<TablesKey, TableContext> tables;
65 private BmpRibInWriter(final YangInstanceIdentifier tablesRoot, final DOMTransactionChain chain, 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, @Nonnull final DOMTransactionChain chain,
76 @Nonnull final RIBExtensionConsumerContext extensions, @Nonnull final Set<TablesKey> tableTypes,
77 @Nonnull final BindingCodecTree tree) {
78 return new BmpRibInWriter(tablesRootPath, chain, extensions, tableTypes, tree);
82 * Write on DS Adj-RIBs-In
86 public void onMessage(final UpdateMessage message) {
88 if (!checkEndOfRib(message)) {
89 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.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
117 * @param yangTableRootIId
122 private ImmutableMap.Builder<TablesKey, TableContext> createTableInstance(final Set<TablesKey> tableTypes,
123 final YangInstanceIdentifier yangTableRootIId, final DOMDataWriteTransaction tx, final RIBExtensionConsumerContext ribExtensions,
124 final BindingCodecTree tree) {
126 final ImmutableMap.Builder<TablesKey, TableContext> tb = ImmutableMap.builder();
127 for (final TablesKey k : tableTypes) {
128 final RIBSupport rs = ribExtensions.getRIBSupport(k);
130 LOG.warn("No support for table type {}, skipping it", k);
133 final InstanceIdentifierBuilder idb = YangInstanceIdentifier.builder(yangTableRootIId);
134 final NodeIdentifierWithPredicates key = TablesUtil.toYangTablesKey(k);
135 idb.nodeWithKey(key.getNodeType(), key.getKeyValues());
136 final TableContext ctx = new TableContext(rs, idb.build(), tree);
139 tx.put(LogicalDatastoreType.OPERATIONAL, ctx.getTableId().node(BMP_ATTRIBUTES_QNAME).node(ATTRIBUTES_UPTODATE_FALSE.getNodeType()), ATTRIBUTES_UPTODATE_FALSE);
140 LOG.debug("Created table instance {}", ctx.getTableId());
146 private void addRoutes(final MpReachNlri nlri, final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang
147 .bgp.message.rev130919.path.attributes.Attributes attributes) {
148 final TablesKey key = new TablesKey(nlri.getAfi(), nlri.getSafi());
149 final TableContext ctx = this.tables.get(key);
152 LOG.debug("No table for {}, not accepting NLRI {}", key, nlri);
156 final DOMDataWriteTransaction tx = this.chain.newWriteOnlyTransaction();
157 ctx.writeRoutes(tx, nlri, attributes);
158 LOG.trace("Write routes {}", nlri);
162 private void removeRoutes(final MpUnreachNlri nlri) {
163 final TablesKey key = new TablesKey(nlri.getAfi(), nlri.getSafi());
164 final TableContext ctx = this.tables.get(key);
167 LOG.debug("No table for {}, not accepting NLRI {}", key, nlri);
170 LOG.trace("Removing routes {}", nlri);
171 final DOMDataWriteTransaction tx = this.chain.newWriteOnlyTransaction();
172 ctx.removeRoutes(tx, nlri);
177 * Creates MPReach for the prefixes to be handled in the same way as linkstate routes
179 * @param message Update message containing prefixes in NLRI
180 * @return MpReachNlri with prefixes from the nlri field
182 private MpReachNlri prefixesToMpReach(final UpdateMessage message) {
183 final List<Ipv4Prefixes> prefixes = new ArrayList<>();
184 for (final Ipv4Prefix p : message.getNlri().getNlri()) {
185 prefixes.add(new Ipv4PrefixesBuilder().setPrefix(p).build());
187 final MpReachNlriBuilder b = new MpReachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(
188 UnicastSubsequentAddressFamily.class).setAdvertizedRoutes(
189 new AdvertizedRoutesBuilder().setDestinationType(
190 new DestinationIpv4CaseBuilder().setDestinationIpv4(
191 new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build());
192 if (message.getAttributes() != null) {
193 b.setCNextHop(message.getAttributes().getCNextHop());
199 * Create MPUnreach for the prefixes to be handled in the same way as linkstate routes
201 * @param message Update message containing withdrawn routes
202 * @return MpUnreachNlri with prefixes from the withdrawn routes field
204 private MpUnreachNlri prefixesToMpUnreach(final UpdateMessage message) {
205 final List<Ipv4Prefixes> prefixes = new ArrayList<>();
206 for (final Ipv4Prefix p : message.getWithdrawnRoutes().getWithdrawnRoutes()) {
207 prefixes.add(new Ipv4PrefixesBuilder().setPrefix(p).build());
209 return new MpUnreachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class).setWithdrawnRoutes(
210 new WithdrawnRoutesBuilder().setDestinationType(
211 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationIpv4CaseBuilder().setDestinationIpv4(
212 new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build()).build();
216 * For each received Update message, the upd sync variable needs to be updated to true, for particular AFI/SAFI
217 * combination. Currently we only assume Unicast SAFI. From the Update message we have to extract the AFI. Each
218 * Update message can contain BGP Object with one type of AFI. If the object is BGP Link, BGP Node or a BGPPrefix
219 * the AFI is Linkstate. In case of BGPRoute, the AFI depends on the IP Address of the prefix.
221 * @param msg received Update message
223 private boolean checkEndOfRib(final UpdateMessage msg) {
224 TablesKey type = new TablesKey(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
225 boolean isEOR = false;
226 if (msg.getNlri() == null && msg.getWithdrawnRoutes() == null) {
227 if (msg.getAttributes() != null) {
228 if (msg.getAttributes().getAugmentation(Attributes1.class) != null) {
229 final Attributes1 pa = msg.getAttributes().getAugmentation(Attributes1.class);
230 if (pa.getMpReachNlri() != null) {
231 type = new TablesKey(pa.getMpReachNlri().getAfi(), pa.getMpReachNlri().getSafi());
233 } else if (msg.getAttributes().getAugmentation(Attributes2.class) != null) {
234 final Attributes2 pa = msg.getAttributes().getAugmentation(Attributes2.class);
235 if (pa.getMpUnreachNlri() != null) {
236 type = new TablesKey(pa.getMpUnreachNlri().getAfi(), pa.getMpUnreachNlri().getSafi());
238 if (pa.getMpUnreachNlri().getWithdrawnRoutes() == null) {
239 // EOR message contains only MPUnreach attribute and no NLRI
244 // true for empty Update Message
250 markTableUptodated(type);
251 LOG.debug("BMP Synchronization finished for table {} ", type);
257 private void markTableUptodated(final TablesKey tableTypes) {
258 final DOMDataWriteTransaction tx = this.chain.newWriteOnlyTransaction();
259 final TableContext ctxPre = this.tables.get(tableTypes);
260 tx.merge(LogicalDatastoreType.OPERATIONAL, ctxPre.getTableId().node(BMP_ATTRIBUTES_QNAME).node(ATTRIBUTES_UPTODATE_TRUE.getNodeType()),
261 ATTRIBUTES_UPTODATE_TRUE);