BGPCEP-578: Extended peer-group support
[bgpcep.git] / bgp / openconfig-state / src / main / java / org / opendaylight / protocol / bgp / state / StateProviderImpl.java
1 /*
2  * Copyright (c) 2016 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
9 package org.opendaylight.protocol.bgp.state;
10
11 import static java.util.Objects.requireNonNull;
12
13 import io.netty.util.concurrent.GlobalEventExecutor;
14 import io.netty.util.concurrent.ScheduledFuture;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Set;
20 import java.util.TimerTask;
21 import java.util.concurrent.TimeUnit;
22 import java.util.stream.Collectors;
23 import javax.annotation.Nonnull;
24 import javax.annotation.concurrent.GuardedBy;
25 import javax.annotation.concurrent.ThreadSafe;
26 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
27 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
28 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
29 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
30 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
31 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
32 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
33 import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
34 import org.opendaylight.protocol.bgp.rib.spi.state.BGPPeerState;
35 import org.opendaylight.protocol.bgp.rib.spi.state.BGPRibState;
36 import org.opendaylight.protocol.bgp.rib.spi.state.BGPStateConsumer;
37 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.Bgp;
38 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.BgpBuilder;
39 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Global;
40 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Neighbors;
41 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.PeerGroups;
42 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.NetworkInstances;
43 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstance;
44 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstanceKey;
45 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.Protocols;
46 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.Protocol;
47 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.ProtocolKey;
48 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.policy.types.rev151009.BGP;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180321.NetworkInstanceProtocol;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.bgp.rib.Rib;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.bgp.rib.RibKey;
52 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
53 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57 @ThreadSafe
58 public final class StateProviderImpl implements TransactionChainListener, AutoCloseable {
59     private static final Logger LOG = LoggerFactory.getLogger(StateProviderImpl.class);
60     private final BGPStateConsumer stateCollector;
61     private final BGPTableTypeRegistryConsumer bgpTableTypeRegistry;
62     private final KeyedInstanceIdentifier<NetworkInstance, NetworkInstanceKey> networkInstanceIId;
63     private final int timeout;
64     private final DataBroker dataBroker;
65     @GuardedBy("this")
66     private final Map<String, InstanceIdentifier<Bgp>> instanceIdentifiersCache = new HashMap<>();
67     @GuardedBy("this")
68     private BindingTransactionChain transactionChain;
69     @GuardedBy("this")
70     private ScheduledFuture<?> scheduleTask;
71
72     public StateProviderImpl(@Nonnull final DataBroker dataBroker, final int timeout,
73             @Nonnull final BGPTableTypeRegistryConsumer bgpTableTypeRegistry,
74             @Nonnull final BGPStateConsumer stateCollector,
75             @Nonnull final String networkInstanceName) {
76         this.dataBroker = requireNonNull(dataBroker);
77         this.bgpTableTypeRegistry = requireNonNull(bgpTableTypeRegistry);
78         this.stateCollector = requireNonNull(stateCollector);
79         this.networkInstanceIId = InstanceIdentifier.create(NetworkInstances.class)
80                 .child(NetworkInstance.class, new NetworkInstanceKey(networkInstanceName));
81         this.timeout = timeout;
82     }
83
84     public synchronized void init() {
85         this.transactionChain = this.dataBroker.createTransactionChain(this);
86         final TimerTask task = new TimerTask() {
87             @Override
88             @SuppressWarnings("checkstyle:IllegalCatch")
89             public void run() {
90                 synchronized (StateProviderImpl.this) {
91                     final WriteTransaction wTx = StateProviderImpl.this.transactionChain.newWriteOnlyTransaction();
92                     try {
93                         updateBGPStats(wTx);
94                     } catch (final Exception e) {
95                         LOG.warn("Failed to update BGP Stats", e);
96                     } finally {
97                         wTx.submit();
98                     }
99                 }
100             }
101         };
102
103         this.scheduleTask = GlobalEventExecutor.INSTANCE.scheduleAtFixedRate(task, 0, this.timeout,
104                 TimeUnit.SECONDS);
105     }
106
107     private synchronized void updateBGPStats(final WriteTransaction wtx) {
108         final Set<String> oldStats = new HashSet<>(this.instanceIdentifiersCache.keySet());
109         this.stateCollector.getRibStats().stream().filter(BGPRibState::isActive).forEach(bgpStateConsumer -> {
110             final KeyedInstanceIdentifier<Rib, RibKey> ribId = bgpStateConsumer.getInstanceIdentifier();
111             final List<BGPPeerState> peerStats = this.stateCollector.getPeerStats().stream()
112                     .filter(BGPPeerState::isActive).filter(peerState -> ribId.equals(peerState.getInstanceIdentifier()))
113                     .collect(Collectors.toList());
114             storeOperationalState(bgpStateConsumer, peerStats, ribId.getKey().getId().getValue(), wtx);
115             oldStats.remove(ribId.getKey().getId().getValue());
116         });
117         oldStats.forEach(ribId -> removeStoredOperationalState(ribId, wtx));
118     }
119
120     private synchronized void removeStoredOperationalState(final String ribId, final WriteTransaction wtx) {
121         final InstanceIdentifier<Bgp> bgpIID = this.instanceIdentifiersCache.remove(ribId);
122         wtx.delete(LogicalDatastoreType.OPERATIONAL, bgpIID);
123     }
124
125     private synchronized void storeOperationalState(final BGPRibState bgpStateConsumer,
126             final List<BGPPeerState> peerStats, final String ribId, final WriteTransaction wtx) {
127         final Global global = GlobalUtil.buildGlobal(bgpStateConsumer, this.bgpTableTypeRegistry);
128         final PeerGroups peerGroups = PeerGroupUtil.buildPeerGroups(peerStats);
129         final Neighbors neighbors = NeighborUtil.buildNeighbors(peerStats, this.bgpTableTypeRegistry);
130         InstanceIdentifier<Bgp> bgpIID = this.instanceIdentifiersCache.get(ribId);
131         if (bgpIID == null) {
132             final ProtocolKey protocolKey = new ProtocolKey(BGP.class, bgpStateConsumer.getInstanceIdentifier()
133                     .getKey().getId().getValue());
134             final KeyedInstanceIdentifier<Protocol, ProtocolKey> protocolIId = this.networkInstanceIId
135                     .child(Protocols.class).child(Protocol.class, protocolKey);
136             bgpIID = protocolIId.augmentation(NetworkInstanceProtocol.class).child(Bgp.class);
137             this.instanceIdentifiersCache.put(ribId, bgpIID);
138         }
139
140         final Bgp bgp = new BgpBuilder().setGlobal(global).setNeighbors(neighbors).setPeerGroups(peerGroups).build();
141         wtx.put(LogicalDatastoreType.OPERATIONAL, bgpIID, bgp, WriteTransaction.CREATE_MISSING_PARENTS);
142     }
143
144     @Override
145     public synchronized void close() throws Exception {
146         this.scheduleTask.cancel(true);
147         if (!this.instanceIdentifiersCache.keySet().isEmpty()) {
148             final WriteTransaction wTx = this.transactionChain.newWriteOnlyTransaction();
149             this.instanceIdentifiersCache.keySet().iterator()
150                     .forEachRemaining(ribId -> removeStoredOperationalState(ribId, wTx));
151             wTx.submit().get();
152         }
153         this.transactionChain.close();
154     }
155
156     @Override
157     public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction,
158             final Throwable cause) {
159         LOG.error("Transaction chain failed {}.", transaction != null ? transaction.getIdentifier() : null, cause);
160     }
161
162     @Override
163     public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
164         LOG.debug("Transaction chain {} successful.", chain);
165     }
166 }