From: Sikhivahan Gundu Date: Wed, 13 Jan 2016 06:37:36 +0000 (+0530) Subject: Updated BgpManager for Be X-Git-Tag: release/beryllium~52^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=vpnservice.git;a=commitdiff_plain;h=46a65688345efa44e3c726ad11c1cc923878e708 Updated BgpManager for Be Change-Id: I72897c060bda94d6aff484098194e62b5813a2ab Signed-off-by: Sikhivahan Gundu --- diff --git a/bgpmanager/bgpmanager-api/src/main/java/org.opendaylight.bgpmanager.api/IBgpManager.java b/bgpmanager/bgpmanager-api/src/main/java/org.opendaylight.bgpmanager.api/IBgpManager.java index a95c198e..3ffa33f2 100644 --- a/bgpmanager/bgpmanager-api/src/main/java/org.opendaylight.bgpmanager.api/IBgpManager.java +++ b/bgpmanager/bgpmanager-api/src/main/java/org.opendaylight.bgpmanager.api/IBgpManager.java @@ -42,4 +42,13 @@ public interface IBgpManager { */ public void deletePrefix(String rd, String prefix) throws Exception; -} \ No newline at end of file + /** + * + * @param fileName + * @param logLevel + */ + public void setQbgpLog(String fileName, String logLevel) throws Exception; + + public String getDCGwIP(); + +} diff --git a/bgpmanager/bgpmanager-impl/pom.xml b/bgpmanager/bgpmanager-impl/pom.xml index 6f637d61..45dcfca4 100644 --- a/bgpmanager/bgpmanager-impl/pom.xml +++ b/bgpmanager/bgpmanager-impl/pom.xml @@ -20,6 +20,9 @@ and is available at http://www.eclipse.org/legal/epl-v10.html bgpmanager-impl ${vpnservices.version} bundle + + 3.0.1 + @@ -44,6 +47,17 @@ and is available at http://www.eclipse.org/legal/epl-v10.html 0.9.1 + + ${project.groupId} + vpnmanager-api + ${vpnservices.version} + + + ${project.groupId} + itm-api + ${vpnservices.version} + + junit @@ -69,7 +83,30 @@ and is available at http://www.eclipse.org/legal/epl-v10.html test test-jar - + + + org.apache.karaf.shell + org.apache.karaf.shell.console + 3.0.3 + + + org.slf4j + log4j + + + + + com.codahale.metrics + metrics-core + 3.0.1 + + + + com.codahale.metrics + metrics-graphite + 3.0.1 + + diff --git a/bgpmanager/bgpmanager-impl/src/main/config/default-config.xml b/bgpmanager/bgpmanager-impl/src/main/config/default-config.xml index d1a5ce52..91883d48 100644 --- a/bgpmanager/bgpmanager-impl/src/main/config/default-config.xml +++ b/bgpmanager/bgpmanager-impl/src/main/config/default-config.xml @@ -24,6 +24,10 @@ and is available at http://www.eclipse.org/legal/epl-v10.html binding:binding-broker-osgi-registry binding-osgi-broker + + itm:itm + itm + diff --git a/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/AbstractDataChangeListener.java b/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/AbstractDataChangeListener.java index e22c43d3..4fab26fb 100644 --- a/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/AbstractDataChangeListener.java +++ b/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/AbstractDataChangeListener.java @@ -5,6 +5,7 @@ * 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; import com.google.common.base.Optional; diff --git a/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/BgpConfigurationManager.java b/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/BgpConfigurationManager.java index ebd49642..e18320f8 100644 --- a/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/BgpConfigurationManager.java +++ b/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/BgpConfigurationManager.java @@ -5,328 +5,1582 @@ * 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; -import java.util.Collections; -import java.util.Map; -import java.util.Set; +import com.google.common.base.Optional; + +import java.util.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStreamReader; +import java.lang.reflect.*; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; -import org.apache.thrift.TException; -import org.opendaylight.bgpmanager.globals.BgpConfiguration; +import org.opendaylight.bgpmanager.commands.ClearBgpCli; +import org.opendaylight.bgpmanager.thrift.gen.*; +import org.opendaylight.bgpmanager.thrift.client.*; +import org.opendaylight.bgpmanager.thrift.server.*; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress; +//import org.opendaylight.vpnservice.itm.api.IITMProvider; +import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.*; +import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.bgp.*; +import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.bgp.neighbors.*; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.*; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntry; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.bgp.rev130715.BgpRouter; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.bgp.rev130715.BgpNeighbors; -import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.bgp.rev130715.bgp.neighbors.BgpNeighbor; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.List; +public class BgpConfigurationManager { + private static final Logger LOG = + LoggerFactory.getLogger(BgpConfigurationManager.class); + private static DataBroker broker; + private static FibDSWriter fib; + private boolean restarting = false; + private static Bgp config; + private static BgpRouter bgpRouter; + private static BgpThriftService updateServer; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; + private static final String DEF_LOGFILE = "/var/log/bgp_debug.log"; + private static final String DEF_LOGLEVEL = "errors"; + private static final String UPDATE_PORT = "bgp.thrift.service.port"; + private static final String CONFIG_HOST = "vpnservice.bgpspeaker.host.name"; + private static final String CONFIG_PORT = "vpnservice.bgpspeaker.thrift.port"; + private static final String DEF_UPORT = "6644"; + private static final String DEF_CHOST = "127.0.0.1"; + private static final String DEF_CPORT = "7644"; + private static final String SDNC_BGP_MIP = "sdnc_bgp_mip"; + private static final String CLUSTER_CONF_FILE = "/cluster/etc/cluster.conf"; + private static final Timer ipActivationCheckTimer = new Timer(); -public class BgpConfigurationManager { - private static final Logger LOG = LoggerFactory.getLogger(BgpConfigurationManager.class); - private ListenerRegistration listenerRegistration; - private BgpConfiguration bgpConfiguration; - private BgpManager bgpManager; - private final DataBroker broker; - private static final int MAX_RETRIES_BGP_COMMUNICATION = 1; - private enum BgpOp { - START_BGP, ADD_NGHBR, DEL_NGHBR - } - - public BgpConfigurationManager(final DataBroker db, BgpConfiguration bgpCfg, BgpManager bgpMgr) { - broker = db; - bgpConfiguration = bgpCfg; + // to have stale FIB map (RD, Prefix) + // number of seconds wait for route sync-up between ODL and BGP. + private static final int BGP_RESTART_ROUTE_SYNC_SEC = 360; + + static String odlThriftIp = "127.0.0.1"; + private static String cHostStartup; + private static String cPortStartup; + private static CountDownLatch initer = new CountDownLatch(1); + //static IITMProvider itmProvider; + public static BgpManager bgpManager; + //map> + private static Map> staledFibEntriesMap = new ConcurrentHashMap<>(); + + private static final Class[] reactors = + { + ConfigServerReactor.class, AsIdReactor.class, + GracefulRestartReactor.class, LoggingReactor.class, + NeighborsReactor.class, UpdateSourceReactor.class, + EbgpMultihopReactor.class, AddressFamiliesReactor.class, + NetworksReactor.class, VrfsReactor.class, BgpReactor.class + }; + + private ListenerRegistration[] registrations; + + private Object createListener(Class cls) { + Constructor ctor; + Object obj = null; + + try { + ctor= cls.getConstructor(BgpConfigurationManager.class); + obj = ctor.newInstance(this); + } catch (Exception e) { + LOG.error("Failed to create listener object", e); + } + return obj; + } + + private void registerCallbacks() { + String emsg = "Failed to register listener"; + registrations = (ListenerRegistration[]) + new ListenerRegistration[reactors.length]; + InstanceIdentifier iid = InstanceIdentifier.create(Bgp.class); + for (int i = 0; i < reactors.length; i++) { + DataChangeListener dcl = + (DataChangeListener) createListener(reactors[i]); + String dclName = dcl.getClass().getName(); + try { + registrations[i] = broker.registerDataChangeListener( + LogicalDatastoreType.CONFIGURATION, + iid, dcl, DataChangeScope.SUBTREE); + } catch (Exception e) { + LOG.error(emsg, e); + throw new IllegalStateException(emsg+" "+dclName, e); + } + } + } + + public void close() { + if (updateServer != null) { + updateServer.stop(); + } + } + + private boolean configExists() { + InstanceIdentifier.InstanceIdentifierBuilder iib = + InstanceIdentifier.builder(Bgp.class); + InstanceIdentifier iid = iib.build(); + Optional b = BgpUtil.read(broker, + LogicalDatastoreType.CONFIGURATION, iid); + return b.isPresent(); + } + + private String getProperty(String var, String def) { + Bundle b = FrameworkUtil.getBundle(BgpManager.class); + if (b == null) { + return def; + } + BundleContext context = b.getBundleContext(); + if (context == null) { + return def; + } + String s = context.getProperty(var); + return (s == null ? def : s); + } + + public BgpConfigurationManager(BgpManager bgpMgr) { + broker = bgpMgr.getBroker(); + fib = bgpMgr.getFibWriter(); + //itmProvider = bgpMgr.getItmProvider(); + // there must be a good way to detect that we're restarting. + // but for now infer it from the existance of config + restarting = configExists(); bgpManager = bgpMgr; - BgpRtrCfgManager rtrCfgManager = new BgpRtrCfgManager(broker); - BgpNghbrCfgManager nghbrCfgManager = new BgpNghbrCfgManager(broker); + bgpRouter = BgpRouter.getInstance(); + String uPort = getProperty(UPDATE_PORT, DEF_UPORT); + cHostStartup = getProperty(CONFIG_HOST, DEF_CHOST); + cPortStartup = getProperty(CONFIG_PORT, DEF_CPORT); + VtyshCli.setHostAddr(cHostStartup); + ClearBgpCli.setHostAddr(cHostStartup); + LOG.info("UpdateServer at localhost:"+uPort+" ConfigServer at " + +cHostStartup+":"+cPortStartup); + updateServer = new BgpThriftService(Integer.parseInt(uPort), bgpMgr); + updateServer.start(); + readOdlThriftIpForBgpCommunication(); + registerCallbacks(); + + // this shouldn't be done. config client must connect in + // response to config; but connecting at startup to a default + // host is legacy behavior. + if (!restarting) { + bgpRouter.connect(cHostStartup, Integer.parseInt(cPortStartup)); + } + LOG.info("BGP Configuration manager initialized"); + initer.countDown(); + } + + public Bgp get() { + return config; } - public class BgpRtrCfgManager extends AbstractDataChangeListener implements AutoCloseable { + private static final String addWarn = + "Config store updated; undo with Delete if needed."; + private static final String delWarn = + "Config store updated; undo with Add if needed."; + private static final String updWarn = + "Update operation not supported; Config store updated;" + +" restore with another Update if needed."; - public BgpRtrCfgManager(final DataBroker db) { - super(BgpRouter.class); - registerListener(db); + public class ConfigServerReactor + extends AbstractDataChangeListener + implements AutoCloseable { + private static final String yangObj = "config-server "; + public ConfigServerReactor() { + super(ConfigServer.class); } - private void registerListener(final DataBroker db) { + protected synchronized void + add(InstanceIdentifier iid, ConfigServer val) { + LOG.debug("received bgp connect config host {}", val.getHost().getValue()); try { - listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, - getWildCardPath(), BgpRtrCfgManager.this, DataChangeScope.SUBTREE); - } catch (final Exception e) { - LOG.error("BGP Configuration DataChange listener registration fail!", e); - throw new IllegalStateException("BGP Configuration registration Listener failed.", e); + initer.await(); + } catch (Exception e) { + } + LOG.debug("issueing bgp router connect to host {}", val.getHost().getValue()); + synchronized(BgpConfigurationManager.this) { + boolean res = bgpRouter.connect(val.getHost().getValue(), + val.getPort().intValue()); + if (!res) { + LOG.error(yangObj + "Add failed; "+addWarn); + } } } - private synchronized void removeBgpRouter(BgpRouter del) - { - bgpManager.disconnect(); + protected synchronized void + remove(InstanceIdentifier iid, ConfigServer val) { + LOG.debug("received bgp disconnect"); + synchronized(BgpConfigurationManager.this) { + bgpRouter.disconnect(); + } + } + + protected void update(InstanceIdentifier iid, + ConfigServer oldval, ConfigServer newval) { + LOG.error(yangObj + updWarn); + } - bgpConfiguration.setRouterId(""); - bgpConfiguration.setAsNum(0); + public void close() { + int i; + for (i=0 ; i < reactors.length ; i++) { + if (reactors[i] == ConfigServerReactor.class) { + break; + } + } + registrations[i].close(); + } + } + private BgpRouter getClient(String yangObj) { + if (bgpRouter == null) { + LOG.warn(yangObj+": configuration received when BGP is inactive"); } + return bgpRouter; + } - @Override - protected void remove(InstanceIdentifier identifier, - BgpRouter del) { + public class AsIdReactor + extends AbstractDataChangeListener + implements AutoCloseable { - LOG.debug("Bgp Router deleted in DS - key: {} value={} ", identifier, del); + private static final String yangObj = "as-id "; - removeBgpRouter(del); + public AsIdReactor() { + super(AsId.class); + } + + protected synchronized void + add(InstanceIdentifier iid, AsId val) { + LOG.debug("received add router config asNum {}", val.getLocalAs().intValue()); + synchronized(BgpConfigurationManager.this) { + BgpRouter br = getClient(yangObj); + if (br == null) { + return; + } + int asNum = val.getLocalAs().intValue(); + Ipv4Address routerId = val.getRouterId(); + Long spt = val.getStalepathTime(); + Boolean afb = val.isAnnounceFbit(); + String rid = (routerId == null) ? "" : routerId.getValue(); + int stalepathTime = (spt == null) ? 90 : spt.intValue(); + boolean announceFbit = (afb == null) ? false : afb.booleanValue(); + try { + br.startBgp(asNum, rid, stalepathTime, announceFbit); + if (bgpManager.getBgpCounters() == null) { + bgpManager.startBgpCountersTask(); + } + } catch (BgpRouterException bre) { + if (bre.getErrorCode() == BgpRouterException.BGP_ERR_ACTIVE) { + LOG.error(yangObj+"Add requested when BGP is already active"); + } else { + LOG.error(yangObj+"Add received exception: \"" + +bre+"\"; "+addWarn); + } + } catch (Exception e) { + LOG.error(yangObj+"Add received exception: \""+e+"\"; "+addWarn); + } + } + } + protected synchronized void + remove(InstanceIdentifier iid, AsId val) { + LOG.debug("received delete router config asNum {}", val.getLocalAs().intValue()); + synchronized(BgpConfigurationManager.this) { + BgpRouter br = getClient(yangObj); + if (br == null) { + return; + } + int asNum = val.getLocalAs().intValue(); + try { + br.stopBgp(asNum); + } catch (Exception e) { + LOG.error(yangObj+" Delete received exception: \""+e+"\"; "+delWarn); + } + if (bgpManager.getBgpCounters() != null) { + bgpManager.stopBgpCountersTask(); + } + } + } + + protected void update(InstanceIdentifier iid, + AsId oldval, AsId newval) { + LOG.error(yangObj + updWarn); } - private synchronized void updateBgpRouter(BgpRouter original, BgpRouter update) - { - if(bgpConfiguration.getAsNum() != update.getLocalAsNumber()) { - bgpConfiguration.setAsNum(update.getLocalAsNumber()); - bgpConfiguration.setConfigUpdated(); + public void close() { + int i; + for (i=0 ; i < reactors.length ; i++) { + if (reactors[i] == AsIdReactor.class) { + break; + } } - if(bgpConfiguration.getRouterId() != update.getLocalAsIdentifier().getIpv4Address().getValue()) { - bgpConfiguration.setRouterId(update.getLocalAsIdentifier().getIpv4Address().getValue()); - bgpConfiguration.setConfigUpdated(); + registrations[i].close(); + } + } + + public class GracefulRestartReactor + extends AbstractDataChangeListener + implements AutoCloseable { + + private static final String yangObj = "graceful-restart "; + + public GracefulRestartReactor() { + super(GracefulRestart.class); + } + + protected synchronized void + add(InstanceIdentifier iid, GracefulRestart val) { + synchronized(BgpConfigurationManager.this) { + BgpRouter br = getClient(yangObj); + if (br == null) { + return; + } + try { + br.addGracefulRestart(val.getStalepathTime().intValue()); + } catch (Exception e) { + LOG.error(yangObj+"Add received exception: \""+e+"\"; "+addWarn); + } } + } - if(bgpConfiguration.isConfigUpdated()) { - configureBgpServer(BgpOp.START_BGP); - bgpConfiguration.unsetConfigUpdated(); + protected synchronized void + remove(InstanceIdentifier iid, GracefulRestart val) { + LOG.debug("received delete GracefulRestart config val {}", val.getStalepathTime().intValue()); + synchronized(BgpConfigurationManager.this) { + BgpRouter br = getClient(yangObj); + if (br == null) { + return; + } + try { + br.delGracefulRestart(); + } catch (Exception e) { + LOG.error(yangObj+" Delete received exception: \""+e+"\"; " + +delWarn); + } } + } + + protected void update(InstanceIdentifier iid, + GracefulRestart oldval, GracefulRestart newval) { + LOG.debug("received update GracefulRestart config val {}", newval.getStalepathTime().intValue()); + synchronized(BgpConfigurationManager.this) { + BgpRouter br = getClient(yangObj); + if (br == null) { + return; + } + try { + br.addGracefulRestart(newval.getStalepathTime().intValue()); + } catch (Exception e) { + LOG.error(yangObj+"update received exception: \""+e+"\"; "+addWarn); + } + } + } + public void close() { + int i; + for (i=0 ; i < reactors.length ; i++) { + if (reactors[i] == GracefulRestartReactor.class) { + break; + } + } + registrations[i].close(); } + } - @Override - protected void update(InstanceIdentifier identifier, - BgpRouter original, BgpRouter update) { + public class LoggingReactor + extends AbstractDataChangeListener + implements AutoCloseable { - LOG.debug("Bgp Router Updated in DS - key: {}, original={}, update={} ", identifier, original, update); + private static final String yangObj = "logging "; - updateBgpRouter(original, update); + public LoggingReactor() { + super(Logging.class); } - private synchronized void addBgpRouter(BgpRouter value){ - if(value.getLocalAsNumber() != null) { - bgpConfiguration.setAsNum(value.getLocalAsNumber()); + protected synchronized void + add(InstanceIdentifier iid, Logging val) { + synchronized(BgpConfigurationManager.this) { + BgpRouter br = getClient(yangObj); + if (br == null) { + return; + } + try { + br.setLogging(val.getFile(),val.getLevel()); + } catch (Exception e) { + LOG.error(yangObj+"Add received exception: \""+e+"\"; " + +addWarn); + } } - if(value.getLocalAsIdentifier() != null) { - bgpConfiguration.setRouterId(value.getLocalAsIdentifier().getIpv4Address().getValue()); + } + + protected synchronized void + remove(InstanceIdentifier iid, Logging val) { + LOG.debug("received remove Logging config val {}", val.getLevel()); + synchronized(BgpConfigurationManager.this) { + BgpRouter br = getClient(yangObj); + if (br == null) { + return; + } + try { + br.setLogging(DEF_LOGFILE, DEF_LOGLEVEL); + } catch (Exception e) { + LOG.error(yangObj+" Delete received exception: \""+e+"\"; " + +delWarn); + } + } + } + + protected void update(InstanceIdentifier iid, + Logging oldval, Logging newval) { + synchronized(BgpConfigurationManager.this) { + BgpRouter br = getClient(yangObj); + if (br == null) { + return; + } + try { + br.setLogging(newval.getFile(),newval.getLevel()); + } catch (Exception e) { + LOG.error(yangObj+"newval received exception: \""+e+"\"; " + +addWarn); + } } + } - if(value.getLocalAsNumber() == null || value.getLocalAsIdentifier() == null) - return; + public void close() { + int i; + for (i=0 ; i < reactors.length ; i++) { + if (reactors[i] == LoggingReactor.class) { + break; + } + } + registrations[i].close(); + } + } + + public class NeighborsReactor + extends AbstractDataChangeListener + implements AutoCloseable { + + private static final String yangObj = "neighbors "; + + public NeighborsReactor() { + super(Neighbors.class); + } + + protected synchronized void + add(InstanceIdentifier iid, Neighbors val) { + LOG.debug("received add Neighbors config val {}", val.getAddress().getValue()); + synchronized(BgpConfigurationManager.this) { + BgpRouter br = getClient(yangObj); + if (br == null) { + return; + } + String peerIp = val.getAddress().getValue(); + int as = val.getRemoteAs().intValue(); + try { + //itmProvider.buildTunnelsToDCGW(new IpAddress(peerIp.toCharArray())); + br.addNeighbor(peerIp, as); + + } catch (Exception e) { + LOG.error(yangObj+"Add received exception: \""+e+"\"; " + +addWarn); + } + } + } - configureBgpServer(BgpOp.START_BGP); + protected synchronized void + remove(InstanceIdentifier iid, Neighbors val) { + LOG.debug("received remove Neighbors config val {}", val.getAddress().getValue()); + synchronized(BgpConfigurationManager.this) { + BgpRouter br = getClient(yangObj); + if (br == null) { + return; + } + String peerIp = val.getAddress().getValue(); + try { + //itmProvider.deleteTunnelsToDCGW(new IpAddress(val.getAddress().getValue().toCharArray())); + br.delNeighbor(peerIp); + } catch (Exception e) { + LOG.error(yangObj+" Delete received exception: \""+e+"\"; " + +delWarn); + } + } + } + + protected void update(InstanceIdentifier iid, + Neighbors oldval, Neighbors newval) { + //purposefully nothing to do. } - @Override - protected void add(InstanceIdentifier identifier, - BgpRouter value) { - LOG.debug("Bgp Router added in DS - key: {}, value={} ",identifier, value); + public void close() { + int i; + for (i=0 ; i < reactors.length ; i++) { + if (reactors[i] == NeighborsReactor.class) { + break; + } + } + registrations[i].close(); + } + } + + public class EbgpMultihopReactor + extends AbstractDataChangeListener + implements AutoCloseable { - addBgpRouter(value); + private static final String yangObj = "ebgp-multihop "; + + public EbgpMultihopReactor() { + super(EbgpMultihop.class); } - private InstanceIdentifier getWildCardPath() { - return InstanceIdentifier.create(BgpRouter.class); + protected synchronized void + add(InstanceIdentifier iid, EbgpMultihop val) { + LOG.debug("received add EbgpMultihop config val {}", val.getPeerIp().getValue()); + synchronized(BgpConfigurationManager.this) { + BgpRouter br = getClient(yangObj); + if (br == null) { + return; + } + String peerIp = val.getPeerIp().getValue(); + try { + br.addEbgpMultihop(peerIp, val.getNhops().intValue()); + } catch (Exception e) { + LOG.error(yangObj+"Add received exception: \""+e+"\"; " + +addWarn); + } + } } - @Override - public void close() throws Exception { - if (listenerRegistration != null) { + protected synchronized void + remove(InstanceIdentifier iid, EbgpMultihop val) { + LOG.debug("received remove EbgpMultihop config val {}", val.getPeerIp().getValue()); + synchronized(BgpConfigurationManager.this) { + BgpRouter br = getClient(yangObj); + if (br == null) { + return; + } + String peerIp = val.getPeerIp().getValue(); try { - listenerRegistration.close(); - } catch (final Exception e) { - LOG.error("Error when cleaning up DataChangeListener.", e); + br.delEbgpMultihop(peerIp); + } catch (Exception e) { + LOG.error(yangObj+" Delete received exception: \""+e+"\"; " + +delWarn); } - listenerRegistration = null; } - LOG.info("Bgp Router Manager Closed"); + } + + protected void update(InstanceIdentifier iid, + EbgpMultihop oldval, EbgpMultihop newval) { + LOG.error(yangObj + updWarn); } + public void close() { + int i; + for (i=0 ; i < reactors.length ; i++) { + if (reactors[i] == EbgpMultihopReactor.class) { + break; + } + } + registrations[i].close(); + } } - public class BgpNghbrCfgManager extends AbstractDataChangeListener implements AutoCloseable { - public BgpNghbrCfgManager(final DataBroker db) { - super(BgpNeighbors.class); - registerListener(db); + public class UpdateSourceReactor + extends AbstractDataChangeListener + implements AutoCloseable { + + private static final String yangObj = "update-source "; + + public UpdateSourceReactor() { + super(UpdateSource.class); } - private void registerListener(final DataBroker db) { - try { - listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, - getWildCardPath(), BgpNghbrCfgManager.this, DataChangeScope.SUBTREE); - } catch (final Exception e) { - LOG.error("BGP Neighbor DataChange listener registration fail!", e); - throw new IllegalStateException("BGP Neighbor registration Listener failed.", e); + protected synchronized void + add(InstanceIdentifier iid, UpdateSource val) { + LOG.debug("received add UpdateSource config val {}", val.getSourceIp().getValue()); + synchronized(BgpConfigurationManager.this) { + BgpRouter br = getClient(yangObj); + if (br == null) { + return; + } + String peerIp = val.getPeerIp().getValue(); + try { + br.addUpdateSource(peerIp, val.getSourceIp().getValue()); + } catch (Exception e) { + LOG.error(yangObj+"Add received exception: \""+e+"\"; " + +addWarn); + } } } - private synchronized void removeBgpNeighbors(BgpNeighbors del) { - List bgpNeighborList = del.getBgpNeighbor(); - BgpNeighbor gateway = bgpNeighborList.get(0); + protected synchronized void + remove(InstanceIdentifier iid, UpdateSource val) { + LOG.debug("received remove UpdateSource config val {}", val.getSourceIp().getValue()); + synchronized(BgpConfigurationManager.this) { + BgpRouter br = getClient(yangObj); + if (br == null) { + return; + } + String peerIp = val.getPeerIp().getValue(); + try { + br.delUpdateSource(peerIp); + } catch (Exception e) { + LOG.error(yangObj+" Delete received exception: \""+e+"\"; " + +delWarn); + } + } + } + + protected void update(InstanceIdentifier iid, + UpdateSource oldval, UpdateSource newval) { + LOG.error(yangObj + updWarn); + } + + public void close() { + int i; + for (i=0 ; i < reactors.length ; i++) { + if (reactors[i] == UpdateSourceReactor.class) { + break; + } + } + registrations[i].close(); + } + } - if(gateway != null) { - if ((gateway.getPeerAddressType() != null) && (gateway.getPeerAddressType() instanceof org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.bgp.rev130715.bgp.neighbors.bgp.neighbor.peer.address.type.IpAddress)) { - IpAddress neighborIPAddr = ((org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.bgp.rev130715.bgp.neighbors.bgp.neighbor.peer.address.type.IpAddress) gateway.getPeerAddressType()).getIpAddress(); - LOG.debug("Bgp Neighbor IP Address {} ", neighborIPAddr.getIpv4Address().getValue()); + public class AddressFamiliesReactor + extends AbstractDataChangeListener + implements AutoCloseable { - configureBgpServer(BgpOp.DEL_NGHBR); + private static final String yangObj = "address-families "; - bgpConfiguration.setNeighbourIp(""); - bgpConfiguration.setNeighbourAsNum(0); + public AddressFamiliesReactor() { + super(AddressFamilies.class); + } + protected synchronized void + add(InstanceIdentifier iid, AddressFamilies val) { + LOG.debug("received add AddressFamilies config val {}", val.getPeerIp().getValue()); + synchronized(BgpConfigurationManager.this) { + BgpRouter br = getClient(yangObj); + if (br == null) { + return; + } + String peerIp = val.getPeerIp().getValue(); + af_afi afi = af_afi.findByValue(val.getAfi().intValue()); + af_safi safi = af_safi.findByValue(val.getSafi().intValue()); + try { + br.addAddressFamily(peerIp, afi, safi); + } catch (Exception e) { + LOG.error(yangObj+"Add received exception: \""+e+"\"; " + +addWarn); } } + } + protected synchronized void + remove(InstanceIdentifier iid, AddressFamilies val) { + LOG.debug("received remove AddressFamilies config val {}", val.getPeerIp().getValue()); + synchronized(BgpConfigurationManager.this) { + BgpRouter br = getClient(yangObj); + if (br == null) { + return; + } + String peerIp = val.getPeerIp().getValue(); + af_afi afi = af_afi.findByValue(val.getAfi().intValue()); + af_safi safi = af_safi.findByValue(val.getSafi().intValue()); + try { + br.delAddressFamily(peerIp, afi, safi); + } catch (Exception e) { + LOG.error(yangObj+" Delete received exception: \""+e+"\"; " + +delWarn); + } + } + } + + protected void update(InstanceIdentifier iid, + AddressFamilies oldval, AddressFamilies newval) { + LOG.error(yangObj + updWarn); } - @Override - protected void remove(InstanceIdentifier identifier, - BgpNeighbors del) { + public void close() { + int i; + for (i=0 ; i < reactors.length ; i++) { + if (reactors[i] == AddressFamiliesReactor.class) { + break; + } + } + registrations[i].close(); + } + } + + public class NetworksReactor + extends AbstractDataChangeListener + implements AutoCloseable { - LOG.debug("Bgp Neighbors deleted in DS - key: {}, value={} ", identifier, del); - removeBgpNeighbors(del); + private static final String yangObj = "networks "; + + public NetworksReactor() { + super(Networks.class); } - private synchronized void updateBgpNeighbors(BgpNeighbors original, BgpNeighbors update) { + protected synchronized void + add(InstanceIdentifier iid, Networks val) { + LOG.debug("received add Networks config val {}", val.getPrefixLen()); + synchronized(BgpConfigurationManager.this) { + BgpRouter br = getClient(yangObj); + if (br == null) { + return; + } + String rd = val.getRd(); + String pfxlen = val.getPrefixLen(); + String nh = val.getNexthop().getValue(); + Long label = val.getLabel(); + int lbl = (label == null) ? qbgpConstants.LBL_NO_LABEL + : label.intValue(); + try { + br.addPrefix(rd, pfxlen, nh, lbl); + } catch (Exception e) { + LOG.error(yangObj+"Add received exception: \""+e+"\"; "+addWarn); + } + } + } - List bgpNeighborList = update.getBgpNeighbor(); + protected synchronized void + remove(InstanceIdentifier iid, Networks val) { + LOG.debug("received remove Networks config val {}", val.getPrefixLen()); + synchronized(BgpConfigurationManager.this) { + BgpRouter br = getClient(yangObj); + if (br == null) { + return; + } + String rd = val.getRd(); + String pfxlen = val.getPrefixLen(); + Long label = val.getLabel(); + int lbl = (label == null) ? 0 : label.intValue(); + if (rd == null && lbl > 0) { + //LU prefix is being deleted. + rd = Integer.toString(lbl); + } + try { + br.delPrefix(rd, pfxlen); + } catch (Exception e) { + LOG.error(yangObj+" Delete received exception: \""+e+"\"; " + +delWarn); + } + } + } + + protected void update(InstanceIdentifier iid, + Networks oldval, Networks newval) { + LOG.error(yangObj + updWarn); + } - //handle the case where there are no neighbors configured - single neighbor entry has been deleted - if(bgpNeighborList.isEmpty()) { - configureBgpServer(BgpOp.DEL_NGHBR); - return; + public void close() { + int i; + for (i=0 ; i < reactors.length ; i++) { + if (reactors[i] == NetworksReactor.class) { + break; + } } + registrations[i].close(); + } + } + + public class VrfsReactor + extends AbstractDataChangeListener + implements AutoCloseable { - //We will always consider the first element of this list, since there can be just one DC Gateway - BgpNeighbor gateway = bgpNeighborList.get(0); + private static final String yangObj = "vrfs "; - if(gateway != null) { - if(gateway.getAsNumber() != null || - ((gateway.getPeerAddressType() != null) && (gateway.getPeerAddressType() instanceof org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.bgp.rev130715.bgp.neighbors.bgp.neighbor.peer.address.type.IpAddress))) { - //there is an updated neighbor, so we need to delete the old neighbor - configureBgpServer(BgpOp.DEL_NGHBR); + public VrfsReactor() { + super(Vrfs.class); + } + + protected synchronized void + add(InstanceIdentifier iid, Vrfs val) { + LOG.debug("received add Vrfs config val {}", val.getRd()); + synchronized(BgpConfigurationManager.this) { + BgpRouter br = getClient(yangObj); + if (br == null) { + return; } - if(gateway.getAsNumber() != null) { - LOG.debug("Bgp Neighbor AS number {} ", gateway.getAsNumber()); - if(bgpConfiguration.getNeighbourAsNum() != gateway.getAsNumber()) { - bgpConfiguration.setNeighbourAsNum(gateway.getAsNumber()); - bgpConfiguration.setConfigUpdated(); - } + try { + br.addVrf(val.getRd(), val.getImportRts(), + val.getExportRts()); + } catch (Exception e) { + LOG.error(yangObj+"Add received exception: \""+e+"\"; " + +addWarn); } - if((gateway.getPeerAddressType() != null) && (gateway.getPeerAddressType() instanceof org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.bgp.rev130715.bgp.neighbors.bgp.neighbor.peer.address.type.IpAddress)) { - IpAddress neighborIPAddr = ((org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.bgp.rev130715.bgp.neighbors.bgp.neighbor.peer.address.type.IpAddress)gateway.getPeerAddressType()).getIpAddress(); - LOG.debug("Bgp Neighbor IP Address {}", neighborIPAddr.getIpv4Address().getValue()); - if(bgpConfiguration.getNeighbourIp() != neighborIPAddr.getIpv4Address().getValue()) { - bgpConfiguration.setNeighbourIp(neighborIPAddr.getIpv4Address().getValue()); - bgpConfiguration.setConfigUpdated(); - } + } + } + protected synchronized void + remove(InstanceIdentifier iid, Vrfs val) { + LOG.debug("received remove Vrfs config val {}", val.getRd()); + synchronized(BgpConfigurationManager.this) { + BgpRouter br = getClient(yangObj); + if (br == null) { + return; + } + try { + br.delVrf(val.getRd()); + } catch (Exception e) { + LOG.error(yangObj+" Delete received exception: \""+e+"\"; " + +delWarn); } } - if(bgpConfiguration.isConfigUpdated()) { - //add the newly configured neighbor - configureBgpServer(BgpOp.ADD_NGHBR); + } + + protected void update(InstanceIdentifier iid, + Vrfs oldval, Vrfs newval) { + LOG.error(yangObj + updWarn); + } + + public void close() { + int i; + for (i=0 ; i < reactors.length ; i++) { + if (reactors[i] == VrfsReactor.class) { + break; + } } + registrations[i].close(); } + } + + Future lastCleanupJob; + AtomicReference lastCleanupJobReference = new AtomicReference<>(); - @Override - protected void update(InstanceIdentifier identifier, - BgpNeighbors original, BgpNeighbors update) { + AtomicBoolean started = new AtomicBoolean(false); + public class BgpReactor + extends AbstractDataChangeListener + implements AutoCloseable { + + private static final String yangObj = "Bgp "; - LOG.debug("Bgp Neighbors Updated in DS - key: {}, original={}, update={} ", identifier, original, update); + public BgpReactor() { + super(Bgp.class); + } - updateBgpNeighbors(original, update); + protected synchronized void + add(InstanceIdentifier iid, Bgp val) { + LOG.debug("received add Bgp config replaying the config"); + try { + initer.await(); + } catch (Exception e) { + } + synchronized(BgpConfigurationManager.this) { + config = val; + if (restarting) { + if (isIpAvailable(odlThriftIp)) { + bgpRestarted(); + } else { + ipActivationCheckTimer.scheduleAtFixedRate(new TimerTask() { + public void run() { + if (isIpAvailable(odlThriftIp)) { + bgpRestarted(); + ipActivationCheckTimer.cancel(); + } + } + }, 10000L, 10000L); + } + } + } + } + + protected synchronized void + remove(InstanceIdentifier iid, Bgp val) { + LOG.debug("received remove Bgp config"); + synchronized(BgpConfigurationManager.this) { + config = null; + } + } + + protected void update(InstanceIdentifier iid, + Bgp oldval, Bgp newval) { + synchronized(BgpConfigurationManager.this) { + config = newval; + } + } + + public void close() { + int i; + for (i=0 ; i < reactors.length ; i++) { + if (reactors[i] == BgpReactor.class) { + break; + } + } + registrations[i].close(); + } + } + + public void readOdlThriftIpForBgpCommunication() { + File f = new File(CLUSTER_CONF_FILE); + if (!f.exists()) { + odlThriftIp = "127.0.0.1"; + return; + } + BufferedReader br = null; + try { + br = new BufferedReader(new InputStreamReader( + new FileInputStream(f))); + String line = br.readLine(); + while (line != null) { + if (line.contains(SDNC_BGP_MIP)) { + line = line.trim(); + odlThriftIp = line.substring(line.lastIndexOf(" ")+1); + break; + } + line = br.readLine(); + } + } catch (Exception e) { + } finally { + try {br.close();} catch (Exception ignore){} + } + } + + public boolean isIpAvailable(String odlip) { + + try { + if (odlip != null) { + if ("127.0.0.1".equals(odlip)) { + return true; + } + Enumeration e = NetworkInterface.getNetworkInterfaces(); + while(e.hasMoreElements()) + { + NetworkInterface n = (NetworkInterface) e.nextElement(); + Enumeration ee = n.getInetAddresses(); + while (ee.hasMoreElements()) + { + InetAddress i = (InetAddress) ee.nextElement(); + if (odlip.equals(i.getHostAddress())) { + return true; + }; + } + } + } + } catch (Exception e) { + } + return false; + } + public void bgpRestarted() { + /* + * If there a thread which in the process of stale cleanup, cancel it + * and start a new thread (to avoid processing same again). + */ + if (lastCleanupJobReference.get() != null) { + lastCleanupJobReference.get().cancel(true); + lastCleanupJobReference.set(null); } + Runnable task = new Runnable() { + @Override + public void run() { + try { + long startTime = System.currentTimeMillis(); + LOG.error("started creating stale fib map "); + createStaleFibMap(); + long endTime = System.currentTimeMillis(); + LOG.error("took {} msecs for stale fib map creation ", endTime - startTime); + LOG.error("started bgp config replay "); + startTime = endTime; + replay(); + endTime = System.currentTimeMillis(); + LOG.error("took {} msecs for bgp replay ", endTime - startTime); + long route_sync_time = BGP_RESTART_ROUTE_SYNC_SEC; + try { + route_sync_time = bgpManager.getConfig().getGracefulRestart().getStalepathTime(); + } catch (Exception e) { + LOG.error("BGP config/Stale-path time is not set"); + } + Thread.sleep(route_sync_time * 1000L); + new RouteCleanup().call(); - private synchronized void addBgpNeighbors(BgpNeighbors value) { - List bgpNeighborList = value.getBgpNeighbor(); + } catch (Exception eCancel) { + LOG.error("Stale Cleanup Task Cancelled", eCancel); + } + } + }; + lastCleanupJob = executor.submit(task); + lastCleanupJobReference.set(lastCleanupJob); + } - //We will always consider the first element of this list, since there can be just one DC Gateway - BgpNeighbor gateway = bgpNeighborList.get(0); + private static void doRouteSync() { + BgpSyncHandle bsh = BgpSyncHandle.getInstance(); + LOG.debug("Starting BGP route sync"); + try { + bgpRouter.initRibSync(bsh); + } catch (Exception e) { + LOG.error("Route sync aborted, exception when initialzing: "+e); + return; + } + while (bsh.getState() != bsh.DONE) { + Routes routes = null; + try { + routes = bgpRouter.doRibSync(bsh); + } catch (Exception e) { + LOG.error("Route sync aborted, exception when syncing: "+e); + return; + } + Iterator updates = routes.getUpdatesIterator(); + while (updates.hasNext()) { + Update u = updates.next(); + Map> stale_fib_rd_map = BgpConfigurationManager.getStaledFibEntriesMap(); + String rd = u.getRd(); + String nexthop = u.getNexthop(); + int label = u.getLabel(); + String prefix = u.getPrefix(); + int plen = u.getPrefixlen(); + onUpdatePushRoute(rd, prefix, plen, nexthop, label); + } + } + try { + LOG.debug("Ending BGP route-sync"); + bgpRouter.endRibSync(bsh); + } catch (Exception e) { + } + } - if(gateway != null) { - if(gateway.getAsNumber() != null) { - LOG.debug("Bgp Neighbor AS number {} ", gateway.getAsNumber()); - bgpConfiguration.setNeighbourAsNum(gateway.getAsNumber()); + /* onUpdatePushRoute + * Get Stale fib map, and compare current route/fib entry. + * - Entry compare shall include NextHop, Label. + * - If entry matches: delete from STALE Map. NO Change to FIB Config DS. + * - If entry nor found, add to FIB Config DS. + * - If entry found, but either Label/NextHop doesnt match. + * - Update FIB Config DS with modified values. + * - delete from Stale Map. + */ + public static void onUpdatePushRoute(String rd, String prefix, int plen, + String nexthop, int label) { + Map> stale_fib_rd_map = BgpConfigurationManager.getStaledFibEntriesMap(); + boolean addroute = false; + if (!stale_fib_rd_map.isEmpty()) { + // restart Scenario, as MAP is not empty. + Map map = stale_fib_rd_map.get(rd); + if (map !=null) { + String nexthoplabel = map.get(prefix + "/" + plen); + if (null == nexthoplabel) { + // New Entry, which happend to be added during restart. + addroute = true; + } else { + map.remove(prefix + "/" + plen); + if (isRouteModified(nexthop, label, nexthoplabel)) { + LOG.debug("Route add ** {} ** {}/{} ** {} ** {} ", rd, prefix, + plen, nexthop, label); + // Existing entry, where in Nexthop/Label got modified during restart + addroute = true; + } } - if((gateway.getPeerAddressType() != null) && (gateway.getPeerAddressType() instanceof org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.bgp.rev130715.bgp.neighbors.bgp.neighbor.peer.address.type.IpAddress)) { - IpAddress neighborIPAddr = ((org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.bgp.rev130715.bgp.neighbors.bgp.neighbor.peer.address.type.IpAddress)gateway.getPeerAddressType()).getIpAddress(); - LOG.debug("Bgp Neighbor IP Address {} ", neighborIPAddr.getIpv4Address().getValue()); - bgpConfiguration.setNeighbourIp(neighborIPAddr.getIpv4Address().getValue()); + } + } else { + LOG.debug("Route add ** {} ** {}/{} ** {} ** {} ", rd, prefix, + plen, nexthop, label); + addroute = true; + } + if (addroute) { + fib.addFibEntryToDS(rd, prefix + "/" + plen, + nexthop, label); + } + } + private static boolean isRouteModified(String nexthop, int label, String nexthoplabel) { + return !nexthoplabel.isEmpty() && !nexthoplabel.equals(nexthop+"/"+label); + } + + static private void replayNbrConfig(List n, BgpRouter br) { + for (Neighbors nbr : n) { + try { + br.addNeighbor(nbr.getAddress().getValue(), + nbr.getRemoteAs().intValue()); + //itmProvider.buildTunnelsToDCGW(new IpAddress(nbr.getAddress().getValue().toCharArray())); + } catch (Exception e) { + LOG.error("Replay:addNbr() received exception: \""+e+"\""); + continue; + } + EbgpMultihop en = nbr.getEbgpMultihop(); + if (en != null) { + try { + br.addEbgpMultihop(en.getPeerIp().getValue(), + en.getNhops().intValue()); + } catch (Exception e) { + LOG.error("Replay:addEBgp() received exception: \""+e+"\""); } - if(bgpConfiguration.getNeighbourAsNum() != 0 && bgpConfiguration.getNeighbourIp() != null) { - configureBgpServer(BgpOp.ADD_NGHBR); + } + UpdateSource us = nbr.getUpdateSource(); + if (us != null) { + try { + br.addUpdateSource(us.getPeerIp().getValue(), + us.getSourceIp().getValue()); + } catch (Exception e) { + LOG.error("Replay:addUS() received exception: \""+e+"\""); + } + } + List afs = nbr.getAddressFamilies(); + if (afs != null) { + for (AddressFamilies af : afs) { + af_afi afi = af_afi.findByValue(af.getAfi().intValue()); + af_safi safi = af_safi.findByValue(af.getSafi().intValue()); + try { + br.addAddressFamily(af.getPeerIp().getValue(), afi, safi); + } catch (Exception e) { + LOG.error("Replay:addAf() received exception: \""+e+"\""); + } } } + } + } + public static String getConfigHost() { + if (config == null) { + return cHostStartup; } + ConfigServer ts = config.getConfigServer(); + return (ts == null ? cHostStartup : ts.getHost().getValue()); + } - @Override - protected void add(InstanceIdentifier identifier, - BgpNeighbors value) { - LOG.debug("Bgp Neighbor added in DS - key: {}, value={} ", identifier, value); + public static int getConfigPort() { + if (config == null) { + return Integer.parseInt(cPortStartup); + } + ConfigServer ts = config.getConfigServer(); + return (ts == null ? Integer.parseInt(cPortStartup) : + ts.getPort().intValue()); + } - addBgpNeighbors(value); + public static synchronized void replay() { + String host = getConfigHost(); + int port = getConfigPort(); + boolean res = bgpRouter.connect(host, port); + if (!res) { + String msg = "Cannot connect to BGP config server at "+host+":"+port; + if (config != null) { + msg += "; Configuration Replay aborted"; + } + LOG.error(msg); + return; + } + if (config == null) { + return; + } + BgpRouter br = bgpRouter; + AsId a = config.getAsId(); + if (a == null) { + return; + } + int asNum = a.getLocalAs().intValue(); + Ipv4Address routerId = a.getRouterId(); + Long spt = a.getStalepathTime(); + Boolean afb = a.isAnnounceFbit(); + String rid = (routerId == null) ? "" : routerId.getValue(); + int stalepathTime = (spt == null) ? 90 : spt.intValue(); + boolean announceFbit = (afb == null) ? false : afb.booleanValue(); + try { + br.startBgp(asNum, rid, stalepathTime, announceFbit); + } catch (BgpRouterException bre) { + if (bre.getErrorCode() == BgpRouterException.BGP_ERR_ACTIVE) { + doRouteSync(); + } else { + LOG.error("Replay: startBgp() received exception: \"" + +bre+"\"; "+addWarn); + } + } catch (Exception e) { + //not unusual. We may have restarted & BGP is already on + LOG.error("Replay:startBgp() received exception: \""+e+"\""); } - private InstanceIdentifier getWildCardPath() { - return InstanceIdentifier.create(BgpNeighbors.class); + if (bgpManager.getBgpCounters() == null) { + bgpManager.startBgpCountersTask(); + } + + Logging l = config.getLogging(); + if (l != null) { + try { + br.setLogging(l.getFile(), l.getLevel()); + } catch (Exception e) { + LOG.error("Replay:setLogging() received exception: \""+e+"\""); + } } + GracefulRestart g = config.getGracefulRestart(); + if (g != null) { + try { + br.addGracefulRestart(g.getStalepathTime().intValue()); + } catch (Exception e) { + LOG.error("Replay:addGr() received exception: \""+e+"\""); + } + } - @Override - public void close() throws Exception { - if (listenerRegistration != null) { + List n = config.getNeighbors(); + if (n != null) { + replayNbrConfig(n, br); + } + + List v = config.getVrfs(); + if (v != null) { + for (Vrfs vrf : v) { + try { + br.addVrf(vrf.getRd(), vrf.getImportRts(), + vrf.getExportRts()); + } catch (Exception e) { + LOG.error("Replay:addVrf() received exception: \""+e+"\""); + } + } + } + + List ln = config.getNetworks(); + if (ln != null) { + for (Networks net : ln) { + String rd = net.getRd(); + String pfxlen = net.getPrefixLen(); + String nh = net.getNexthop().getValue(); + Long label = net.getLabel(); + int lbl = (label == null) ? 0 : label.intValue(); + if (rd == null && lbl > 0) { + //LU prefix is being deleted. + rd = Integer.toString(lbl); + } try { - listenerRegistration.close(); - } catch (final Exception e) { - LOG.error("Error when cleaning up DataChangeListener.", e); + br.addPrefix(rd, pfxlen, nh, lbl); + } catch (Exception e) { + LOG.error("Replay:addPfx() received exception: \""+e+"\""); } - listenerRegistration = null; } - LOG.info("Bgp Neighbor Manager Closed"); } + } + + private void update(InstanceIdentifier iid, T dto) { + BgpUtil.update(broker, LogicalDatastoreType.CONFIGURATION, iid, dto); + } + + private void asyncWrite(InstanceIdentifier iid, T dto) { + BgpUtil.write(broker,LogicalDatastoreType.CONFIGURATION,iid,dto); + } + + private void delete(InstanceIdentifier iid) { + BgpUtil.delete(broker, LogicalDatastoreType.CONFIGURATION, iid); + } + + public synchronized void + startConfig(String bgpHost, int thriftPort) { + InstanceIdentifier.InstanceIdentifierBuilder iib = + InstanceIdentifier.builder(Bgp.class).child(ConfigServer.class); + InstanceIdentifier iid = iib.build(); + Ipv4Address ipAddr = new Ipv4Address(bgpHost); + ConfigServer dto = new ConfigServerBuilder().setHost(ipAddr) + .setPort((long) thriftPort).build(); + update(iid, dto); + } + public synchronized void + startBgp(int as, String routerId, int spt, boolean fbit) { + Long localAs = (long) as; + Ipv4Address rid = (routerId == null) ? + null : new Ipv4Address(routerId); + Long staleTime = (long) spt; + InstanceIdentifier.InstanceIdentifierBuilder iib = + InstanceIdentifier.builder(Bgp.class).child(AsId.class); + InstanceIdentifier iid = iib.build(); + AsId dto = new AsIdBuilder().setLocalAs(localAs) + .setRouterId(rid) + .setStalepathTime(staleTime) + .setAnnounceFbit(fbit).build(); + update(iid, dto); } - private void configureBgpServer(BgpOp bgpOp) { - int retryCount = 0; - boolean retry = false; - do { + public synchronized void + addLogging(String fileName, String logLevel) { + InstanceIdentifier.InstanceIdentifierBuilder iib = + InstanceIdentifier.builder(Bgp.class).child(Logging.class); + InstanceIdentifier iid = iib.build(); + Logging dto = new LoggingBuilder().setFile(fileName) + .setLevel(logLevel).build(); + update(iid, dto); + } + + public synchronized void + addGracefulRestart(int staleTime) { + InstanceIdentifier.InstanceIdentifierBuilder iib = + InstanceIdentifier.builder(Bgp.class).child(GracefulRestart.class); + InstanceIdentifier iid = iib.build(); + GracefulRestart dto = new GracefulRestartBuilder() + .setStalepathTime((long)staleTime).build(); + update(iid, dto); + } + + public synchronized void + addNeighbor(String nbrIp, int remoteAs) { + Ipv4Address nbrAddr = new Ipv4Address(nbrIp); + Long rAs = (long) remoteAs; + InstanceIdentifier.InstanceIdentifierBuilder iib = + InstanceIdentifier.builder(Bgp.class) + .child(Neighbors.class, new NeighborsKey(nbrAddr)); + InstanceIdentifier iid = iib.build(); + Neighbors dto = new NeighborsBuilder().setAddress(nbrAddr) + .setRemoteAs(rAs).build(); + update(iid, dto); + } + + public synchronized void + addUpdateSource(String nbrIp, String srcIp) { + Ipv4Address nbrAddr = new Ipv4Address(nbrIp); + Ipv4Address srcAddr = new Ipv4Address(srcIp); + InstanceIdentifier.InstanceIdentifierBuilder iib = + InstanceIdentifier.builder(Bgp.class) + .child(Neighbors.class, new NeighborsKey(nbrAddr)) + .child(UpdateSource.class); + InstanceIdentifier iid = iib.build(); + UpdateSource dto = new UpdateSourceBuilder().setPeerIp(nbrAddr) + .setSourceIp(srcAddr).build(); + update(iid, dto); + } + + public synchronized void + addEbgpMultihop(String nbrIp, int nHops) { + Ipv4Address nbrAddr = new Ipv4Address(nbrIp); + InstanceIdentifier.InstanceIdentifierBuilder iib = + InstanceIdentifier.builder(Bgp.class) + .child(Neighbors.class, new NeighborsKey(nbrAddr)) + .child(EbgpMultihop.class); + InstanceIdentifier iid = iib.build(); + EbgpMultihop dto = new EbgpMultihopBuilder().setPeerIp(nbrAddr) + .setNhops((long)nHops).build(); + update(iid, dto); + } + + public synchronized void + addAddressFamily(String nbrIp, int afi, int safi) { + Ipv4Address nbrAddr = new Ipv4Address(nbrIp); + Long a = (long) afi; + Long sa = (long) safi; + InstanceIdentifier.InstanceIdentifierBuilder iib = + InstanceIdentifier.builder(Bgp.class) + .child(Neighbors.class, new NeighborsKey(nbrAddr)) + .child(AddressFamilies.class, new AddressFamiliesKey(a, sa)); + InstanceIdentifier iid = iib.build(); + AddressFamilies dto = new AddressFamiliesBuilder().setPeerIp(nbrAddr) + .setAfi(a).setSafi(sa).build(); + update(iid, dto); + } + + public synchronized void + addPrefix(String rd, String pfx, String nh, int lbl) { + Ipv4Address nexthop = new Ipv4Address(nh); + Long label = (long) lbl; + InstanceIdentifier.InstanceIdentifierBuilder iib = + InstanceIdentifier.builder(Bgp.class) + .child(Networks.class, new NetworksKey(pfx, rd)); + InstanceIdentifier iid = iib.build(); + Networks dto = new NetworksBuilder().setRd(rd) + .setPrefixLen(pfx) + .setNexthop(nexthop) + .setLabel(label).build(); + update(iid, dto); + } + + public synchronized void + addVrf(String rd, List irts, List erts) { + InstanceIdentifier.InstanceIdentifierBuilder iib = + InstanceIdentifier.builder(Bgp.class) + .child(Vrfs.class, new VrfsKey(rd)); + InstanceIdentifier iid = iib.build(); + Vrfs dto = new VrfsBuilder().setRd(rd) + .setImportRts(irts) + .setExportRts(erts).build(); + + asyncWrite(iid, dto); + } + + public synchronized void stopConfig() { + InstanceIdentifier.InstanceIdentifierBuilder iib = + InstanceIdentifier.builder(Bgp.class).child(ConfigServer.class); + InstanceIdentifier iid = iib.build(); + delete(iid); + } + + public synchronized void stopBgp() { + InstanceIdentifier.InstanceIdentifierBuilder iib = + InstanceIdentifier.builder(Bgp.class).child(AsId.class); + InstanceIdentifier iid = iib.build(); + delete(iid); + } + + public synchronized void delLogging() { + InstanceIdentifier.InstanceIdentifierBuilder iib = + InstanceIdentifier.builder(Bgp.class).child(Logging.class); + InstanceIdentifier iid = iib.build(); + delete(iid); + } + + public synchronized void delGracefulRestart() { + InstanceIdentifier.InstanceIdentifierBuilder iib = + InstanceIdentifier.builder(Bgp.class) + .child(GracefulRestart.class); + InstanceIdentifier iid = iib.build(); + delete(iid); + } + + public synchronized void delNeighbor(String nbrIp) { + Ipv4Address nbrAddr = new Ipv4Address(nbrIp); + InstanceIdentifier.InstanceIdentifierBuilder iib = + InstanceIdentifier.builder(Bgp.class) + .child(Neighbors.class, new NeighborsKey(nbrAddr)); + InstanceIdentifier iid = iib.build(); + delete(iid); + } + + public synchronized void delUpdateSource(String nbrIp) { + Ipv4Address nbrAddr = new Ipv4Address(nbrIp); + InstanceIdentifier.InstanceIdentifierBuilder iib = + InstanceIdentifier.builder(Bgp.class) + .child(Neighbors.class, new NeighborsKey(nbrAddr)) + .child(UpdateSource.class); + InstanceIdentifier iid = iib.build(); + delete(iid); + } + + public synchronized void delEbgpMultihop(String nbrIp) { + Ipv4Address nbrAddr = new Ipv4Address(nbrIp); + InstanceIdentifier.InstanceIdentifierBuilder iib = + InstanceIdentifier.builder(Bgp.class) + .child(Neighbors.class, new NeighborsKey(nbrAddr)) + .child(EbgpMultihop.class); + InstanceIdentifier iid = iib.build(); + delete(iid); + } + + public synchronized void + delAddressFamily(String nbrIp, int afi, int safi) { + Ipv4Address nbrAddr = new Ipv4Address(nbrIp); + Long a = (long) afi; + Long sa = (long) safi; + InstanceIdentifier.InstanceIdentifierBuilder iib = + InstanceIdentifier.builder(Bgp.class) + .child(Neighbors.class, new NeighborsKey(nbrAddr)) + .child(AddressFamilies.class, new AddressFamiliesKey(a, sa)); + InstanceIdentifier iid = iib.build(); + delete(iid); + } + + public synchronized void delPrefix(String rd, String pfx) { + InstanceIdentifier.InstanceIdentifierBuilder iib = + InstanceIdentifier.builder(Bgp.class) + .child(Networks.class, new NetworksKey(pfx, rd)); + InstanceIdentifier iid = iib.build(); + delete(iid); + } + + public synchronized void delVrf(String rd) { + InstanceIdentifier.InstanceIdentifierBuilder iib = + InstanceIdentifier.builder(Bgp.class) + .child(Vrfs.class, new VrfsKey(rd)); + InstanceIdentifier iid = iib.build(); + delete(iid); + } + + static ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); + /* + * Remove Stale Marked Routes after timer expiry. + */ + class RouteCleanup implements Callable { + + public Integer call () { + int totalCleared = 0; try { - switch(bgpOp) { - case START_BGP: - bgpManager.startBgpService(); - break; - case ADD_NGHBR: - bgpManager.addNeighbor(bgpConfiguration.getNeighbourIp(), bgpConfiguration.getNeighbourAsNum()); - break; - case DEL_NGHBR: - bgpManager.deleteNeighbor(bgpConfiguration.getNeighbourIp()); - break; - default: - LOG.error("Invalid configuration option {}", bgpOp); - } - - retry = false; - } catch (TException t) { - retry = true; - retryCount++; - } - } while(retry && retryCount <= MAX_RETRIES_BGP_COMMUNICATION); + if (staledFibEntriesMap.isEmpty()) { + LOG.info("BGP: RouteCleanup timertask tirggered but STALED FIB MAP is EMPTY"); + } else { + for (String rd : staledFibEntriesMap.keySet()) { + if (Thread.interrupted()) { + return 0; + } + Map map = staledFibEntriesMap.get(rd); + if (map != null) { + for (String prefix : map.keySet()) { + if (Thread.interrupted()) { + return 0; + } + try { + totalCleared++; + bgpManager.deletePrefix(rd, prefix); + } catch (Exception e) { + LOG.error("BGP: RouteCleanup deletePrefix failed rd:{}, prefix{}" + rd.toString() + prefix); + } + } + } + } + } + } catch(Exception e) { + LOG.error("Cleanup Thread Got interrupted, Failed to cleanup stale routes ", e); + } finally { + staledFibEntriesMap.clear(); + } + LOG.error("cleared {} stale routes after bgp restart", totalCleared); + return 0; + } + } + + /* + * BGP restart scenario, ODL-BGP manager was/is running. + * On re-sync notification, Get a copy of FIB database. + */ + public static void createStaleFibMap() { + int totalStaledCount = 0; + try { + staledFibEntriesMap.clear(); + InstanceIdentifier id = InstanceIdentifier.create(FibEntries.class); + DataBroker db = BgpUtil.getBroker(); + if (db == null) { + LOG.error("Couldn't find BgpUtil broker while creating createStaleFibMap"); + return; + } + + Optional fibEntries = BgpUtil.read(BgpUtil.getBroker(), + LogicalDatastoreType.CONFIGURATION, id); + if (fibEntries.isPresent()) { + List stale_vrfTables = fibEntries.get().getVrfTables(); + for (VrfTables vrfTable : stale_vrfTables) { + Map stale_fib_ent_map = new HashMap<>(); + for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) { + if (Thread.interrupted()) { + break; + } + totalStaledCount++; + //Create MAP from stale_vrfTables. + stale_fib_ent_map.put(vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddress() + "/" + vrfEntry.getLabel()); + } + staledFibEntriesMap.put(vrfTable.getRouteDistinguisher(), stale_fib_ent_map); + } + } else { + LOG.error("createStaleFibMap:: FIBentries.class is not present"); + } + } catch (Exception e) { + LOG.error("createStaleFibMap:: erorr ", e); + } + LOG.error("created {} staled entries ", totalStaledCount); + } + + //map> + public static Map> getStaledFibEntriesMap() { + return staledFibEntriesMap; } + + } diff --git a/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/BgpManager.java b/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/BgpManager.java index 55085413..909b82a8 100644 --- a/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/BgpManager.java +++ b/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/BgpManager.java @@ -5,28 +5,25 @@ * 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; +package org.opendaylight.bgpmanager; -import java.net.SocketTimeoutException; +import java.lang.management.ManagementFactory; import java.util.*; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CountDownLatch; - +import javax.management.*; import org.apache.thrift.TException; -import org.opendaylight.bgpmanager.thrift.client.globals.Route; -import org.opendaylight.bgpmanager.thrift.client.implementation.BgpRouter; -import org.opendaylight.bgpmanager.thrift.server.implementation.BgpThriftService; -import org.opendaylight.bgpmanager.thrift.exceptions.BgpRouterException; import org.opendaylight.bgpmanager.api.IBgpManager; -import org.opendaylight.bgpmanager.globals.BgpConfiguration; -import org.opendaylight.bgpmanager.globals.BgpConstants; - +import org.opendaylight.bgpmanager.commands.Commands; +import org.opendaylight.bgpmanager.oam.*; +import org.opendaylight.bgpmanager.thrift.gen.af_afi; +import org.opendaylight.bgpmanager.thrift.gen.af_safi; import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; - +//import org.opendaylight.vpnservice.itm.api.IITMProvider; +import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.Bgp; +import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.bgp.Neighbors; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; @@ -36,337 +33,233 @@ import org.slf4j.LoggerFactory; public class BgpManager implements BindingAwareProvider, AutoCloseable, IBgpManager { private static final Logger LOGGER = LoggerFactory.getLogger(BgpManager.class); - private BgpConfigurationManager bgpConfigurationMgr; + private BgpConfigurationManager bcm; private FibDSWriter fibDSWriter; - private BgpConfiguration bgpConfiguration = new BgpConfiguration(); - private BgpRouter bgpThriftClient; - private BgpThriftService bgpThriftService; - private boolean isBgpInitialized = false; - private boolean hasBgpServiceStarted = false; - private String bgpHost; - private int bgpPort; - - - private String getCustomConfig(String var, String def) { - Bundle b = FrameworkUtil.getBundle(this.getClass()); - BundleContext context = null; - if (b != null) { - context = b.getBundleContext(); - } - if (context != null) - return context.getProperty(var); - else - return def; - - } - - private void initializeBGPCommunication() { - //start our side of thrift server - bgpThriftService = new BgpThriftService(this, fibDSWriter); - bgpThriftService.start(); - - //start bgp thrift client connection - bgpThriftClient = new BgpRouter(); - - bgpHost = getCustomConfig(BgpConstants.BGP_SPEAKER_HOST_NAME, BgpConstants.DEFAULT_BGP_HOST_NAME); - bgpPort = BgpConstants.DEFAULT_BGP_THRIFT_PORT; - - configureBgpServer(bgpHost, bgpPort); - try { - connectToServer(bgpHost, bgpPort); - } catch (Exception e) { - return; - } - - isBgpInitialized = true; - //notify(); //notify all threads waiting for bgp init - - } - - public synchronized void waitForBgpInit() { - if(!isBgpInitialized) { - try { - wait(); - } catch (InterruptedException e) { - LOGGER.error("InterruptedException while waiting for Bgp connection to initialize"); - return; - } - } - } - - public void startBgpService() throws TException { - if(bgpThriftClient == null) { - LOGGER.error("Start Bgp Service - bgpThriftClient is null. Unable to start BGP service."); - return; - } - - // Now try start bgp - if bgp is already Active, it will tell us, nothing to do then - try { - bgpThriftClient.startBgp((int)bgpConfiguration.getAsNum(), bgpConfiguration.getRouterId()); - LOGGER.debug("Started BGP with AS number " + (int)bgpConfiguration.getAsNum() + " and router id " + bgpConfiguration.getRouterId()); - } catch (BgpRouterException be) { - if(be.getErrorCode() == BgpRouterException.BGP_ERR_ACTIVE) { - LOGGER.info("bgp server already active"); - return; - } - else if(be.getErrorCode() == BgpRouterException.BGP_ERR_NOT_INITED) { - LOGGER.error("bgp server connection not initialized."); - reInitConn(); - return; - } - else { - LOGGER.error("application error while starting bgp server " + be.getErrorCode()); - return; - } - - } catch (TException t) { - LOGGER.error("Could not set up thrift connection with bgp server"); - LOGGER.debug("Transport error while starting bgp server ", t); - reInitConn(); - throw t; - } catch (Exception e) { - LOGGER.error("Error while starting bgp server"); - LOGGER.debug("Bgp Service not started due to exception", e); - return; - } + //private IITMProvider itmProvider; + private DataBroker dataBroker; + private BgpAlarmBroadcaster qbgpAlarmProducer = null; + private MBeanServer qbgpAlarmServer = null; + private NotificationFilter qbgpAlarmFilter = null; + final static int DEFAULT_STALEPATH_TIME = 210; + final static boolean DEFAULT_FBIT = true; - hasBgpServiceStarted = true; - - } + public BgpCounters bgpCounters; + public Timer bgpCountersTimer; @Override public void onSessionInitiated(ProviderContext session) { - LOGGER.info("BgpManager Session Initiated"); try { - final DataBroker dataBroker = session.getSALService(DataBroker.class); - bgpConfigurationMgr = new BgpConfigurationManager(dataBroker, bgpConfiguration, this); + dataBroker = session.getSALService(DataBroker.class); fibDSWriter = new FibDSWriter(dataBroker); + BgpUtil.setBroker(dataBroker); + bcm = new BgpConfigurationManager(this); + Commands commands = new Commands(this); + ConfigureBgpCli.setBgpManager(this); + LOGGER.info("BgpManager started"); } catch (Exception e) { - LOGGER.error("Error initializing services", e); + LOGGER.error("Failed to start BgpManager: "+e); } - initializeBGPCommunication(); + // Set up the Infra for Posting BGP Alarms as JMX notifications. + try { + qbgpAlarmProducer = new BgpAlarmBroadcaster(); + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + ObjectName alarmObj = new ObjectName("SDNC.FM:name=BgpAlarmObj"); + mbs.registerMBean(qbgpAlarmProducer, alarmObj); + } catch (JMException e) { + LOGGER.error("Adding a NotificationBroadcaster failed." + e.toString()); + e.printStackTrace(); + } } - @Override public void close() throws Exception { + bcm.close(); LOGGER.info("BgpManager Closed"); - - //close the client and server ends of the thrift communication - if(bgpThriftClient != null) - bgpThriftClient.disconnect(); - bgpThriftService.stop(); - - } - private void setBgpServerDetails() { - if(bgpThriftClient != null) - bgpThriftClient.setBgpServer(bgpHost, bgpPort); + /*public void setITMProvider(IITMProvider itmProvider) { + this.itmProvider = itmProvider; } - private void configureBgpServer(String bgpServer, int bgpPort) { - bgpConfiguration.setBgpServer(bgpServer); - bgpConfiguration.setBgpPort(bgpPort); - setBgpServerDetails(); + public IITMProvider getItmProvider() { return this.itmProvider; } */ + + public Bgp getConfig() { + return bcm.get(); } - protected void addNeighbor(String ipAddress, long asNum) throws TException { - if(bgpThriftClient == null) { - LOGGER.error("Add BGP Neighbor - bgpThriftClient is null. Unable to add BGP Neighbor."); - return; - } + public void configureGR(int stalepathTime) throws TException { + bcm.addGracefulRestart(stalepathTime); + } - try { - bgpThriftClient.addNeighbor(ipAddress, (int) asNum); - } catch (BgpRouterException b) { - LOGGER.error("Failed to add BGP neighbor " + ipAddress + " due to BgpRouter Exception number " + b.getErrorCode()); - LOGGER.debug("BgpRouterException trace ", b); - } catch (TException t) { - LOGGER.error(String.format("Failed adding neighbor %s due to Transport error", ipAddress)); - reInitConn(); - throw t; - } catch (Exception e) { - LOGGER.error(String.format("Failed adding neighbor %s", ipAddress)); - } + public void delGracefulRestart() throws Exception { + bcm.delGracefulRestart(); } + public void addNeighbor(String ipAddress, long asNum) throws TException { + bcm.addNeighbor(ipAddress, (int) asNum); + } - protected void deleteNeighbor(String ipAddress) throws TException { - if(bgpThriftClient == null) { - LOGGER.error("Delete BGP Neighbor - bgpThriftClient is null. Unable to delete BGP Neighbor."); - return; - } + public void addEbgpMultihop(String ipAddress, int nhops) throws TException { + bcm.addEbgpMultihop(ipAddress, nhops); + } + + public void addUpdateSource(String ipAddress, String srcIp) throws TException { + bcm.addUpdateSource(ipAddress, srcIp); + } - try { - bgpThriftClient.delNeighbor(ipAddress); - } catch (BgpRouterException b) { - LOGGER.error("Failed to delete BGP neighbor " + ipAddress + "due to BgpRouter Exception number " + b.getErrorCode()); - LOGGER.debug("BgpRouterException trace ", b); - }catch (TException t) { - LOGGER.error(String.format("Failed deleting neighbor %s due to Transport error", ipAddress)); - reInitConn(); - throw t; - } catch (Exception e) { - LOGGER.error(String.format("Failed deleting neighbor %s", ipAddress)); - } + public void addAddressFamily(String ipAddress, af_afi afi, af_safi safi) throws TException { + bcm.addAddressFamily(ipAddress, afi.getValue(), safi.getValue()); } + public void deleteNeighbor(String ipAddress) throws TException { + bcm.delNeighbor(ipAddress); + } @Override public void addVrf(String rd, Collection importRts, Collection exportRts) throws Exception { - if(bgpThriftClient == null) { - LOGGER.error("Add BGP vrf - bgpThriftClient is null. Unable to add BGP vrf."); - return; - } - try { - bgpThriftClient.addVrf(rd, new ArrayList<>(importRts), new ArrayList<>(exportRts)); - } catch (BgpRouterException b) { - LOGGER.error("Failed to add BGP vrf " + rd + "due to BgpRouter Exception number " + b.getErrorCode()); - LOGGER.debug("BgpRouterException trace ", b); - throw b; - } catch (TException t) { - LOGGER.error(String.format("Failed adding vrf %s due to Transport error", rd)); - reInitConn(); - throw t; - } catch (Exception e) { - LOGGER.error(String.format("Failed adding vrf %s", rd)); - throw e; - } + bcm.addVrf(rd, new ArrayList(importRts), + new ArrayList(exportRts)); } @Override public void deleteVrf(String rd) throws Exception { - if(bgpThriftClient == null || !hasBgpServiceStarted) { - LOGGER.debug("Delete BGP vrf - Unable to delete BGP vrf in BGP Server. Removing Vrf from local DS"); - fibDSWriter.removeVrfFromDS(rd); - return; - } - - try { - bgpThriftClient.delVrf(rd); - fibDSWriter.removeVrfFromDS(rd); - } catch (BgpRouterException b) { - LOGGER.error("Failed to delete BGP vrf " + rd + "due to BgpRouter Exception number " + b.getErrorCode()); - LOGGER.debug("BgpRouterException trace ", b); - throw b; - } catch (TException t) { - LOGGER.error(String.format("Failed deleting vrf %s due to Transport error", rd)); - reInitConn(); - throw t; - } catch (Exception e) { - LOGGER.error(String.format("Failed deleting vrf %s", rd)); - throw e; - } + bcm.delVrf(rd); } @Override public void addPrefix(String rd, String prefix, String nextHop, int vpnLabel) throws Exception { + fibDSWriter.addFibEntryToDS(rd, prefix, nextHop, vpnLabel); + bcm.addPrefix(rd, prefix, nextHop, vpnLabel); + } - if(bgpThriftClient == null || !hasBgpServiceStarted) { - fibDSWriter.addFibEntryToDS(rd, prefix, nextHop, vpnLabel); - return; - } + @Override + public void deletePrefix(String rd, String prefix) throws Exception { + fibDSWriter.removeFibEntryFromDS(rd, prefix); + bcm.delPrefix(rd, prefix); + } - try { - bgpThriftClient.addPrefix(rd, prefix, nextHop, vpnLabel); - } catch (BgpRouterException b) { - LOGGER.error("Failed to add BGP prefix " + prefix + "due to BgpRouter Exception number " + b.getErrorCode()); - LOGGER.debug("BgpRouterException trace ", b); - throw b; - } catch (TException t) { - LOGGER.error(String.format("Failed adding prefix entry %s:%s:%s:%d due to Transport error", - rd, prefix, nextHop, vpnLabel)); - reInitConn(); - throw t; - } catch (Exception e) { - LOGGER.error(String.format("Failed adding prefix entry %s:%s:%s:%d", - rd, prefix, nextHop, vpnLabel)); - throw e; - } + public void setQbgpLog(String fileName, String debugLevel) throws Exception { + bcm.addLogging(fileName, debugLevel); + } + + public void delLogging() throws Exception { + bcm.delLogging(); } + public void startBgp(int asn, String routerId, int spt, boolean fbit) { + bcm.startBgp(asn, routerId, spt, fbit); + } + + public void stopBgp() { + bcm.stopBgp(); + } + + public void startConfig(String host, int port) { + bcm.startConfig(host, port); + } + + public void stopConfig() { + bcm.stopConfig(); + } @Override - public void deletePrefix(String rd, String prefix) throws Exception { - if(bgpThriftClient == null || !hasBgpServiceStarted) { - fibDSWriter.removeFibEntryFromDS(rd, prefix); - return; + public String getDCGwIP() { + Bgp conf = getConfig(); + if (conf == null) { + return null; } - - try { - bgpThriftClient.delPrefix(rd, prefix); - } catch (BgpRouterException b) { - LOGGER.error("Failed to delete BGP prefix " + prefix + "due to BgpRouter Exception number " + b.getErrorCode()); - LOGGER.debug("BgpRouterException trace ", b); - throw b; - } catch (TException t) { - LOGGER.error(String.format("Failed deleting prefix entry %s:%s due to Transport error", - rd, prefix)); - reInitConn(); - throw t; - } catch (Exception e) { - LOGGER.error(String.format("Failed deleting prefix entry %s:%s", - rd, prefix)); - throw e; + List nbrs = conf.getNeighbors(); + if (nbrs == null) { + return null; } + return nbrs.get(0).getAddress().getValue(); } - private void connectToServer(String host, int port) throws Exception { - - bgpHost = host; - bgpPort = port; + public MBeanServer getBgpAlarmServer() { + return qbgpAlarmServer; + } - if(bgpThriftClient == null) { - LOGGER.error("Failed to connect to BGP server since Bgp Thrift Client is not initialized yet."); + public synchronized void sendNotificationEvent(String pfx, int code, int subcode) { + BgpAlarmErrorCodes errorSubCode; + if (code != BgpConstants.BGP_NOTIFY_CEASE_CODE) { + // CEASE Notifications alone have to be reported to the CBA. + // Silently return here. No need to log because tons + // of non-alarm notifications will be sent to the SDNc. return; } - try { - bgpThriftClient.connect(host, port); - LOGGER.debug("Connected to BGP server {} on port {} ", host, port); - } catch (BgpRouterException b) { - LOGGER.error("Failed to connect to BGP server " + host + " on port " + port + " due to BgpRouter Exception number " + b.getErrorCode()); - LOGGER.debug("BgpRouterException trace ", b); - throw b; - } catch (TException t) { - LOGGER.error("Failed to initialize BGP Connection due to Transport error "); - throw t; - } - catch (Exception e) { - LOGGER.error("Failed to initialize BGP Connection "); - throw e; + errorSubCode = BgpAlarmErrorCodes.checkErrorSubcode(subcode); + if (errorSubCode == BgpAlarmErrorCodes.ERROR_IGNORE) { + // Need to report only those subcodes, defined in + // BgpAlarmErrorCodes enum class. + return; } + String alarmString = ""; + alarmString = "Alarm (" + code + "," + subcode + ") from neighbor " + pfx; + qbgpAlarmProducer.sendBgpAlarmInfo(pfx, code, subcode); } - public void configureBgp(long asNum, String routerId) { - try { - bgpConfiguration.setAsNum(asNum); - bgpConfiguration.setRouterId(routerId); - } catch(Exception e) { - LOGGER.error("failed configuring bgp ",e); - } + public Timer getBgpCountersTimer() { + return bgpCountersTimer; } - public synchronized void reInitConn() { + public BgpCounters getBgpCounters() { + return bgpCounters; + } - try { - bgpThriftClient.reInit(); - LOGGER.debug("Reinitialized connection to BGP Server {}", bgpHost); - } catch (BgpRouterException b) { - LOGGER.error("Failed to reinitialize connection to BGP server {} on port {} due to BgpRouter Exception number {}", bgpHost, bgpPort, b.getErrorCode()); - LOGGER.debug("BgpRouterException trace ", b); - } catch (TException t) { - LOGGER.error("Failed to reinitialize BGP Connection due to Transport error."); + public void setBgpCountersTimer (Timer t) { + bgpCountersTimer = t; + } + + public void startBgpCountersTask() { + if (getBgpCounters() == null) { + + try { + bgpCounters = new BgpCounters(); + setBgpCountersTimer(new Timer(true)); + getBgpCountersTimer().scheduleAtFixedRate(bgpCounters, 0, 120 * 1000); + + + LOGGER.info("Bgp Counters task scheduled for every two minutes."); + } catch (Exception e) { + System.out.println("Could not start the timertask for Bgp Counters."); + e.printStackTrace(); + } + + try { + setQbgpLog(BgpConstants.BGP_DEF_LOG_FILE, BgpConstants.BGP_DEF_LOG_LEVEL); + } catch (Exception e) { + System.out.println("Could not set the default options for logging"); + } } - catch (Exception e) { - LOGGER.error("Failed to reinitialize BGP Connection.", e); + } + + public void stopBgpCountersTask() { + Timer t = getBgpCountersTimer(); + if (getBgpCounters() != null) { + t.cancel(); + setBgpCountersTimer(null); + bgpCounters = null; } } - public void disconnect() { - bgpThriftClient.disconnect(); + public FibDSWriter getFibWriter() { + return fibDSWriter; + } + + public DataBroker getBroker() { + return dataBroker; + } + + public String getConfigHost() { + return bcm.getConfigHost(); } + public int getConfigPort() { + return bcm.getConfigPort(); + } + public void bgpRestarted() { + bcm.bgpRestarted(); + } } diff --git a/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/BgpUtil.java b/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/BgpUtil.java new file mode 100644 index 00000000..9aacdb8c --- /dev/null +++ b/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/BgpUtil.java @@ -0,0 +1,72 @@ +/* + * 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; + +import com.google.common.base.Optional; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Created by emhamla on 8/31/2015. + */ +public class BgpUtil { + + private static final Logger LOG = LoggerFactory.getLogger(BgpUtil.class); + private static DataBroker dataBroker; + + static void update(DataBroker broker, LogicalDatastoreType datastoreType, + InstanceIdentifier path, T data) { + WriteTransaction tx = broker.newWriteOnlyTransaction(); + tx.merge(datastoreType, path, data, true); + tx.submit(); + } + + public static void write(DataBroker broker, LogicalDatastoreType datastoreType, + InstanceIdentifier path, T data) { + WriteTransaction tx = broker.newWriteOnlyTransaction(); + tx.put(datastoreType, path, data, true); + tx.submit(); + } + + static void delete(DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier path) { + WriteTransaction tx = broker.newWriteOnlyTransaction(); + tx.delete(datastoreType, path); + tx.submit(); + } + + public static Optional read(DataBroker broker, LogicalDatastoreType datastoreType, + InstanceIdentifier path) { + + ReadOnlyTransaction tx = broker.newReadOnlyTransaction(); + + Optional result = Optional.absent(); + try { + result = tx.read(datastoreType, path).get(); + } catch (Exception e) { + throw new RuntimeException(e); + } + + return result; + } + + public static void setBroker(DataBroker broker) { + BgpUtil.dataBroker = broker; + } + + public static DataBroker getBroker() { + return dataBroker; + } + +} diff --git a/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/ConfigureBgpCli.java b/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/ConfigureBgpCli.java new file mode 100644 index 00000000..71d9786f --- /dev/null +++ b/bgpmanager/bgpmanager-impl/src/main/java/org/opendaylight/bgpmanager/ConfigureBgpCli.java @@ -0,0 +1,398 @@ +/* + * 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; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Future; + +import org.apache.karaf.shell.commands.*; +import org.apache.karaf.shell.console.OsgiCommandSupport; +import org.opendaylight.bgpmanager.thrift.gen.af_afi; +import org.opendaylight.bgpmanager.thrift.gen.af_safi; +import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.*; +import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.bgp.*; +import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.bgp.neighbors.*; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.*; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; + +@Command(scope = "odl", name = "configure-bgp", description = "") +public class ConfigureBgpCli extends OsgiCommandSupport { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigureBgpCli.class); + + private static BgpManager bgpManager; + + public static void setBgpManager(BgpManager mgr) { + bgpManager = mgr; + } + + @Option(name = "-op", aliases = {"--operation","--op"}, description = "[start-bgp-server, stop-bgp-server, add-neighbor, delete-neighbor, graceful-restart, enable-log ]", + required = false, multiValued = false) + String op; + + //exec configure-bgp add-neighbor --ip --as-num --address-family --use-source-ip --ebgp-multihops --next-hop + + @Option(name = "--as-num", description = "as number of the bgp neighbor", required = false, multiValued = false) + String asNumber = null; + + @Option(name = "--ip", description = "ip of the bgp neighbor", required = false, multiValued = false) + String ip = null; + + @Option(name = "--address-family", description = "address family of the bgp neighbor SAFI_IPV4_LABELED_UNICAST|SAFI_MPLS_VPN", + required = false, multiValued = false) + String addressFamily = null; + + @Option(name = "--use-source-ip", description = "source ip to be used for neighborship connection establishment", + required = false, multiValued = false) + String sourceIp = null; + + @Option(name = "--ebgp-multihops", description = "ebgp multihops of the bgp neighbor", + required = false, multiValued = false) + String ebgpMultihops = null; + + @Option(name = "--router-id", description = "router id of the bgp instance", + required = false, multiValued = false) + String routerId = null; + + @Option(name = "--stalepath-time", description = "the time delay after bgp restart stalepaths are cleaned", + required = false, multiValued = false) + String stalePathTime = null; + + @Option(name = "--log-file-path", description = "bgp log file path", + required = false, multiValued = false) + String logFile = null; + + @Option(name = "--log-level", description = "log level emergencies,alerts,critical,errors,warnings,notifications,informational,debugging", + required = false, multiValued = false) + String logLevel = null; + + enum LogLevels { + emergencies,alerts,critical,errors,warnings,notifications,informational,debugging; + } + + @Override + protected Object doExecute() throws Exception { + try { + if (op == null) { + System.out.println("Please provide valid operation"); + usage(); + System.out.println("exec configure-bgp -op [start-bgp-server | stop-bgp-server | add-neighbor | delete-neighbor| graceful-restart| enable-log ]"); + } + switch(op) { + case "start-bgp-server": + startBgp(); + break; + case "stop-bgp-server": + stopBgp(); + break; + case "add-neighbor": + addNeighbor(); + break; + case "delete-neighbor": + deleteNeighbor(); + break; + case "graceful-restart": + configureGR(); + break; + case "enable-log" : + enableBgpLogLevel(); + break; + default : + System.out.println("invalid operation"); + usage(); + System.out.println("exec configure-bgp -op [start-bgp-server | stop-bgp-server | add-neighbor | delete-neighbor| graceful-restart| enable-log ]"); + } + } catch (Exception e) { + log.error("failed to handle the command",e); + } + return null; + } + + public boolean validateStalepathTime() { + try { + int time = Integer.parseInt(stalePathTime); + if (time < 30 || time > 3600) { + System.out.println("invalid stale path time valid range [30-3600]"); + printGracefulRestartHelp(); + return false; + } + } catch (Exception e) { + System.out.println("invalid stale path time"); + printGracefulRestartHelp(); + return false; + } + return true; + } + + private void configureGR() throws Exception { + boolean validStalepathTime = validateStalepathTime(); + if (!validStalepathTime) { + return; + } + bgpManager.configureGR(Integer.parseInt(stalePathTime)); + } + + private void deleteNeighbor() throws Exception { + if (ip == null || !validateIp(ip)) { + System.out.println("invalid neighbor ip"); + printDeleteNeighborHelp(); + return; + } + long asNo = getAsNumber(ip); + if (asNo < 0) { + System.out.println("neighbor does not exist"); + printDeleteNeighborHelp(); + return; + } + bgpManager.deleteNeighbor(ip); + } + + public long getAsNumber(String nbrIp) { + Bgp conf = bgpManager.getConfig(); + if (conf == null) { + return -1; + } + List nbrs = conf.getNeighbors(); + if (nbrs == null) { + return -1; + } + for (Neighbors nbr : nbrs) { + if (nbrIp.equals(nbr.getAddress().getValue())) { + return nbr.getRemoteAs().longValue(); + } + } + return -1; + } + + private void stopBgp() throws Exception { + Bgp conf = bgpManager.getConfig(); + if (conf == null) { + return; + } + List nbrs = conf.getNeighbors(); + if (nbrs != null && nbrs.size() > 0) { + System.err.println("error: all BGP congiguration must be deleted before stopping the router instance"); + return; + } + bgpManager.stopBgp(); + } + + void usage() { + System.out.println("usage:"); + } + + void printStartBgpHelp() { + usage(); + System.out.println("exec configure-bgp -op start-bgp-server --as-num --router-id [--stalepath-time