/* * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.bgpmanager.thrift.client; import java.util.*; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.TException; import org.apache.thrift.transport.TSocket; import org.apache.thrift.transport.TTransport; import org.apache.thrift.transport.TTransportException; import org.opendaylight.bgpmanager.thrift.gen.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class BgpRouter { private static TTransport transport; private static TProtocol protocol; private static BgpConfigurator.Client bgpClient=null; private static final Logger LOGGER = LoggerFactory.getLogger(BgpRouter.class); private enum Optype { START, STOP, NBR, VRF, PFX, SRC, MHOP, LOG, AF, GR }; private final static int GET_RTS_INIT = 0; private final static int GET_RTS_NEXT = 1; private final static int CONNECTION_TIMEOUT = 2000; private class BgpOp { public Optype type; public boolean add; public String[] strs; public int[] ints; public List irts; public List erts; public static final int ignore = 0; public BgpOp() { strs = new String[3]; ints = new int[2]; } } private static BgpOp bop; public synchronized void disconnect() { bgpClient = null; if (transport != null) { transport.close(); } } public synchronized boolean connect(String bgpHost, int bgpPort) { String msgPiece = "BGP config server at "+bgpHost+":"+bgpPort; disconnect(); try { TSocket ts = new TSocket(bgpHost, bgpPort, CONNECTION_TIMEOUT); transport = ts; transport.open(); ts.setTimeout(0); } catch (TTransportException tte) { LOGGER.error("Failed connecting to "+msgPiece+ "; Exception: "+tte); return false; } protocol = new TBinaryProtocol(transport); bgpClient = new BgpConfigurator.Client(protocol); LOGGER.info("Connected to "+msgPiece); return true; } private BgpRouter() { bop = new BgpOp(); } private static BgpRouter br = null; public static synchronized BgpRouter getInstance() { return (br == null ? br = new BgpRouter() : br); } private void dispatch(BgpOp op) throws TException, BgpRouterException { int result = 1; if (bgpClient == null) { throw new BgpRouterException(BgpRouterException.BGP_ERR_NOT_INITED); } switch (op.type) { case START: result = bgpClient.startBgp(op.ints[0], op.strs[0], op.ignore, op.ignore, op.ignore, op.ints[1], op.add); break; case STOP: result = bgpClient.stopBgp(op.ints[0]); break; case NBR: result = bop.add ? bgpClient.createPeer(op.strs[0], op.ints[0]) : bgpClient.deletePeer(op.strs[0]); break; case VRF: result = bop.add ? bgpClient.addVrf(op.strs[0], op.irts, op.erts) : bgpClient.delVrf(op.strs[0]); break; case PFX: // order of args is different in addPrefix(), hence the // seeming out-of-order-ness of string indices result = bop.add ? bgpClient.pushRoute(op.strs[1], op.strs[2], op.strs[0], op.ints[0]) : bgpClient.withdrawRoute(op.strs[1], op.strs[0]); break; case LOG: result = bgpClient.setLogConfig(op.strs[0], op.strs[1]); break; case MHOP: result = bop.add ? bgpClient.setEbgpMultihop(op.strs[0], op.ints[0]) : bgpClient.unsetEbgpMultihop(op.strs[0]); break; case SRC: result = bop.add ? bgpClient.setUpdateSource(op.strs[0], op.strs[1]) : bgpClient.unsetUpdateSource(op.strs[0]); break; default: break; case AF: af_afi afi = af_afi.findByValue(op.ints[0]); af_safi safi = af_safi.findByValue(op.ints[1]); result = bop.add ? bgpClient.enableAddressFamily(op.strs[0], afi, safi) : bgpClient.disableAddressFamily(op.strs[0], afi, safi); break; case GR: result = bop.add ? bgpClient.enableGracefulRestart(op.ints[0]) : bgpClient.disableGracefulRestart(); break; } if (result != 0) { throw new BgpRouterException(result); } } public synchronized void startBgp(int asNum, String rtrId, int stalepathTime, boolean announceFbit) throws TException, BgpRouterException { bop.type = Optype.START; bop.add = announceFbit; bop.ints[0] = asNum; bop.ints[1] = stalepathTime; bop.strs[0] = rtrId; LOGGER.debug("Starting BGP with as number {} and router ID {} ", asNum, rtrId); dispatch(bop); } public synchronized void stopBgp(int asNum) throws TException, BgpRouterException { bop.type = Optype.STOP; bop.ints[0] = asNum; LOGGER.debug("Stopping BGP with as number {}", asNum); dispatch(bop); } public synchronized void addNeighbor(String nbrIp, int nbrAsNum) throws TException, BgpRouterException { bop.type = Optype.NBR; bop.add = true; bop.strs[0] = nbrIp; bop.ints[0] = nbrAsNum; LOGGER.debug("Adding BGP Neighbor {} with as number {} ", nbrIp, nbrAsNum); dispatch(bop); } public synchronized void delNeighbor(String nbrIp) throws TException, BgpRouterException { bop.type = Optype.NBR; bop.add = false; bop.strs[0] = nbrIp; LOGGER.debug("Deleting BGP Neighbor {} ", nbrIp); dispatch(bop); } public synchronized void addVrf(String rd, List irts, List erts) throws TException, BgpRouterException { bop.type = Optype.VRF; bop.add = true; bop.strs[0] = rd; bop.irts = irts; bop.erts = erts; LOGGER.debug("Adding BGP VRF rd: {} ", rd); dispatch(bop); } public synchronized void delVrf(String rd) throws TException, BgpRouterException { bop.type = Optype.VRF; bop.add = false; bop.strs[0] = rd; LOGGER.debug("Deleting BGP VRF rd: {} " + rd); dispatch(bop); } // bit of a mess-up: the order of arguments is different in // the Thrift RPC: prefix-nexthop-rd-label. public synchronized void addPrefix(String rd, String prefix, String nexthop, int label) throws TException, BgpRouterException { bop.type = Optype.PFX; bop.add = true; bop.strs[0] = rd; bop.strs[1] = prefix; bop.strs[2] = nexthop; bop.ints[0] = label; LOGGER.debug("Adding BGP route - rd:{} prefix:{} nexthop:{} label:{} ", rd ,prefix, nexthop, label); dispatch(bop); } public synchronized void delPrefix(String rd, String prefix) throws TException, BgpRouterException { bop.type = Optype.PFX; bop.add = false; bop.strs[0] = rd; bop.strs[1] = prefix; LOGGER.debug("Deleting BGP route - rd:{} prefix:{} ", rd, prefix); dispatch(bop); } public int initRibSync(BgpSyncHandle handle) throws TException, BgpRouterException { if (bgpClient == null) { throw new BgpRouterException(BgpRouterException.BGP_ERR_NOT_INITED); } if (handle.getState() == BgpSyncHandle.ITERATING) { return BgpRouterException.BGP_ERR_IN_ITER; } handle.setState(BgpSyncHandle.INITED); handle.setMore(1); return 0; } public int endRibSync(BgpSyncHandle handle) throws TException, BgpRouterException { if (bgpClient == null) { throw new BgpRouterException(BgpRouterException.BGP_ERR_NOT_INITED); } int state = handle.getState(); switch (state) { case BgpSyncHandle.INITED: case BgpSyncHandle.ITERATING: handle.setState(BgpSyncHandle.ABORTED); break; case BgpSyncHandle.DONE: break; case BgpSyncHandle.NEVER_DONE: return BgpRouterException.BGP_ERR_NOT_ITER; default: break; } return 0; } public Routes doRibSync(BgpSyncHandle handle) throws TException, BgpRouterException { if (bgpClient == null) { throw new BgpRouterException(BgpRouterException.BGP_ERR_NOT_INITED); } int state = handle.getState(); if (state != BgpSyncHandle.INITED && state != BgpSyncHandle.ITERATING) { Routes r = new Routes(); r.setErrcode(BgpRouterException.BGP_ERR_NOT_ITER); return r; } int op = (state == BgpSyncHandle.INITED) ? GET_RTS_INIT : GET_RTS_NEXT; handle.setState(BgpSyncHandle.ITERATING); int winSize = handle.getMaxCount()*handle.getRouteSize(); Routes outRoutes = bgpClient.getRoutes(op, winSize); if (outRoutes.errcode != 0) { return outRoutes; } handle.setMore(outRoutes.more); if (outRoutes.more == 0) { handle.setState(BgpSyncHandle.DONE); } return outRoutes; } public synchronized void setLogging(String fileName, String debugLevel) throws TException, BgpRouterException { bop.type = Optype.LOG; bop.strs[0] = fileName; bop.strs[1] = debugLevel; LOGGER.debug("Setting Log file to BGP VRF rd: {} ", fileName, debugLevel); dispatch(bop); } public synchronized void addEbgpMultihop(String nbrIp, int nhops) throws TException, BgpRouterException { bop.type = Optype.MHOP; bop.add = true; bop.strs[0] = nbrIp; bop.ints[0] = nhops; LOGGER.debug("ebgp-multihop set for peer {}, num hops = {}", nbrIp, nhops); dispatch(bop); } public synchronized void delEbgpMultihop(String nbrIp) throws TException, BgpRouterException { bop.type = Optype.MHOP; bop.add = false; bop.strs[0] = nbrIp; LOGGER.debug("ebgp-multihop deleted for peer {}", nbrIp); dispatch(bop); } public synchronized void addUpdateSource(String nbrIp, String srcIp) throws TException, BgpRouterException { bop.type = Optype.SRC; bop.add = true; bop.strs[0] = nbrIp; bop.strs[1] = srcIp; LOGGER.debug("update-source added for peer {}, src-ip = {}", nbrIp, srcIp); dispatch(bop); } public synchronized void delUpdateSource(String nbrIp) throws TException, BgpRouterException { bop.type = Optype.SRC; bop.add = false; bop.strs[0] = nbrIp; LOGGER.debug("update-source deleted for peer {}", nbrIp); dispatch(bop); } public synchronized void addAddressFamily(String nbrIp, af_afi afi, af_safi safi) throws TException, BgpRouterException { bop.type = Optype.AF; bop.add = true; bop.strs[0] = nbrIp; bop.ints[0] = afi.getValue(); bop.ints[1] = safi.getValue(); LOGGER.debug("addr family added for peer {}, afi = {}, safi = {}", nbrIp, bop.ints[0], bop.ints[1]); dispatch(bop); } public synchronized void delAddressFamily(String nbrIp, af_afi afi, af_safi safi) throws TException, BgpRouterException { bop.type = Optype.AF; bop.add = false; bop.strs[0] = nbrIp; bop.ints[0] = afi.getValue(); bop.ints[1] = safi.getValue(); LOGGER.debug("addr family deleted for peer {}, afi = {}, safi = {}", nbrIp, bop.ints[0], bop.ints[1]); dispatch(bop); } public synchronized void addGracefulRestart(int stalepathTime) throws TException, BgpRouterException { bop.type = Optype.GR; bop.add = true; bop.ints[0] = stalepathTime; LOGGER.debug("graceful restart added, stale-path-time = {}", stalepathTime); dispatch(bop); } public synchronized void delGracefulRestart() throws TException, BgpRouterException { bop.type = Optype.GR; bop.add = false; LOGGER.debug("graceful restart deleted"); dispatch(bop); } }