Merge "BUG-2109 : clear BGP session after it was already initialized"
[bgpcep.git] / bgp / rib-impl / src / main / java / org / opendaylight / protocol / bgp / rib / impl / BGPPeer.java
1 /*
2  * Copyright (c) 2014 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.rib.impl;
10
11 import com.google.common.base.Objects;
12 import com.google.common.base.Objects.ToStringHelper;
13 import com.google.common.base.Preconditions;
14 import com.google.common.collect.Lists;
15 import com.google.common.net.InetAddresses;
16 import java.util.Arrays;
17 import java.util.HashSet;
18 import java.util.List;
19 import java.util.Set;
20 import javax.annotation.concurrent.GuardedBy;
21 import org.opendaylight.controller.config.yang.bgp.rib.impl.BGPPeerRuntimeMXBean;
22 import org.opendaylight.controller.config.yang.bgp.rib.impl.BGPPeerRuntimeRegistration;
23 import org.opendaylight.controller.config.yang.bgp.rib.impl.BGPPeerRuntimeRegistrator;
24 import org.opendaylight.controller.config.yang.bgp.rib.impl.BgpPeerState;
25 import org.opendaylight.controller.config.yang.bgp.rib.impl.BgpSessionState;
26 import org.opendaylight.controller.config.yang.bgp.rib.impl.RouteTable;
27 import org.opendaylight.protocol.bgp.rib.impl.spi.AdjRIBsOutRegistration;
28 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPSessionStatistics;
29 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
30 import org.opendaylight.protocol.bgp.rib.impl.spi.ReusableBGPPeer;
31 import org.opendaylight.protocol.bgp.rib.spi.BGPSession;
32 import org.opendaylight.protocol.bgp.rib.spi.BGPTerminationReason;
33 import org.opendaylight.protocol.bgp.rib.spi.Peer;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Update;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
37 import org.opendaylight.yangtools.yang.binding.Notification;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41
42 /**
43  * Class representing a peer. We have a single instance for each peer, which provides translation from BGP events into
44  * RIB actions.
45  */
46 public class BGPPeer implements ReusableBGPPeer, Peer, AutoCloseable, BGPPeerRuntimeMXBean {
47
48     private static final Logger LOG = LoggerFactory.getLogger(BGPPeer.class);
49
50     @GuardedBy("this")
51     private final Set<TablesKey> tables = new HashSet<>();
52     private final RIB rib;
53     private final String name;
54
55     @GuardedBy("this")
56     private BGPSession session;
57     @GuardedBy("this")
58     private byte[] rawIdentifier;
59     @GuardedBy("this")
60     private AdjRIBsOutRegistration reg;
61
62     private BGPPeerRuntimeRegistrator registrator;
63     private BGPPeerRuntimeRegistration runtimeReg;
64     private long sessionEstablishedCounter = 0L;
65
66     public BGPPeer(final String name, final RIB rib) {
67         this.rib = Preconditions.checkNotNull(rib);
68         this.name = name;
69     }
70
71     @Override
72     public synchronized void close() {
73         dropConnection();
74         // TODO should this perform cleanup ?
75     }
76
77     @Override
78     public void onMessage(final BGPSession session, final Notification message) {
79         if (message instanceof Update) {
80             this.rib.updateTables(this, (Update) message);
81         } else {
82             LOG.info("Ignoring unhandled message class {}", message.getClass());
83         }
84     }
85
86     @Override
87     public synchronized void onSessionUp(final BGPSession session) {
88         LOG.info("Session with peer {} went up with tables: {}", this.name, session.getAdvertisedTableTypes());
89
90         this.session = session;
91         this.rawIdentifier = InetAddresses.forString(session.getBgpId().getValue()).getAddress();
92
93         for (final BgpTableType t : session.getAdvertisedTableTypes()) {
94             final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
95
96             this.tables.add(key);
97             this.rib.initTable(this, key);
98         }
99
100         // Not particularly nice, but what can
101         if (session instanceof BGPSessionImpl) {
102             this.reg = this.rib.registerRIBsOut(this, new SessionRIBsOut((BGPSessionImpl) session));
103         }
104         this.sessionEstablishedCounter++;
105         if (this.registrator != null) {
106             this.runtimeReg = this.registrator.register(this);
107         }
108     }
109
110     private synchronized void cleanup() {
111         // FIXME: BUG-196: support graceful restart
112         for (final TablesKey key : this.tables) {
113             this.rib.clearTable(this, key);
114         }
115
116         if (this.reg != null) {
117             this.reg.close();
118             this.reg = null;
119         }
120
121         this.tables.clear();
122     }
123
124     @Override
125     public void onSessionDown(final BGPSession session, final Exception e) {
126         LOG.info("Session with peer {} went down", this.name, e);
127         releaseConnection();
128     }
129
130     @Override
131     public void onSessionTerminated(final BGPSession session, final BGPTerminationReason cause) {
132         LOG.info("Session with peer {} terminated: {}", this.name, cause);
133         releaseConnection();
134     }
135
136     @Override
137     public String toString() {
138         return addToStringAttributes(Objects.toStringHelper(this)).toString();
139     }
140
141     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
142         toStringHelper.add("name", this.name);
143         toStringHelper.add("tables", this.tables);
144         return toStringHelper;
145     }
146
147     @Override
148     public String getName() {
149         return this.name;
150     }
151
152     protected RIB getRib() {
153         return this.rib;
154     }
155
156     @Override
157     public void releaseConnection() {
158         dropConnection();
159         cleanup();
160     }
161
162     @GuardedBy("this")
163     private void dropConnection() {
164         if (this.runtimeReg != null) {
165             this.runtimeReg.close();
166             this.runtimeReg = null;
167         }
168         if (this.session != null) {
169             this.session.close();
170             this.session = null;
171         }
172     }
173
174     @Override
175     public boolean isSessionActive() {
176         return this.session != null;
177     }
178
179     @Override
180     public synchronized byte[] getRawIdentifier() {
181         return Arrays.copyOf(this.rawIdentifier, this.rawIdentifier.length);
182     }
183
184     @Override
185     public void resetSession() {
186         releaseConnection();
187     }
188
189     @Override
190     public void resetStats() {
191         if (this.session instanceof BGPSessionStatistics) {
192             ((BGPSessionStatistics) this.session).resetSessionStats();
193         }
194     }
195
196     public synchronized void registerRootRuntimeBean(final BGPPeerRuntimeRegistrator registrator) {
197         this.registrator = registrator;
198     }
199
200     @Override
201     public BgpSessionState getBgpSessionState() {
202         if (this.session instanceof BGPSessionStatistics) {
203             return ((BGPSessionStatistics) this.session).getBgpSesionState();
204         }
205         return new BgpSessionState();
206     }
207
208     @Override
209     public synchronized BgpPeerState getBgpPeerState() {
210         final BgpPeerState peerState = new BgpPeerState();
211         final List<RouteTable> routes = Lists.newArrayList();
212         for (final TablesKey tablesKey : this.tables) {
213             final RouteTable routeTable = new RouteTable();
214             routeTable.setTableType("afi=" + tablesKey.getAfi().getSimpleName() + ",safi=" + tablesKey.getSafi().getSimpleName());
215             routeTable.setRoutesCount(this.rib.getRoutesCount(tablesKey));
216             routes.add(routeTable);
217         }
218         peerState.setRouteTable(routes);
219         peerState.setSessionEstablishedCount(this.sessionEstablishedCounter);
220         return peerState;
221     }
222 }