Bump versions by x.y.(z+1)
[bgpcep.git] / bgp / rib-impl / src / main / java / org / opendaylight / protocol / bgp / rib / impl / AdjRibOutListener.java
1 /*
2  * Copyright (c) 2015 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.Preconditions;
11 import java.util.Collection;
12 import java.util.Collections;
13 import javax.annotation.Nonnull;
14 import javax.annotation.concurrent.NotThreadSafe;
15 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
16 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener;
17 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
18 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier;
19 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
20 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
21 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Update;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.Attributes;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.peer.AdjRibOut;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
32 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
33 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38  * Instantiated for each peer and table, listens on a particular peer's adj-rib-out,
39  * performs transcoding to BA form (message) and sends it down the channel.
40  */
41 @NotThreadSafe
42 final class AdjRibOutListener implements DOMDataTreeChangeListener {
43
44     private static final Logger LOG = LoggerFactory.getLogger(AdjRibOutListener.class);
45
46     private final ChannelOutputLimiter session;
47     private final RIBSupportContextImpl context;
48     private final RIBSupport support;
49
50     private AdjRibOutListener(final TablesKey tablesKey, final YangInstanceIdentifier ribId, final DOMDataTreeChangeService service, final RIBSupportContextRegistry registry, final ChannelOutputLimiter session) {
51         this.session = Preconditions.checkNotNull(session);
52         this.context = (RIBSupportContextImpl) registry.getRIBSupportContext(tablesKey);
53         this.support = this.context.getRibSupport();
54         final YangInstanceIdentifier adjRibOutId =  ribId.node(Peer.QNAME).node(Peer.QNAME).node(AdjRibOut.QNAME).node(Tables.QNAME).node(RibSupportUtils.toYangTablesKey(tablesKey));
55         service.registerDataTreeChangeListener(new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, adjRibOutId), this);
56     }
57
58     static AdjRibOutListener create(@Nonnull final TablesKey tablesKey, @Nonnull final YangInstanceIdentifier ribId, @Nonnull final DOMDataTreeChangeService service, @Nonnull final RIBSupportContextRegistry registry, @Nonnull final ChannelOutputLimiter session) {
59         return new AdjRibOutListener(tablesKey, ribId, service, registry, session);
60     }
61
62     @Override
63     public void onDataTreeChanged(final Collection<DataTreeCandidate> changes) {
64         LOG.debug("Data change received for AdjRibOut {}", changes);
65         for (final DataTreeCandidate tc : changes) {
66             for (final DataTreeCandidateNode child : tc.getRootNode().getChildNodes()) {
67                 for (final DataTreeCandidateNode route : this.context.getRibSupport().changedRoutes(child)) {
68                     final Update update;
69
70                     switch (route.getModificationType()) {
71                     case UNMODIFIED:
72                         LOG.debug("Skipping unmodified route {}", route.getIdentifier());
73                         continue;
74                     case DELETE:
75                         // FIXME: we can batch deletions into a single batch
76                         update = withdraw((MapEntryNode) route.getDataBefore().get());
77                         break;
78                     case SUBTREE_MODIFIED:
79                     case WRITE:
80                         update = advertise((MapEntryNode) route.getDataAfter().get());
81                         break;
82                     default:
83                         LOG.warn("Ignoring unhandled modification type {}", route.getModificationType());
84                         continue;
85                     }
86
87                     LOG.debug("Writing update {}", update);
88                     this.session.write(update);
89                 }
90             }
91         }
92         this.session.flush();
93     }
94
95     private Attributes routeAttributes(final MapEntryNode route) {
96         if (LOG.isDebugEnabled()) {
97             LOG.debug("AdjRibOut parsing route {}", NormalizedNodes.toStringTree(route));
98         }
99
100         final ContainerNode advertisedAttrs = (ContainerNode) NormalizedNodes.findNode(route, this.support.routeAttributesIdentifier()).orNull();
101         return this.context.deserializeAttributes(advertisedAttrs);
102     }
103
104     private Update withdraw(final MapEntryNode route) {
105         return this.support.buildUpdate(Collections.singleton(route), Collections.<MapEntryNode>emptyList(), routeAttributes(route));
106     }
107
108     private Update advertise(final MapEntryNode route) {
109         return this.support.buildUpdate(Collections.<MapEntryNode>emptyList(), Collections.singleton(route), routeAttributes(route));
110     }
111 }