2 * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. 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.netvirt.bgpmanager.thrift.client;
11 import com.google.common.annotations.VisibleForTesting;
12 import java.net.ConnectException;
13 import java.util.List;
14 import java.util.function.BooleanSupplier;
15 import java.util.function.Supplier;
16 import javax.annotation.Nullable;
17 import org.apache.thrift.TException;
18 import org.apache.thrift.protocol.TBinaryProtocol;
19 import org.apache.thrift.transport.TSocket;
20 import org.apache.thrift.transport.TTransport;
21 import org.apache.thrift.transport.TTransportException;
22 import org.opendaylight.netvirt.bgpmanager.BgpConfigurationManager;
23 import org.opendaylight.netvirt.bgpmanager.RetryOnException;
24 import org.opendaylight.netvirt.bgpmanager.thrift.gen.BgpConfigurator;
25 import org.opendaylight.netvirt.bgpmanager.thrift.gen.Routes;
26 import org.opendaylight.netvirt.bgpmanager.thrift.gen.af_afi;
27 import org.opendaylight.netvirt.bgpmanager.thrift.gen.af_safi;
28 import org.opendaylight.netvirt.bgpmanager.thrift.gen.encap_type;
29 import org.opendaylight.netvirt.bgpmanager.thrift.gen.layer_type;
30 import org.opendaylight.netvirt.bgpmanager.thrift.gen.protocol_type;
31 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.Bgp;
32 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.LayerType;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
36 public final class BgpRouter {
37 private static final Logger LOG = LoggerFactory.getLogger(BgpRouter.class);
39 private static final int THRIFT_TIMEOUT_MILLI = 10000;
40 private static final int GET_RTS_INIT = 0;
41 private static final int GET_RTS_NEXT = 1;
42 private static final int CONNECTION_TIMEOUT = 60000;
45 START, STOP, NBR, VRF, PFX, SRC, MHOP, LOG, AF, GR, MP, VRFMP, EOR, DELAY_EOR
48 private static class BgpOp {
49 static final int IGNORE = 0;
58 layer_type thriftLayerType;
59 protocol_type thriftProtocolType;
65 encap_type thriftEncapType;
77 private final BgpOp bop = new BgpOp();
78 private final Supplier<Bgp> bgpConfigSupplier;
79 private final BooleanSupplier isBGPEntityOwner;
81 private volatile TTransport transport;
82 private volatile BgpConfigurator.Client bgpClient;
83 private volatile boolean isConnected = false;
84 private volatile long startTS;
85 private volatile long connectTS;
86 private volatile long lastConnectedTS;
87 private volatile boolean configServerUpdated = false;
89 private BgpRouter(Supplier<Bgp> bgpConfigSupplier, BooleanSupplier isBGPEntityOwner) {
90 this.bgpConfigSupplier = bgpConfigSupplier;
91 this.isBGPEntityOwner = isBGPEntityOwner;
94 // private ctor FOR UNIT TESTS ONLY
95 private BgpRouter(BgpConfigurator.Client bgpClient) {
96 this(() -> null, () -> false);
97 this.bgpClient = bgpClient;
100 // FOR UNIT TESTS ONLY
102 static BgpRouter newTestingInstance(BgpConfigurator.Client bgpClient) {
103 return new BgpRouter(bgpClient);
106 public static BgpRouter newInstance(Supplier<Bgp> bgpConfigSupplier, BooleanSupplier isEntityBGPOwner) {
107 return new BgpRouter(bgpConfigSupplier, isEntityBGPOwner);
110 public TTransport getTransport() {
114 public long getLastConnectedTS() {
115 return lastConnectedTS;
118 public void setLastConnectedTS(long lastConnectedTS) {
119 this.lastConnectedTS = lastConnectedTS;
122 public long getConnectTS() {
126 public void setConnectTS(long connectTS) {
127 this.connectTS = connectTS;
130 public long getStartTS() {
134 public void setStartTS(long startTS) {
135 this.startTS = startTS;
138 public void configServerUpdated() {
139 configServerUpdated = true;
142 public synchronized void disconnect() {
145 if (transport != null) {
150 public synchronized boolean connect(String bgpHost, int bgpPort) {
151 String msgPiece = "BGP config server at " + bgpHost + ":" + bgpPort;
153 if (!BgpConfigurationManager.isValidConfigBgpHostPort(bgpHost, bgpPort)) {
154 LOG.error("Invalid config server host: {}, port: {}", bgpHost, bgpPort);
158 final int numberOfConnectRetries = 180;
159 configServerUpdated = false;
160 RetryOnException connectRetry = new RetryOnException(numberOfConnectRetries);
163 setConnectTS(System.currentTimeMillis());
165 if (!isBGPEntityOwner.getAsBoolean()) {
166 LOG.error("Non Entity BGP owner trying to connect to thrift. Returning");
170 if (configServerUpdated) {
171 LOG.error("Config server updated while connecting to server {} {}", bgpHost, bgpPort);
176 LOG.error("Trying to connect BGP config server at {} : {}", bgpHost, bgpPort);
177 TSocket ts = new TSocket(bgpHost, bgpPort, CONNECTION_TIMEOUT);
180 ts.setTimeout(THRIFT_TIMEOUT_MILLI);
182 setLastConnectedTS(System.currentTimeMillis());
183 LOG.error("Connected to BGP config server at {} : {}", bgpHost, bgpPort);
185 } catch (TTransportException tte) {
186 LOG.debug("Failed connecting to BGP config server at {} : {}. msg: {}; Exception :",
187 bgpHost, bgpPort, msgPiece, tte);
188 if (tte.getCause() instanceof ConnectException) {
189 LOG.debug("Connect exception. Failed connecting to BGP config server at {} : {}. "
190 + "msg: {}; Exception :", bgpHost, bgpPort, msgPiece, tte);
191 connectRetry.errorOccured();
193 //In Case of other exceptions we try only 3 times
194 connectRetry.errorOccured(60);
197 } while (connectRetry.shouldRetry());
199 if (!connectRetry.shouldRetry()) {
204 bgpClient = new BgpConfigurator.Client(new TBinaryProtocol(transport));
205 LOG.info("Connected to " + msgPiece);
209 public boolean isBgpConnected() {
213 private void dispatch(BgpOp op) throws TException, BgpRouterException {
215 dispatchInternal(op);
216 } catch (TTransportException tte) {
217 LOG.error("dispatch command to qthriftd failed, command: {}, exception:", op.toString(), tte);
219 dispatchInternal(op);
223 private void reConnect(TTransportException tte) {
224 Bgp bgpConfig = bgpConfigSupplier.get();
225 if (bgpConfig != null) {
226 LOG.error("Received TTransportException, while configuring qthriftd, goind for Disconnect/Connect "
227 + " Host: {}, Port: {}", bgpConfig.getConfigServer().getHost().getValue(),
228 bgpConfig.getConfigServer().getPort().intValue());
232 } catch (InterruptedException e) {
233 LOG.error("Exception wile reconnecting ", e);
235 connect(bgpConfig.getConfigServer().getHost().getValue(),
236 bgpConfig.getConfigServer().getPort().intValue());
238 LOG.error("Unable to send commands to thrift and fetch bgp configuration", tte);
242 private void dispatchInternal(BgpOp op) throws TException, BgpRouterException {
245 if (bgpClient == null) {
246 throw new BgpRouterException(BgpRouterException.BGP_ERR_NOT_INITED);
249 if (op.type == null) {
250 LOG.error("dispatchInternal called with op.type null", new Throwable("stack trace"));
254 af_afi afi = af_afi.findByValue(op.ints[0]);
255 af_safi safi = af_safi.findByValue(op.ints[1]);
259 setStartTS(System.currentTimeMillis());
260 LOG.debug("startBgp thrift call for AsId {}", op.asNumber);
261 result = bgpClient.startBgp(op.asNumber, op.strs[0],
262 BgpOp.IGNORE, BgpOp.IGNORE, BgpOp.IGNORE, op.ints[0], op.add);
263 LOG.debug("Result of startBgp thrift call for AsId {} : {}", op.asNumber, result);
266 result = bgpClient.stopBgp(op.asNumber);
270 result = bgpClient.createPeer(op.strs[0], op.asNumber);
271 if (result == 0 && op.strs[1] != null) { // createPeer worked and password is specified
272 result = bgpClient.setPeerSecret(op.strs[0], op.strs[1]);
274 throw new BgpRouterException(BgpRouterException.Function.SET_PEER_SECRET, result);
278 result = bgpClient.deletePeer(op.strs[0]);
283 ? bgpClient.addVrf(op.thriftLayerType, op.strs[0], op.irts, op.erts, op.afi, op.safi)
284 : bgpClient.delVrf(op.strs[0], op.afi, op.safi);
287 // order of args is different in addPrefix(), hence the
288 // seeming out-of-order-ness of string indices
289 afi = af_afi.findByValue(org.opendaylight.netvirt.bgpmanager.BgpUtil
290 .getAFItranslatedfromPrefix(op.strs[1]));
292 ? bgpClient.pushRoute(
293 op.thriftProtocolType,
306 : bgpClient.withdrawRoute(
307 op.thriftProtocolType,
316 result = bgpClient.setLogConfig(op.strs[0], op.strs[1]);
320 ? bgpClient.setEbgpMultihop(op.strs[0], op.ints[0])
321 : bgpClient.unsetEbgpMultihop(op.strs[0]);
325 ? bgpClient.setUpdateSource(op.strs[0], op.strs[1])
326 : bgpClient.unsetUpdateSource(op.strs[0]);
330 ? bgpClient.enableAddressFamily(op.strs[0], afi, safi)
331 : bgpClient.disableAddressFamily(op.strs[0], afi, safi);
335 ? bgpClient.enableGracefulRestart(op.ints[0])
336 : bgpClient.disableGracefulRestart();
340 ? bgpClient.enableMultipath(afi, safi)
341 : bgpClient.disableMultipath(afi, safi);
344 result = bgpClient.multipaths(bop.strs[0], bop.ints[0]);
347 result = bgpClient.sendEOR();
350 bgpClient.send_enableEORDelay(op.delayEOR);
356 throw new BgpRouterException(result);
360 public synchronized void startBgp(long asNum, String rtrId, int stalepathTime, boolean announceFbit)
361 throws TException, BgpRouterException {
362 bop.type = Optype.START;
363 bop.add = announceFbit;
364 bop.asNumber = asNum;
365 bop.ints[0] = stalepathTime;
367 LOG.debug("Starting BGP with as number {} and router ID {} StalePathTime: {}", asNum, rtrId, stalepathTime);
371 public synchronized void stopBgp(long asNum)
372 throws TException, BgpRouterException {
373 bop.type = Optype.STOP;
374 bop.asNumber = asNum;
375 LOG.debug("Stopping BGP with as number {}", asNum);
379 public synchronized void addNeighbor(String nbrIp, long nbrAsNum, @Nullable String md5Secret)
380 throws TException, BgpRouterException {
381 if (md5Secret == null) {
382 LOG.debug("Adding BGP Neighbor {} with as number {} ", nbrIp, nbrAsNum);
384 LOG.debug("Adding BGP Neighbor {} with as number {} and MD5 secret {}", nbrIp, nbrAsNum, md5Secret);
386 bop.type = Optype.NBR;
389 bop.asNumber = nbrAsNum;
390 bop.strs[1] = md5Secret;
392 } // public addNeighbor( nbrIp, nbrAsNum, md5Secret )
394 public synchronized void delNeighbor(String nbrIp) throws TException, BgpRouterException {
395 bop.type = Optype.NBR;
398 LOG.debug("Deleting BGP Neighbor {} ", nbrIp);
402 public synchronized void addVrf(LayerType layerType, String rd, List<String> irts, List<String> erts,
403 long afi, long safi) throws TException, BgpRouterException {
404 bop.thriftLayerType = layerType == LayerType.LAYER2 ? layer_type.LAYER_2 : layer_type.LAYER_3;
405 bop.type = Optype.VRF;
410 LOG.debug("Adding BGP VRF rd: {} ", rd);
414 public synchronized void delVrf(String rd, long afi, long safi) throws TException, BgpRouterException {
415 bop.type = Optype.VRF;
418 bop.afi = af_afi.findByValue((int)afi);
419 bop.safi = af_safi.findByValue((int)safi);
420 LOG.debug("Deleting BGP VRF rd: {} " + rd);
424 // bit of a mess-up: the order of arguments is different in
425 // the Thrift RPC: prefix-nexthop-rd-label.
427 public synchronized void addPrefix(String rd,
433 protocol_type protocolType,
437 encap_type encapType,
439 throws TException, BgpRouterException {
440 bop.type = Optype.PFX;
443 bop.strs[1] = prefix;
444 bop.strs[2] = nexthop;
445 // TODO: set label2 or label3 based on encapsulation type and protocol type once L2label is applicable
447 if (protocolType.equals(protocol_type.PROTOCOL_EVPN) && encapType.equals(encap_type.VXLAN)) {
448 bop.l3label = l3vni; //L3VPN Over VxLan
451 bop.l3label = label; // L3VPN Over MPLSGRE
453 bop.thriftProtocolType = protocolType;
454 bop.ethernetTag = ethtag;
456 bop.macAddress = macaddress;
457 bop.thriftEncapType = encapType;
458 bop.routermac = routermac;
460 LOG.debug("Adding BGP route - rd:{} prefix:{} nexthop:{} label:{} ", rd ,prefix, nexthop, label);
464 public synchronized void delPrefix(String rd, String prefix) throws TException, BgpRouterException {
465 bop.type = Optype.PFX;
468 bop.strs[1] = prefix;
469 LOG.debug("Deleting BGP route - rd:{} prefix:{} ", rd, prefix);
473 public int initRibSync(BgpSyncHandle handle) throws BgpRouterException {
474 if (bgpClient == null) {
475 throw new BgpRouterException(BgpRouterException.BGP_ERR_NOT_INITED);
477 if (handle.getState() == BgpSyncHandle.ITERATING) {
478 return BgpRouterException.BGP_ERR_IN_ITER;
480 handle.setState(BgpSyncHandle.INITED);
484 public int endRibSync(BgpSyncHandle handle) throws BgpRouterException {
485 if (bgpClient == null) {
486 throw new BgpRouterException(BgpRouterException.BGP_ERR_NOT_INITED);
488 int state = handle.getState();
490 case BgpSyncHandle.INITED:
491 case BgpSyncHandle.ITERATING:
492 handle.setState(BgpSyncHandle.ABORTED);
494 case BgpSyncHandle.DONE:
496 case BgpSyncHandle.NEVER_DONE:
497 return BgpRouterException.BGP_ERR_NOT_ITER;
504 public Routes doRibSync(BgpSyncHandle handle, af_afi afi) throws TException, BgpRouterException {
505 if (bgpClient == null) {
506 throw new BgpRouterException(BgpRouterException.BGP_ERR_NOT_INITED);
508 int state = handle.getState();
509 if (state != BgpSyncHandle.INITED && state != BgpSyncHandle.ITERATING) {
510 Routes routes = new Routes();
511 routes.setErrcode(BgpRouterException.BGP_ERR_NOT_ITER);
514 int op = state == BgpSyncHandle.INITED ? GET_RTS_INIT : GET_RTS_NEXT;
515 handle.setState(BgpSyncHandle.ITERATING);
516 int winSize = handle.getMaxCount() * handle.getRouteSize();
519 // TODO: receive correct protocol_type here, currently populating with dummy protocol type
520 Routes outRoutes = bgpClient.getRoutes(protocol_type.PROTOCOL_ANY, op, winSize, afi);
521 if (outRoutes.more == 0) {
522 handle.setState(BgpSyncHandle.DONE);
527 public synchronized void setLogging(String fileName, String debugLevel) throws TException, BgpRouterException {
528 bop.type = Optype.LOG;
529 bop.strs[0] = fileName;
530 bop.strs[1] = debugLevel;
531 LOG.debug("Setting Log file to BGP VRF rd: {} ", fileName, debugLevel);
535 public synchronized void addEbgpMultihop(String nbrIp, int nhops) throws TException, BgpRouterException {
536 bop.type = Optype.MHOP;
540 LOG.debug("ebgp-multihop set for peer {}, num hops = {}",
545 public synchronized void delEbgpMultihop(String nbrIp) throws TException, BgpRouterException {
546 bop.type = Optype.MHOP;
549 LOG.debug("ebgp-multihop deleted for peer {}", nbrIp);
553 public synchronized void addUpdateSource(String nbrIp, String srcIp) throws TException, BgpRouterException {
554 bop.type = Optype.SRC;
558 LOG.debug("update-source added for peer {}, src-ip = {}",
563 public synchronized void delUpdateSource(String nbrIp) throws TException, BgpRouterException {
564 bop.type = Optype.SRC;
567 LOG.debug("update-source deleted for peer {}", nbrIp);
571 public synchronized void addAddressFamily(String nbrIp, af_afi afi, af_safi safi)
572 throws TException, BgpRouterException {
573 bop.type = Optype.AF;
576 bop.ints[0] = afi.getValue();
577 bop.ints[1] = safi.getValue();
578 LOG.debug("addr family added for peer {}, afi = {}, safi = {}",
579 nbrIp, bop.ints[0], bop.ints[1]);
583 public synchronized void delAddressFamily(String nbrIp, af_afi afi, af_safi safi)
584 throws TException, BgpRouterException {
585 bop.type = Optype.AF;
588 bop.ints[0] = afi.getValue();
589 bop.ints[1] = safi.getValue();
590 LOG.debug("addr family deleted for peer {}, afi = {}, safi = {}",
591 nbrIp, bop.ints[0], bop.ints[1]);
595 public synchronized void addGracefulRestart(int stalepathTime) throws TException, BgpRouterException {
596 bop.type = Optype.GR;
598 bop.ints[0] = stalepathTime;
599 LOG.debug("graceful restart added, stale-path-time = {}",
604 public synchronized void delGracefulRestart() throws TException, BgpRouterException {
605 bop.type = Optype.GR;
607 LOG.debug("graceful restart deleted");
611 public synchronized void enableMultipath(af_afi afi, af_safi safi) throws TException, BgpRouterException {
612 bop.type = Optype.MP;
614 LOG.debug("Enabling multipath for afi: " + afi.getValue() + " safi: " + safi.getValue());
615 bop.ints[0] = afi.getValue();
616 bop.ints[1] = safi.getValue();
620 public synchronized void disableMultipath(af_afi afi, af_safi safi) throws TException, BgpRouterException {
621 bop.type = Optype.MP;
623 LOG.debug("Disabling multipath for afi: " + afi.getValue() + " safi: " + safi.getValue());
624 bop.ints[0] = afi.getValue();
625 bop.ints[1] = safi.getValue();
629 public synchronized void multipaths(String rd, int maxpath) throws TException, BgpRouterException {
630 bop.type = Optype.VRFMP;
632 bop.ints[0] = maxpath;
636 public synchronized void sendEOR() throws TException, BgpRouterException {
637 bop.type = Optype.EOR;
638 LOG.debug("EOR message sent");
642 public synchronized void delayEOR(int delay) throws TException, BgpRouterException {
643 bop.type = Optype.DELAY_EOR;
644 bop.delayEOR = delay;
645 LOG.debug("EOR delay time in Seconds sent");