mirror of
https://github.com/opennetworkinglab/onos.git
synced 2025-12-06 18:01:53 +01:00
[ONOS-8085] Route Refresh timers in Controller
- Add timers in BgpController - Add triggers in BgpLocalRib - Code to send Route Refresh messages Change-Id: Id45f1bcb3325ccc21c0d0d2e673c2b0097aac552
This commit is contained in:
parent
dcd56ba4ce
commit
2d7ff64d09
@ -221,4 +221,9 @@ public interface BgpController {
|
|||||||
*/
|
*/
|
||||||
Set<BgpRouteListener> routeListener();
|
Set<BgpRouteListener> routeListener();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to notify the controller if the topology has changed.
|
||||||
|
* Controller will decide if route-refresh needs to be triggered
|
||||||
|
*/
|
||||||
|
void notifyTopologyChange();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -155,4 +155,9 @@ public interface BgpPeer {
|
|||||||
void updateEvpnNlri(FlowSpecOperation operType, IpAddress nextHop,
|
void updateEvpnNlri(FlowSpecOperation operType, IpAddress nextHop,
|
||||||
List<BgpValueType> extcommunity,
|
List<BgpValueType> extcommunity,
|
||||||
List<BgpEvpnNlri> evpnNlris);
|
List<BgpEvpnNlri> evpnNlris);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the Route Refresh message to the connected BGP peer.
|
||||||
|
*/
|
||||||
|
void sendRouteRefreshMessage();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,8 @@ public final class Constants {
|
|||||||
private Constants() {
|
private Constants() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final byte EMPTY = 0x00; //Empty byte
|
||||||
|
|
||||||
public static final short TYPE_AND_LEN = 4;
|
public static final short TYPE_AND_LEN = 4;
|
||||||
public static final short TYPE_AND_LEN_AS_SHORT = 4;
|
public static final short TYPE_AND_LEN_AS_SHORT = 4;
|
||||||
public static final short TYPE_AND_LEN_AS_BYTE = 3;
|
public static final short TYPE_AND_LEN_AS_BYTE = 3;
|
||||||
|
|||||||
@ -46,9 +46,16 @@ import java.util.Set;
|
|||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
import static org.onlab.util.Tools.groupedThreads;
|
||||||
|
|
||||||
@Component(immediate = true, service = BgpController.class)
|
@Component(immediate = true, service = BgpController.class)
|
||||||
public class BgpControllerImpl implements BgpController {
|
public class BgpControllerImpl implements BgpController {
|
||||||
|
|
||||||
@ -72,6 +79,19 @@ public class BgpControllerImpl implements BgpController {
|
|||||||
private Map<String, List<String>> closedSessionExceptionMap = new TreeMap<>();
|
private Map<String, List<String>> closedSessionExceptionMap = new TreeMap<>();
|
||||||
protected Set<BgpRouteListener> bgpRouteListener = new CopyOnWriteArraySet<>();
|
protected Set<BgpRouteListener> bgpRouteListener = new CopyOnWriteArraySet<>();
|
||||||
|
|
||||||
|
//IDs for timers
|
||||||
|
private static final int PERIODIC_TIMER = 1001;
|
||||||
|
private static final int WARMUP_TIMER = 1002;
|
||||||
|
private static final int COOLDOWN_TIMER = 1003;
|
||||||
|
|
||||||
|
private static final int POOL_SIZE = 3; //Current pool size is 3
|
||||||
|
private ScheduledExecutorService executor;
|
||||||
|
private ScheduledFuture<?> cooldownFuture;
|
||||||
|
private ScheduledFuture<?> periodicFuture;
|
||||||
|
private ScheduledFuture<?> warmupFuture;
|
||||||
|
|
||||||
|
private AtomicBoolean hasTopologyChanged = new AtomicBoolean(false);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void activeSessionExceptionAdd(String peerId, String exception) {
|
public void activeSessionExceptionAdd(String peerId, String exception) {
|
||||||
if (peerId != null) {
|
if (peerId != null) {
|
||||||
@ -131,6 +151,9 @@ public class BgpControllerImpl implements BgpController {
|
|||||||
@Activate
|
@Activate
|
||||||
public void activate() {
|
public void activate() {
|
||||||
this.ctrl.start();
|
this.ctrl.start();
|
||||||
|
executor = Executors.newScheduledThreadPool(
|
||||||
|
POOL_SIZE,
|
||||||
|
groupedThreads("onos/apps/bgpcontroller", "bgp-rr-timer"));
|
||||||
log.info("Started");
|
log.info("Started");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,6 +164,7 @@ public class BgpControllerImpl implements BgpController {
|
|||||||
// Close all connected peers
|
// Close all connected peers
|
||||||
closeConnectedPeers();
|
closeConnectedPeers();
|
||||||
this.ctrl.stop();
|
this.ctrl.stop();
|
||||||
|
executor.shutdown();
|
||||||
log.info("Stopped");
|
log.info("Stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,6 +289,17 @@ public class BgpControllerImpl implements BgpController {
|
|||||||
} else {
|
} else {
|
||||||
this.log.debug("Added Peer {}", bgpId.toString());
|
this.log.debug("Added Peer {}", bgpId.toString());
|
||||||
connectedPeers.put(bgpId, bgpPeer);
|
connectedPeers.put(bgpId, bgpPeer);
|
||||||
|
|
||||||
|
//If all timers are stopped, start periodic timer
|
||||||
|
this.log.info("Start periodic timer");
|
||||||
|
if (bgpconfig.isRouteRefreshEnabled()
|
||||||
|
&& (periodicFuture == null || periodicFuture.isCancelled())
|
||||||
|
&& (cooldownFuture == null || cooldownFuture.isCancelled())
|
||||||
|
&& (warmupFuture == null || warmupFuture.isCancelled())) {
|
||||||
|
periodicFuture = executor.schedule(periodicTimerTask,
|
||||||
|
bgpconfig.getRouteRefreshPeriodicTimer(), TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -383,4 +418,143 @@ public class BgpControllerImpl implements BgpController {
|
|||||||
public Set<BgpPrefixListener> prefixListener() {
|
public Set<BgpPrefixListener> prefixListener() {
|
||||||
return bgpPrefixListener;
|
return bgpPrefixListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyTopologyChange() {
|
||||||
|
log.info("Topology change received");
|
||||||
|
|
||||||
|
hasTopologyChanged.set(true);
|
||||||
|
|
||||||
|
//If cooldown timer is running, do nothing further because routeRefresh will be sent when it expires
|
||||||
|
if (cooldownFuture != null && !cooldownFuture.isCancelled()) {
|
||||||
|
log.debug("Do nothing : Cooldown timer running");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//If warmup timer is running, refresh it. If not, start it
|
||||||
|
if (warmupFuture != null && !warmupFuture.isCancelled()) {
|
||||||
|
warmupFuture.cancel(true);
|
||||||
|
warmupFuture = null;
|
||||||
|
|
||||||
|
warmupFuture = executor.schedule(warmupTimerTask,
|
||||||
|
bgpconfig.getRouteRefreshWarmupTimer(), TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
log.debug("Warmup timer running. Re-started warmup timer");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
warmupFuture = executor.schedule(warmupTimerTask,
|
||||||
|
bgpconfig.getRouteRefreshWarmupTimer(), TimeUnit.SECONDS);
|
||||||
|
log.debug("Warmup timer started");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void resetTimers() {
|
||||||
|
if (periodicFuture != null && !periodicFuture.isCancelled()) {
|
||||||
|
periodicFuture.cancel(true);
|
||||||
|
periodicFuture = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (warmupFuture != null && !warmupFuture.isCancelled()) {
|
||||||
|
warmupFuture.cancel(true);
|
||||||
|
warmupFuture = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cooldownFuture != null && !cooldownFuture.isCancelled()) {
|
||||||
|
cooldownFuture.cancel(true);
|
||||||
|
cooldownFuture = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected synchronized void timerCallback(int timerId) {
|
||||||
|
switch (timerId) {
|
||||||
|
case PERIODIC_TIMER:
|
||||||
|
//Cancel periodic timer and run cooldown timer
|
||||||
|
periodicFuture.cancel(true);
|
||||||
|
periodicFuture = null;
|
||||||
|
|
||||||
|
sendRouteRefreshToPeers();
|
||||||
|
|
||||||
|
//Cancel warmup timer if it is running
|
||||||
|
if (warmupFuture != null && !warmupFuture.isCancelled()) {
|
||||||
|
warmupFuture.cancel(true);
|
||||||
|
warmupFuture = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
cooldownFuture = executor.schedule(cooldownTimerTask,
|
||||||
|
bgpconfig.getRouteRefreshCooldownTimer(), TimeUnit.SECONDS);
|
||||||
|
log.debug("Cooldown timer started");
|
||||||
|
break;
|
||||||
|
case WARMUP_TIMER:
|
||||||
|
//Send route refresh and start cooldown timer
|
||||||
|
warmupFuture.cancel(true);
|
||||||
|
warmupFuture = null;
|
||||||
|
|
||||||
|
sendRouteRefreshToPeers();
|
||||||
|
|
||||||
|
cooldownFuture = executor.schedule(cooldownTimerTask,
|
||||||
|
bgpconfig.getRouteRefreshCooldownTimer(), TimeUnit.SECONDS);
|
||||||
|
//Cancel periodic timer, if it is running
|
||||||
|
if (periodicFuture != null && !periodicFuture.isCancelled()) {
|
||||||
|
periodicFuture.cancel(true);
|
||||||
|
periodicFuture = null;
|
||||||
|
}
|
||||||
|
log.debug("Cooldown timer started");
|
||||||
|
break;
|
||||||
|
case COOLDOWN_TIMER:
|
||||||
|
//If hasTopologyChanged is true, we need to restart cooldown timer.
|
||||||
|
//Otherwise, start periodic timer
|
||||||
|
boolean hasTopologyChangedValue = hasTopologyChanged.get();
|
||||||
|
|
||||||
|
cooldownFuture.cancel(true);
|
||||||
|
cooldownFuture = null;
|
||||||
|
|
||||||
|
if (hasTopologyChangedValue) {
|
||||||
|
sendRouteRefreshToPeers();
|
||||||
|
cooldownFuture = executor.schedule(cooldownTimerTask,
|
||||||
|
bgpconfig.getRouteRefreshCooldownTimer(), TimeUnit.SECONDS);
|
||||||
|
log.debug("Cooldown timer started");
|
||||||
|
} else {
|
||||||
|
periodicFuture = executor.schedule(periodicTimerTask,
|
||||||
|
bgpconfig.getRouteRefreshPeriodicTimer(), TimeUnit.SECONDS);
|
||||||
|
log.debug("Periodic timer started");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log.error("Invalid timerId in callback");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void sendRouteRefreshToPeers() {
|
||||||
|
//Iterate over peers and send route refresh
|
||||||
|
connectedPeers.forEach((k, v) -> v.sendRouteRefreshMessage());
|
||||||
|
|
||||||
|
//Refresh hasTopologyChanged variable
|
||||||
|
hasTopologyChanged.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Runnable periodicTimerTask = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
log.debug("Periodic Timer Expired");
|
||||||
|
timerCallback(PERIODIC_TIMER);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private Runnable cooldownTimerTask = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
log.info("Cooldown Timer Expired");
|
||||||
|
timerCallback(COOLDOWN_TIMER);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private Runnable warmupTimerTask = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
log.debug("Warmup Timer Expired");
|
||||||
|
timerCallback(WARMUP_TIMER);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -153,7 +153,8 @@ public class BgpLocalRibImpl implements BgpLocalRib {
|
|||||||
for (BgpNodeListener l : bgpController.listener()) {
|
for (BgpNodeListener l : bgpController.listener()) {
|
||||||
l.addNode((BgpNodeLSNlriVer4) nlri, details);
|
l.addNode((BgpNodeLSNlriVer4) nlri, details);
|
||||||
}
|
}
|
||||||
log.debug("Local RIB ad node: {}", detailsLocRib.toString());
|
bgpController.notifyTopologyChange();
|
||||||
|
log.debug("Local RIB add node: {}", detailsLocRib.toString());
|
||||||
}
|
}
|
||||||
} else if (nlri instanceof BgpLinkLsNlriVer4) {
|
} else if (nlri instanceof BgpLinkLsNlriVer4) {
|
||||||
BgpLinkLSIdentifier linkLsIdentifier = ((BgpLinkLsNlriVer4) nlri).getLinkIdentifier();
|
BgpLinkLSIdentifier linkLsIdentifier = ((BgpLinkLsNlriVer4) nlri).getLinkIdentifier();
|
||||||
@ -173,6 +174,7 @@ public class BgpLocalRibImpl implements BgpLocalRib {
|
|||||||
for (BgpLinkListener l : bgpController.linkListener()) {
|
for (BgpLinkListener l : bgpController.linkListener()) {
|
||||||
l.addLink((BgpLinkLsNlriVer4) nlri, details);
|
l.addLink((BgpLinkLsNlriVer4) nlri, details);
|
||||||
}
|
}
|
||||||
|
bgpController.notifyTopologyChange();
|
||||||
log.debug("Local RIB add link: {}", detailsLocRib.toString());
|
log.debug("Local RIB add link: {}", detailsLocRib.toString());
|
||||||
}
|
}
|
||||||
} else if (nlri instanceof BgpPrefixIPv4LSNlriVer4) {
|
} else if (nlri instanceof BgpPrefixIPv4LSNlriVer4) {
|
||||||
@ -314,6 +316,7 @@ public class BgpLocalRibImpl implements BgpLocalRib {
|
|||||||
l.deleteNode((BgpNodeLSNlriVer4) nlri);
|
l.deleteNode((BgpNodeLSNlriVer4) nlri);
|
||||||
}
|
}
|
||||||
nodeTree.remove(nodeLsIdentifier);
|
nodeTree.remove(nodeLsIdentifier);
|
||||||
|
bgpController.notifyTopologyChange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,7 +382,7 @@ public class BgpLocalRibImpl implements BgpLocalRib {
|
|||||||
l.deleteLink((BgpLinkLsNlriVer4) nlri);
|
l.deleteLink((BgpLinkLsNlriVer4) nlri);
|
||||||
}
|
}
|
||||||
linkTree.remove(linkLsIdentifier);
|
linkTree.remove(linkLsIdentifier);
|
||||||
|
bgpController.notifyTopologyChange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -46,6 +46,7 @@ import org.onosproject.bgpio.types.Med;
|
|||||||
import org.onosproject.bgpio.types.MpReachNlri;
|
import org.onosproject.bgpio.types.MpReachNlri;
|
||||||
import org.onosproject.bgpio.types.MpUnReachNlri;
|
import org.onosproject.bgpio.types.MpUnReachNlri;
|
||||||
import org.onosproject.bgpio.types.MultiProtocolExtnCapabilityTlv;
|
import org.onosproject.bgpio.types.MultiProtocolExtnCapabilityTlv;
|
||||||
|
import org.onosproject.bgpio.types.RouteRefreshCapabilityTlv;
|
||||||
import org.onosproject.bgpio.types.Origin;
|
import org.onosproject.bgpio.types.Origin;
|
||||||
import org.onosproject.bgpio.types.RpdCapabilityTlv;
|
import org.onosproject.bgpio.types.RpdCapabilityTlv;
|
||||||
import org.onosproject.bgpio.types.attr.WideCommunity;
|
import org.onosproject.bgpio.types.attr.WideCommunity;
|
||||||
@ -160,6 +161,19 @@ public class BgpPeerImpl implements BgpPeer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final boolean isRouteRefreshSupported() {
|
||||||
|
List<BgpValueType> capabilities = sessionInfo.remoteBgpCapability();
|
||||||
|
|
||||||
|
for (BgpValueType currentCapability : capabilities) {
|
||||||
|
if (currentCapability instanceof RouteRefreshCapabilityTlv) {
|
||||||
|
//Presence of Reoute Refresh capability TLV means route refresh is supported
|
||||||
|
log.debug("Route Refresh is supported by peer");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send flow specification update message to peer.
|
* Send flow specification update message to peer.
|
||||||
*
|
*
|
||||||
@ -319,6 +333,24 @@ public class BgpPeerImpl implements BgpPeer {
|
|||||||
channel.write(Collections.singletonList(msg));
|
channel.write(Collections.singletonList(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendRouteRefreshMessage() {
|
||||||
|
if (!isRouteRefreshSupported()) {
|
||||||
|
log.debug("Route Refresh not supported by peer, so cannot send message");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BgpMessage msg = Controller.getBgpMessageFactory4()
|
||||||
|
.routeRefreshMsgBuilder()
|
||||||
|
.addAfiSafiValue(Constants.AFI_IPV6_UNICAST, Constants.EMPTY, Constants.SAFI_UNICAST)
|
||||||
|
.addAfiSafiValue(Constants.AFI_VALUE, Constants.EMPTY, Constants.SAFI_VALUE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
channel.write(Collections.singletonList(msg));
|
||||||
|
|
||||||
|
log.info("Route Refresh sent to {}", channelId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void buildAdjRibIn(List<BgpValueType> pathAttr) throws BgpParseException {
|
public void buildAdjRibIn(List<BgpValueType> pathAttr) throws BgpParseException {
|
||||||
ListIterator<BgpValueType> iterator = pathAttr.listIterator();
|
ListIterator<BgpValueType> iterator = pathAttr.listIterator();
|
||||||
|
|||||||
@ -181,4 +181,9 @@ public class BgpControllerAdapter implements BgpController {
|
|||||||
public void removePrefixListener(BgpPrefixListener listener) {
|
public void removePrefixListener(BgpPrefixListener listener) {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyTopologyChange() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user