4e50ed1e5006d00e2abefc878920e252dc21ba12
[bgpcep.git] / bgp / rib-impl / src / main / java / org / opendaylight / protocol / bgp / rib / impl / ExportPolicyPeerTrackerImpl.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 static java.util.Objects.requireNonNull;
11
12 import java.util.EnumMap;
13 import java.util.HashMap;
14 import java.util.Map;
15 import java.util.Optional;
16 import java.util.function.BiConsumer;
17 import javax.annotation.concurrent.GuardedBy;
18 import javax.annotation.concurrent.ThreadSafe;
19 import org.opendaylight.protocol.bgp.rib.impl.spi.PeerExportGroupRegistry;
20 import org.opendaylight.protocol.bgp.rib.spi.ExportPolicyPeerTracker;
21 import org.opendaylight.protocol.bgp.rib.spi.PeerExportGroup;
22 import org.opendaylight.protocol.bgp.rib.spi.PeerExportGroup.PeerExporTuple;
23 import org.opendaylight.protocol.concepts.AbstractRegistration;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev171207.SendReceive;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.PeerId;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.PeerRole;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.rib.TablesKey;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 /**
34  * There is one ExportPolicyPeerTracker per table
35  * - peerTables: keep track of registered peers, the ones which support this table.
36  * - peerTables: flag indicates whether the structure of the peer has been created, and therefore it can start
37  * to be updated.
38  * - peerAddPathTables: keeps track of peer which supports Additional Path for this table and which Add Path
39  * configuration they are using.
40  * - groups: Contains peers grouped by peerRole and therefore sharing the same export policy.
41  */
42 @ThreadSafe
43 final class ExportPolicyPeerTrackerImpl implements ExportPolicyPeerTracker {
44     private static final Logger LOG = LoggerFactory.getLogger(ExportPolicyPeerTrackerImpl.class);
45     @GuardedBy("this")
46     private final Map<YangInstanceIdentifier, PeerRole> peerRoles = new HashMap<>();
47     @GuardedBy("this")
48     private final Map<PeerId, SendReceive> peerAddPathTables = new HashMap<>();
49     @GuardedBy("this")
50     private final Map<PeerId, Boolean> peerTables = new HashMap<>();
51     private final PolicyDatabase policyDatabase;
52     private final TablesKey localTableKey;
53     @GuardedBy("this")
54     private final Map<PeerRole, PeerExportGroupRegistry> groups = new EnumMap<>(PeerRole.class);
55
56     ExportPolicyPeerTrackerImpl(final PolicyDatabase policyDatabase, final TablesKey localTablesKey) {
57         this.policyDatabase = requireNonNull(policyDatabase);
58         this.localTableKey = localTablesKey;
59     }
60
61     private synchronized AbstractRegistration addToExportGroups(final PeerId peerId,
62             final YangInstanceIdentifier peerPath, final PeerRole peerRole) {
63         final PeerExportGroupRegistry peerExp = this.groups.computeIfAbsent(peerRole,
64                 k -> new PeerExportGroupImpl(this.policyDatabase.exportPolicyForRole(peerRole)));
65
66         final AbstractRegistration registration = peerExp.registerPeer(peerId, new PeerExporTuple(peerPath, peerRole));
67
68         return new AbstractRegistration() {
69             @Override
70             protected void removeRegistration() {
71                 registration.close();
72                 if (ExportPolicyPeerTrackerImpl.this.groups.get(peerRole).isEmpty()) {
73                     ExportPolicyPeerTrackerImpl.this.groups.remove(peerRole);
74                 }
75             }
76         };
77     }
78
79     @Override
80     public synchronized AbstractRegistration registerPeer(final PeerId peerId, final SendReceive sendReceive,
81             final YangInstanceIdentifier peerPath, final PeerRole peerRole) {
82         if (sendReceive != null) {
83             this.peerAddPathTables.put(peerId, sendReceive);
84             LOG.debug("Supported Add BestPath table {} added to peer {}", sendReceive, peerId);
85         }
86         this.peerTables.put(peerId, false);
87         this.peerRoles.put(peerPath, peerRole);
88         LOG.debug("Supported table {} added to peer {} role {}", this.localTableKey, peerId, peerRole);
89         final AbstractRegistration registration = addToExportGroups(peerId, peerPath, peerRole);
90
91         final Object lock = this;
92         return new AbstractRegistration() {
93             @Override
94             protected void removeRegistration() {
95                 synchronized (lock) {
96                     final SendReceive sendReceiveValue = ExportPolicyPeerTrackerImpl.this.peerAddPathTables.remove(peerId);
97                     if (sendReceiveValue != null) {
98                         LOG.debug("Supported Add BestPath table {} removed to peer {}", sendReceiveValue, peerId);
99                     }
100                     ExportPolicyPeerTrackerImpl.this.peerTables.remove(peerId);
101                     LOG.debug("Removed peer {} from supported table {}", peerId, ExportPolicyPeerTrackerImpl.this.localTableKey);
102                     ExportPolicyPeerTrackerImpl.this.peerRoles.remove(peerPath);
103                     registration.close();
104                 }
105             }
106         };
107     }
108
109     @Override
110     public synchronized PeerExportGroup getPeerGroup(final PeerRole role) {
111         return this.groups.get(requireNonNull(role));
112     }
113
114     @Override
115     public synchronized boolean isTableSupported(final PeerId peerId) {
116         return this.peerTables.containsKey(peerId);
117     }
118
119     @Override
120     public synchronized PeerRole getRole(final YangInstanceIdentifier peerId) {
121         return this.peerRoles.get(peerId);
122     }
123
124     @Override
125     public synchronized boolean isAddPathSupportedByPeer(final PeerId peerId) {
126         final SendReceive sendReceive = this.peerAddPathTables.get(peerId);
127         return sendReceive != null && (sendReceive.equals(SendReceive.Both) || sendReceive.equals(SendReceive.Receive));
128     }
129
130     @Override
131     public synchronized void registerPeerAsInitialized(final PeerId peerId) {
132         this.peerTables.computeIfPresent(peerId, (k, v) -> true);
133     }
134
135     @Override
136     public synchronized boolean isTableStructureInitialized(final PeerId peerId) {
137         return this.peerTables.get(peerId);
138     }
139
140     final class PeerExportGroupImpl implements PeerExportGroupRegistry {
141         @GuardedBy("this")
142         private final Map<PeerId, PeerExporTuple> peers = new HashMap<>();
143         private final AbstractExportPolicy policy;
144
145         public PeerExportGroupImpl(final AbstractExportPolicy policy) {
146             this.policy = requireNonNull(policy);
147         }
148
149         @Override
150         public ContainerNode effectiveAttributes(final PeerRole role, final ContainerNode attributes) {
151             return attributes == null || role == null ? null : this.policy.effectiveAttributes(role, attributes);
152         }
153
154         @Override
155         public boolean containsPeer(final PeerId routePeerId) {
156             synchronized (this.peers) {
157                 return this.peers.containsKey(routePeerId);
158             }
159         }
160
161         @Override
162         public void forEach(final BiConsumer<PeerId, YangInstanceIdentifier> action) {
163             synchronized (ExportPolicyPeerTrackerImpl.this) {
164                 synchronized (this.peers) {
165                     for (final Map.Entry<PeerId, PeerExporTuple> pid : this.peers.entrySet()) {
166                         action.accept(pid.getKey(), pid.getValue().getYii());
167                     }
168                 }
169             }
170         }
171
172         @Override
173         public AbstractRegistration registerPeer(final PeerId peerId, final PeerExporTuple peerExporTuple) {
174             synchronized (ExportPolicyPeerTrackerImpl.this) {
175                 synchronized (this.peers) {
176                     this.peers.put(peerId, peerExporTuple);
177                 }
178
179                 return new AbstractRegistration() {
180                     @Override
181                     protected void removeRegistration() {
182                         synchronized (ExportPolicyPeerTrackerImpl.this) {
183                             synchronized (PeerExportGroupImpl.this.peers) {
184                                 PeerExportGroupImpl.this.peers.remove(peerId);
185                             }
186                         }
187                     }
188                 };
189             }
190         }
191
192         @Override
193         public boolean isEmpty() {
194             synchronized (this.peers) {
195                 return this.peers.isEmpty();
196             }
197         }
198     }
199 }