Implemented sequence number processing on the ONOS side. BGPd needs to be upgraded after this commit
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
index 826fd93..52c4bfd 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
@@ -143,7 +143,7 @@
private FlowCache flowCache;
protected volatile Map<Long, ?> topoRouteTopology = null;
-
+
protected class TopologyChangeDetector implements Runnable {
@Override
public void run() {
@@ -483,7 +483,7 @@
}
private void addPrefixFlows(Prefix prefix, Interface egressInterface, MACAddress nextHopMacAddress) {
- log.debug("Adding flows for prefix {} added, next hop mac {}",
+ log.debug("Adding flows for prefix {}, next hop mac {}",
prefix, nextHopMacAddress);
//We only need one flow mod per switch, so pick one interface on each switch
@@ -1120,10 +1120,22 @@
RibUpdate update = ribUpdates.take();
switch (update.getOperation()){
case UPDATE:
- processRibAdd(update);
+ if (validateUpdate(update)) {
+ processRibAdd(update);
+ }
+ else {
+ log.debug("Rib UPDATE out of order: {} via {}",
+ update.getPrefix(), update.getRibEntry().getNextHop());
+ }
break;
case DELETE:
- processRibDelete(update);
+ if (validateUpdate(update)) {
+ processRibDelete(update);
+ }
+ else {
+ log.debug("Rib DELETE out of order: {} via {}",
+ update.getPrefix(), update.getRibEntry().getNextHop());
+ }
break;
}
} catch (InterruptedException e) {
@@ -1139,6 +1151,40 @@
}
}
}
+
+ private boolean validateUpdate(RibUpdate update) {
+ RibEntry newEntry = update.getRibEntry();
+ RibEntry oldEntry = ptree.lookup(update.getPrefix());
+
+ //If there is no existing entry we must assume this is the most recent
+ //update. However this might not always be the case as we might have a
+ //POST then DELETE reordering.
+ //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
+ if (oldEntry == null) {
+ return true;
+ }
+
+ // This handles the case where routes are gathered in the initial
+ // request because they don't have sequence number info
+ if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
+ return true;
+ }
+
+ if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
+ return true;
+ }
+ else if (newEntry.getSysUpTime() == oldEntry.getSysUpTime()) {
+ if (newEntry.getSequenceNum() > oldEntry.getSequenceNum()) {
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ else {
+ return false;
+ }
+ }
@Override
public void topologyChanged() {
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteResource.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteResource.java
index 8403f71..c1f0cd6 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteResource.java
@@ -68,19 +68,27 @@
IBgpRouteService bgpRoute = (IBgpRouteService) getContext().getAttributes().
get(IBgpRouteService.class.getCanonicalName());
+ String strSysuptime = (String) getRequestAttributes().get("sysuptime");
+ String strSequence = (String) getRequestAttributes().get("sequence");
String routerId = (String) getRequestAttributes().get("routerid");
String prefix = (String) getRequestAttributes().get("prefix");
String mask = (String) getRequestAttributes().get("mask");
String nexthop = (String) getRequestAttributes().get("nexthop");
String capability = (String) getRequestAttributes().get("capability");
+
+ log.debug("sysuptime: {}", strSysuptime);
+ log.debug("sequence: {}", strSequence);
String reply = "";
if (capability == null) {
// this is a prefix add
Prefix p;
+ long sysUpTime, sequenceNum;
try {
p = new Prefix(prefix, Integer.valueOf(mask));
+ sysUpTime = Long.parseLong(strSysuptime);
+ sequenceNum = Long.parseLong(strSequence);
} catch (NumberFormatException e) {
reply = "[POST: mask format is wrong]";
log.info(reply);
@@ -91,7 +99,7 @@
return reply + "\n";
}
- RibEntry rib = new RibEntry(routerId, nexthop);
+ RibEntry rib = new RibEntry(routerId, nexthop, sysUpTime, sequenceNum);
bgpRoute.newRibUpdate(new RibUpdate(Operation.UPDATE, p, rib));
@@ -117,19 +125,27 @@
IBgpRouteService bgpRoute = (IBgpRouteService)getContext().getAttributes().
get(IBgpRouteService.class.getCanonicalName());
+ String strSysuptime = (String) getRequestAttributes().get("sysuptime");
+ String strSequence = (String) getRequestAttributes().get("sequence");
String routerId = (String) getRequestAttributes().get("routerid");
String prefix = (String) getRequestAttributes().get("prefix");
String mask = (String) getRequestAttributes().get("mask");
String nextHop = (String) getRequestAttributes().get("nexthop");
String capability = (String) getRequestAttributes().get("capability");
+ log.debug("sysuptime: {}", strSysuptime);
+ log.debug("sequence: {}", strSequence);
+
String reply = "";
if (capability == null) {
// this is a prefix delete
Prefix p;
+ long sysUpTime, sequenceNum;
try {
p = new Prefix(prefix, Integer.valueOf(mask));
+ sysUpTime = Long.parseLong(strSysuptime);
+ sequenceNum = Long.parseLong(strSequence);
} catch (NumberFormatException e) {
reply = "[DELE: mask format is wrong]";
log.info(reply);
@@ -140,7 +156,7 @@
return reply + "\n";
}
- RibEntry r = new RibEntry(routerId, nextHop);
+ RibEntry r = new RibEntry(routerId, nextHop, sysUpTime, sequenceNum);
bgpRoute.newRibUpdate(new RibUpdate(Operation.DELETE, p, r));
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteWebRoutable.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteWebRoutable.java
index 669c385..26971b0 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteWebRoutable.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteWebRoutable.java
@@ -12,7 +12,7 @@
Router router = new Router(context);
router.attach("/json", BgpRouteResource.class);
router.attach("/rib/{dest}", BgpRouteResource.class);
- router.attach("/{routerid}/{prefix}/{mask}/{nexthop}", BgpRouteResource.class);
+ router.attach("/{sysuptime}/{sequence}/{routerid}/{prefix}/{mask}/{nexthop}", BgpRouteResource.class);
router.attach("/{routerid}/{prefix}/{mask}/{nexthop}/synch", BgpRouteResourceSynch.class);
router.attach("/{routerid}/{capability}", BgpRouteResource.class);
return router;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/RibEntry.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/RibEntry.java
index 1520c60..ccf8951 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/RibEntry.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/RibEntry.java
@@ -7,21 +7,57 @@
public class RibEntry {
private final InetAddress routerId;
private final InetAddress nextHop;
+
+ /*
+ * Store the sequence number information provided on the update here for
+ * now. I think this *should* really be in the RibUpdate, and we should
+ * store RibUpdates in the Ptrie. But, that's a bigger change to change
+ * what the Ptrie stores.
+ */
+ private final long sysUpTime;
+ private final long sequenceNum;
+
+ /*
+ * Marker for RibEntries where we don't have sequence number info.
+ * The user of this class should make sure they don't check this data
+ * if they don't provide it.
+ */
+ private final static long NULL_TIME = -1;
public RibEntry(InetAddress routerId, InetAddress nextHop) {
this.routerId = routerId;
this.nextHop = nextHop;
+ sequenceNum = NULL_TIME;
+ sysUpTime = NULL_TIME;
}
public RibEntry(String routerId, String nextHop) {
this.routerId = InetAddresses.forString(routerId);
this.nextHop = InetAddresses.forString(nextHop);
+ sequenceNum = NULL_TIME;
+ sysUpTime = NULL_TIME;
+ }
+
+ public RibEntry(String routerId, String nextHop, long sysUpTime
+ , long sequenceNum) {
+ this.routerId = InetAddresses.forString(routerId);
+ this.nextHop = InetAddresses.forString(nextHop);
+ this.sequenceNum = sequenceNum;
+ this.sysUpTime = sysUpTime;
}
public InetAddress getNextHop() {
return nextHop;
}
+ public long getSysUpTime() {
+ return sysUpTime;
+ }
+
+ public long getSequenceNum() {
+ return sequenceNum;
+ }
+
@Override
public boolean equals(Object other) {
if (other == null || !(other instanceof RibEntry)) {