Merge branch 'routeserver'
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 c36d4a5..278fb86 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
@@ -19,7 +19,6 @@
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.core.IOFSwitchListener;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.module.FloodlightModuleException;
import net.floodlightcontroller.core.module.IFloodlightModule;
@@ -71,11 +70,11 @@
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
+import com.google.common.net.InetAddresses;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
public class BgpRoute implements IFloodlightModule, IBgpRouteService,
- ITopologyListener, IOFSwitchListener,
- IArpRequester {
+ ITopologyListener, IArpRequester {
protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
@@ -87,8 +86,8 @@
protected ProxyArpManager proxyArp;
- //protected static Ptree ptree;
- protected IPatriciaTrie ptree;
+ protected IPatriciaTrie<RibEntry> ptree;
+ protected IPatriciaTrie<Interface> interfacePtrie;
protected BlockingQueue<RibUpdate> ribUpdates;
protected String bgpdRestIp;
@@ -127,30 +126,15 @@
protected SingletonTask topologyChangeDetectorTask;
protected SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
- protected SetMultimap<InetAddress, PathUpdate> pathsWaitingOnArp;
+
+ protected Map<InetAddress, Path> pathsWaitingOnArp;
protected ExecutorService bgpUpdatesExecutor;
+ protected Map<InetAddress, Path> pushedPaths;
+ protected Map<Prefix, Path> prefixToPath;
protected Multimap<Prefix, PushedFlowMod> pushedFlows;
-
- private class PushedFlowMod {
- private long dpid;
- private OFFlowMod flowMod;
- public PushedFlowMod(long dpid, OFFlowMod flowMod) {
- this.dpid = dpid;
- this.flowMod = flowMod;
- }
-
- public long getDpid() {
- return dpid;
- }
-
- public OFFlowMod getFlowMod() {
- return flowMod;
- }
- }
-
protected class TopologyChangeDetector implements Runnable {
@Override
public void run() {
@@ -219,6 +203,12 @@
log.error("Error reading JSON file", e);
System.exit(1);
}
+
+ //Populate the interface Patricia Trie
+ for (Interface intf : interfaces.values()) {
+ Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
+ interfacePtrie.put(prefix, intf);
+ }
}
@Override
@@ -252,8 +242,8 @@
public void init(FloodlightModuleContext context)
throws FloodlightModuleException {
- //ptree = new Ptree(32);
- ptree = new PatriciaTrie(32);
+ ptree = new PatriciaTrie<RibEntry>(32);
+ interfacePtrie = new PatriciaTrie<Interface>(32);
ribUpdates = new LinkedBlockingQueue<RibUpdate>();
@@ -273,11 +263,12 @@
topoRouteService = new TopoRouteService("");
- pathsWaitingOnArp = Multimaps.synchronizedSetMultimap(
- HashMultimap.<InetAddress, PathUpdate>create());
+ pathsWaitingOnArp = new HashMap<InetAddress, Path>();
prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
HashMultimap.<InetAddress, RibUpdate>create());
+ pushedPaths = new HashMap<InetAddress, Path>();
+ prefixToPath = new HashMap<Prefix, Path>();
pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
@@ -309,19 +300,25 @@
log.debug("Config file set to {}", configFilename);
readGatewaysConfiguration(configFilename);
- // Test.
- //test();
+ }
+
+ @Override
+ public void startUp(FloodlightModuleContext context) {
+ restApi.addRestletRoutable(new BgpRouteWebRoutable());
+ topology.addListener(this);
+
+ floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
+
+ //Retrieve the RIB from BGPd during startup
+ retrieveRib();
}
- //public Ptree getPtree() {
- public IPatriciaTrie getPtree() {
+ public IPatriciaTrie<RibEntry> getPtree() {
return ptree;
}
public void clearPtree() {
- //ptree = null;
- //ptree = new Ptree(32);
- ptree = new PatriciaTrie(32);
+ ptree = new PatriciaTrie<RibEntry>(32);
}
public String getBGPdRestIp() {
@@ -332,105 +329,6 @@
return routerId;
}
- // Return nexthop address as byte array.
- /*
- public RibEntry lookupRib(byte[] dest) {
- if (ptree == null) {
- log.debug("lookupRib: ptree null");
- return null;
- }
-
- PtreeNode node = ptree.match(dest, 32);
- if (node == null) {
- log.debug("lookupRib: ptree node null");
- return null;
- }
-
- if (node.rib == null) {
- log.debug("lookupRib: ptree rib null");
- return null;
- }
-
- ptree.delReference(node);
-
- return node.rib;
- }
- */
-
- /*
- //TODO looks like this should be a unit test
- @SuppressWarnings("unused")
- private void test() throws UnknownHostException {
- System.out.println("Here it is");
- Prefix p = new Prefix("128.0.0.0", 8);
- Prefix q = new Prefix("8.0.0.0", 8);
- Prefix r = new Prefix("10.0.0.0", 24);
- Prefix a = new Prefix("10.0.0.1", 32);
-
- ptree.acquire(p.getAddress(), p.getPrefixLength());
- ptree.acquire(q.getAddress(), q.getPrefixLength());
- ptree.acquire(r.getAddress(), r.getPrefixLength());
-
- System.out.println("Traverse start");
- for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
- Prefix p_result = new Prefix(node.key, node.keyBits);
- }
-
- PtreeNode n = ptree.match(a.getAddress(), a.getPrefixLength());
- if (n != null) {
- System.out.println("Matched prefix for 10.0.0.1:");
- Prefix x = new Prefix(n.key, n.keyBits);
- ptree.delReference(n);
- }
-
- n = ptree.lookup(p.getAddress(), p.getPrefixLength());
- if (n != null) {
- ptree.delReference(n);
- ptree.delReference(n);
- }
- System.out.println("Traverse start");
- for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
- Prefix p_result = new Prefix(node.key, node.keyBits);
- }
-
- n = ptree.lookup(q.getAddress(), q.getPrefixLength());
- if (n != null) {
- ptree.delReference(n);
- ptree.delReference(n);
- }
- System.out.println("Traverse start");
- for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
- Prefix p_result = new Prefix(node.key, node.keyBits);
- }
-
- n = ptree.lookup(r.getAddress(), r.getPrefixLength());
- if (n != null) {
- ptree.delReference(n);
- ptree.delReference(n);
- }
- System.out.println("Traverse start");
- for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
- Prefix p_result = new Prefix(node.key, node.keyBits);
- }
-
- }
- */
-
- //TODO once the Ptree is object oriented this can go
- /*
- private String getPrefixFromPtree(PtreeNode node){
- InetAddress address = null;
- try {
- address = InetAddress.getByAddress(node.key);
- } catch (UnknownHostException e1) {
- //Should never happen is the reverse conversion has already been done
- log.error("Malformed IP address");
- return "";
- }
- return address.toString() + "/" + node.rib.masklen;
- }
- */
-
private void retrieveRib(){
String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
String response = RestClient.get(url);
@@ -469,21 +367,8 @@
continue;
}
- //PtreeNode node = ptree.acquire(p.getAddress(), p.getPrefixLength());
RibEntry rib = new RibEntry(router_id, nexthop);
-
- /*
- if (node.rib != null) {
- node.rib = null;
- ptree.delReference(node);
- }
-
- node.rib = rib;
- */
-
- //ptree.put(p, rib);
-
- //addPrefixFlows(p, rib);
+
try {
ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
} catch (InterruptedException e) {
@@ -497,8 +382,8 @@
try {
ribUpdates.put(update);
} catch (InterruptedException e) {
- // TODO Auto-generated catch block
- log.debug(" ", e);
+ log.debug("Interrupted while putting on ribUpdates queue", e);
+ Thread.currentThread().interrupt();
}
}
@@ -507,140 +392,105 @@
log.debug("Processing prefix add {}", prefix);
- //PtreeNode node = ptree.acquire(prefix.getAddress(), prefix.getPrefixLength());
RibEntry rib = ptree.put(prefix, update.getRibEntry());
- //if (node.rib != null) {
if (rib != null && !rib.equals(update.getRibEntry())) {
//There was an existing nexthop for this prefix. This update supersedes that,
//so we need to remove the old flows for this prefix from the switches
- deletePrefixFlows(prefix);
-
- //Then remove the old nexthop from the Ptree
- //node.rib = null;
- //ptree.delReference(node);
+ _processDeletePrefix(prefix, rib);
}
- //Put the new nexthop in the Ptree
- //node.rib = update.getRibEntry();
-
- //Push flows for the new <prefix, nexthop>
- addPrefixFlows(prefix, update.getRibEntry());
+ if (update.getRibEntry().getNextHop().equals(
+ InetAddresses.forString("0.0.0.0"))) {
+ //Route originated by SDN domain
+ //We don't handle these at the moment
+ log.debug("Own route {} to {}", prefix,
+ update.getRibEntry().getNextHop().getHostAddress());
+ return;
+ }
+
+ _processRibAdd(update);
}
- public synchronized void processRibDelete(RibUpdate update) {
+ private void _processRibAdd(RibUpdate update) {
Prefix prefix = update.getPrefix();
+ RibEntry rib = update.getRibEntry();
- //PtreeNode node = ptree.lookup(prefix.getAddress(), prefix.getPrefixLength());
+ InetAddress dstIpAddress = rib.getNextHop();
- /*
- * Remove the flows from the switches before the rib is lost
- * Theory: we could get a delete for a prefix not in the Ptree.
- * This would result in a null node being returned. We could get a delete for
- * a node that's not actually there, but is a aggregate node. This would result
- * in a non-null node with a null rib. Only a non-null node with a non-null
- * rib is an actual prefix in the Ptree.
- */
-
- /*
- if (node != null && node.rib != null) {
- if (update.getRibEntry().equals(node.rib)) {
- node.rib = null;
- ptree.delReference(node);
-
- deletePrefixFlows(update.getPrefix());
+ //See if we know the MAC address of the next hop
+ byte[] nextHopMacAddress = proxyArp.getMacAddress(rib.getNextHop());
+
+ //Find the attachment point (egress interface) of the next hop
+ Interface egressInterface = null;
+ if (bgpPeers.containsKey(dstIpAddress)) {
+ //Route to a peer
+ log.debug("Route to peer {}", dstIpAddress);
+ BgpPeer peer = bgpPeers.get(dstIpAddress);
+ egressInterface = interfaces.get(peer.getInterfaceName());
+ }
+ else {
+ //Route to non-peer
+ log.debug("Route to non-peer {}", dstIpAddress);
+ egressInterface = interfacePtrie.match(
+ new Prefix(dstIpAddress.getAddress(), 32));
+ if (egressInterface == null) {
+ log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
+ return;
}
}
- */
- if (ptree.remove(prefix, update.getRibEntry())) {
- /*
- * Only delete flows if an entry was actually removed from the trie.
- * If no entry was removed, the <prefix, nexthop> wasn't there so
- * it's probably already been removed and we don't need to do anything
- */
- deletePrefixFlows(prefix);
+ if (nextHopMacAddress == null) {
+ prefixesWaitingOnArp.put(dstIpAddress,
+ new RibUpdate(Operation.UPDATE, prefix, rib));
+ proxyArp.sendArpRequest(dstIpAddress, this, true);
+ return;
+ }
+ else {
+ if (!bgpPeers.containsKey(dstIpAddress)) {
+ //If the prefix is for a non-peer we need to ensure there's a path,
+ //and push one if there isn't.
+ Path path = pushedPaths.get(dstIpAddress);
+ if (path == null) {
+ path = new Path(egressInterface, dstIpAddress);
+ setUpDataPath(path, MACAddress.valueOf(nextHopMacAddress));
+ pushedPaths.put(dstIpAddress, path);
+ }
+
+ path.incrementUsers();
+ prefixToPath.put(prefix, path);
+ }
+
+ //For all prefixes we need to add the first-hop mac-rewriting flows
+ addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
}
}
- //TODO compatibility layer, used by beginRouting()
- /*public void prefixAdded(PtreeNode node) {
- Prefix prefix = null;
- try {
- prefix = new Prefix(node.key, node.rib.masklen);
- } catch (IllegalArgumentException e) {
- log.error(" ", e);
- }
+ private void addPrefixFlows(Prefix prefix, Interface egressInterface, byte[] nextHopMacAddress) {
+ log.debug("Adding flows for prefix {} added, next hop mac {}",
+ prefix, HexString.toHexString(nextHopMacAddress));
- addPrefixFlows(prefix, node.rib);
- }*/
-
- private void addPrefixFlows(Prefix prefix, RibEntry rib) {
- if (!topologyReady){
- return;
- }
-
- //TODO before we do anything, we have to check that the RIB entry is still in the
- //Ptree because it could have been removed while we were waiting for ARP.
- //I think we'll have to make prefixAdded and prefixDelete atomic as well
- //to protect against the prefix getting deleted while where trying to add it
-
- log.debug("New prefix {} added, next hop {}",
- prefix, rib.getNextHop().getHostAddress());
-
- //TODO this is wrong, we shouldn't be dealing with BGP peers here.
- //We need to figure out where the device is attached and what its
- //mac address is by learning.
- //The next hop is not necessarily the peer, and the peer's attachment
- //point is not necessarily the next hop's attachment point.
- BgpPeer peer = bgpPeers.get(rib.getNextHop());
-
- if (peer == null){
- //TODO local router isn't in peers list so this will get thrown
- //Need to work out what to do about local prefixes with next hop 0.0.0.0.
-
- //The other scenario is this is a route server route. In that
- //case the next hop is not in our configuration
- log.error("Couldn't find next hop router in router {} in config",
- rib.getNextHop().getHostAddress());
- return; //just quit out here? This is probably a configuration error
- }
-
- //Get MAC address for peer from the ARP module
- //TODO separate out the 'ask for MAC' bit to another method
- byte[] peerMacAddress = proxyArp.getMacAddress(peer.getIpAddress());
- if (peerMacAddress == null) {
- //A RibUpdate is still a nice way to package them up
- prefixesWaitingOnArp.put(peer.getIpAddress(),
- new RibUpdate(Operation.UPDATE, prefix, rib));
- proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
- return;
- }
-
- Interface peerInterface = interfaces.get(peer.getInterfaceName());
-
- //Add a flow to rewrite mac for this prefix to all border switches
+ //Add a flow to rewrite mac for this prefix to all other border switches
for (Interface srcInterface : interfaces.values()) {
- if (srcInterface == peerInterface) {
+ if (srcInterface == egressInterface) {
//Don't push a flow for the switch where this peer is attached
continue;
}
DataPath shortestPath = topoRouteService.getShortestPath(
srcInterface.getSwitchPort(),
- peerInterface.getSwitchPort());
+ egressInterface.getSwitchPort());
if (shortestPath == null){
log.debug("Shortest path between {} and {} not found",
srcInterface.getSwitchPort(),
- peerInterface.getSwitchPort());
+ egressInterface.getSwitchPort());
return; // just quit here?
}
//Set up the flow mod
- OFFlowMod fm =
- (OFFlowMod) floodlightProvider.getOFMessageFactory()
- .getMessage(OFType.FLOW_MOD);
+ OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
+ .getMessage(OFType.FLOW_MOD);
fm.setIdleTimeout((short)0)
.setHardTimeout((short)0)
@@ -656,30 +506,16 @@
match.setDataLayerType(Ethernet.TYPE_IPv4);
match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
- /*
- InetAddress address = null;
- try {
- address = InetAddress.getByAddress(prefix.getAddress());
- } catch (UnknownHostException e1) {
- //Should never happen is the reverse conversion has already been done
- log.error("Malformed IP address");
- return;
- }*/
-
- //match.setFromCIDR(address.getHostAddress() + "/" +
- // prefix.getPrefixLength(), OFMatch.STR_NW_DST);
match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
fm.setMatch(match);
//Set up MAC rewrite action
OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
- //TODO the peer's mac address is not necessarily the next hop's...
- macRewriteAction.setDataLayerAddress(peerMacAddress);
+ macRewriteAction.setDataLayerAddress(nextHopMacAddress);
//Set up output action
OFActionOutput outputAction = new OFActionOutput();
outputAction.setMaxLength((short)0xffff);
-
Port outputPort = shortestPath.flowEntries().get(0).outPort();
outputAction.setPort(outputPort.value());
@@ -697,7 +533,6 @@
continue;
}
- //TODO if prefix Added/Deleted are synchronized this shouldn't have to be
pushedFlows.put(prefix, new PushedFlowMod(sw.getId(), fm));
List<OFMessage> msglist = new ArrayList<OFMessage>();
@@ -711,20 +546,41 @@
}
}
- //TODO test next-hop changes
- //TODO check delete/add synchronization
+ public synchronized void processRibDelete(RibUpdate update) {
+ Prefix prefix = update.getPrefix();
- private void deletePrefixFlows(Prefix prefix) {
- if (!topologyReady) {
- return;
+ if (ptree.remove(prefix, update.getRibEntry())) {
+ /*
+ * Only delete flows if an entry was actually removed from the trie.
+ * If no entry was removed, the <prefix, nexthop> wasn't there so
+ * it's probably already been removed and we don't need to do anything
+ */
+ _processDeletePrefix(prefix, update.getRibEntry());
}
+ }
+
+ private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
+ deletePrefixFlows(prefix);
- log.debug("In deletePrefixFlows for {}", prefix);
-
- /*for (Map.Entry<Prefix, PushedFlowMod> entry : pushedFlows.entries()) {
- log.debug("Pushed flow: {} => {}", entry.getKey(), entry.getValue());
- }*/
-
+ log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
+ log.debug("is peer {}", bgpPeers.containsKey(ribEntry.getNextHop()));
+ if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
+ log.debug("Getting path for route with non-peer nexthop");
+ Path path = prefixToPath.get(prefix);
+
+ if (path == null) {
+ log.error("No path found for non-peer path");
+ }
+
+ path.decrementUsers();
+ log.debug("users {}, permanent {}", path.getUsers(), path.isPermanent());
+ if (path.getUsers() <= 0 && !path.isPermanent()) {
+ deletePath(path);
+ }
+ }
+ }
+
+ private void deletePrefixFlows(Prefix prefix) {
Collection<PushedFlowMod> pushedFlowMods
= pushedFlows.removeAll(prefix);
@@ -736,29 +592,45 @@
HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
.getDataLayerAddress())});
- OFFlowMod fm = pfm.getFlowMod();
-
- fm.setCommand(OFFlowMod.OFPFC_DELETE)
- .setOutPort(OFPort.OFPP_NONE)
- .setLengthU(OFFlowMod.MINIMUM_LENGTH);
-
- fm.getActions().clear();
-
- IOFSwitch sw = floodlightProvider.getSwitches().get(pfm.getDpid());
- if (sw == null) {
- log.warn("Switch not found when pushing delete flow mod");
- continue;
- }
-
- try {
- sw.write(fm, null);
- sw.flush();
- } catch (IOException e) {
- log.error("Failure writing flow mod", e);
- }
+ sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
}
}
+ private void deletePath(Path path) {
+ for (PushedFlowMod pfm : path.getFlowMods()) {
+ log.debug("Pushing a DELETE flow mod to {}, dst MAC {}",
+ new Object[] {HexString.toHexString(pfm.getDpid()),
+ HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
+ });
+
+ sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
+ }
+ }
+
+ private void sendDeleteFlowMod(OFFlowMod addFlowMod, long dpid) {
+ addFlowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT)
+ .setOutPort(OFPort.OFPP_NONE)
+ .setLengthU(OFFlowMod.MINIMUM_LENGTH);
+
+ addFlowMod.getActions().clear();
+
+ IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
+ if (sw == null) {
+ log.warn("Switch not found when pushing delete flow mod");
+ return;
+ }
+
+ try {
+ sw.write(addFlowMod, null);
+ sw.flush();
+ } catch (IOException e) {
+ log.error("Failure writing flow mod", e);
+ }
+ }
+
+ //TODO test next-hop changes
+ //TODO check delete/add synchronization
+
/*
* On startup we need to calculate a full mesh of paths between all gateway
* switches
@@ -773,25 +645,37 @@
for (BgpPeer peer : bgpPeers.values()) {
Interface peerInterface = interfaces.get(peer.getInterfaceName());
+ //We know there's not already a Path here pushed, because this is
+ //called before all other routing
+ Path path = new Path(peerInterface, peer.getIpAddress());
+ path.setPermanent();
+
//See if we know the MAC address of the peer. If not we can't
//do anything until we learn it
byte[] mac = proxyArp.getMacAddress(peer.getIpAddress());
if (mac == null) {
log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
//Put in the pending paths list first
- pathsWaitingOnArp.put(peer.getIpAddress(),
- new PathUpdate(peerInterface, peer.getIpAddress()));
+ pathsWaitingOnArp.put(peer.getIpAddress(), path);
proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
continue;
}
//If we know the MAC, lets go ahead and push the paths to this peer
- calculateAndPushPath(peerInterface, MACAddress.valueOf(mac));
+ setUpDataPath(path, MACAddress.valueOf(mac));
}
}
- private void calculateAndPushPath(Interface dstInterface, MACAddress dstMacAddress) {
+ private void setUpDataPath(Path path, MACAddress dstMacAddress) {
+ calculateAndPushPath(path, dstMacAddress);
+ }
+
+ private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
+ Interface dstInterface = path.getDstInterface();
+
+ List<PushedFlowMod> pushedFlows = new ArrayList<PushedFlowMod>();
+
for (Interface srcInterface : interfaces.values()) {
if (dstInterface.equals(srcInterface.getName())){
continue;
@@ -806,11 +690,15 @@
return; // just quit here?
}
- installPath(shortestPath.flowEntries(), dstMacAddress);
+ pushedFlows.addAll(installPath(shortestPath.flowEntries(), dstMacAddress));
}
+
+ path.setFlowMods(pushedFlows);
}
- private void installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
+ private List<PushedFlowMod> installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
+ List<PushedFlowMod> flowMods = new ArrayList<PushedFlowMod>();
+
//Set up the flow mod
OFFlowMod fm =
(OFFlowMod) floodlightProvider.getOFMessageFactory()
@@ -835,7 +723,6 @@
FlowEntry flowEntry = flowEntries.get(i);
OFMatch match = new OFMatch();
- //TODO Again using MAC address from configuration
match.setDataLayerDestination(dstMacAddress.toBytes());
match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
@@ -849,6 +736,8 @@
continue;
}
+ flowMods.add(new PushedFlowMod(sw.getId(), fm));
+
List<OFMessage> msglist = new ArrayList<OFMessage>();
msglist.add(fm);
try {
@@ -864,6 +753,8 @@
log.error("Failure cloning flow mod", e1);
}
}
+
+ return flowMods;
}
private void setupBgpPaths(){
@@ -908,7 +799,6 @@
//Common match fields
forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
- //forwardMatch.setWildcards(forwardMatch.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
forwardMatchSrc.setTransportDestination(BGP_PORT);
forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
@@ -1024,30 +914,39 @@
log.debug("Received ARP response: {} => {}", ipAddress.getHostAddress(),
MACAddress.valueOf(macAddress).toString());
- Set<PathUpdate> pathsToPush = pathsWaitingOnArp.removeAll(ipAddress);
-
- for (PathUpdate update : pathsToPush) {
- log.debug("Pushing path to {} at {} on {}", new Object[] {
- update.getDstIpAddress().getHostAddress(),
- MACAddress.valueOf(macAddress),
- update.getDstInterface().getSwitchPort()});
- calculateAndPushPath(update.getDstInterface(),
- MACAddress.valueOf(macAddress));
- }
-
- Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
-
/*
* We synchronize on this to prevent changes to the ptree while we're pushing
* flows to the switches. If the ptree changes, the ptree and switches
* could get out of sync.
*/
synchronized (this) {
+ Path path = pathsWaitingOnArp.remove(ipAddress);
+
+ if (path != null) {
+ log.debug("Pushing path to {} at {} on {}", new Object[] {
+ path.getDstIpAddress().getHostAddress(),
+ MACAddress.valueOf(macAddress),
+ path.getDstInterface().getSwitchPort()});
+ //These paths should always be to BGP peers. Paths to non-peers are
+ //handled once the first prefix is ready to push
+ if (pushedPaths.containsKey(path.getDstInterface())) {
+ //A path already got pushed to this endpoint while we were waiting
+ //for ARP. We'll copy over the permanent attribute if it is set on this path.
+ if (path.isPermanent()) {
+ pushedPaths.get(path.getDstInterface()).setPermanent();
+ }
+ }
+ else {
+ setUpDataPath(path, MACAddress.valueOf(macAddress));
+ pushedPaths.put(path.getDstIpAddress(), path);
+ }
+ }
+
+ Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
+
for (RibUpdate update : prefixesToPush) {
//These will always be adds
- //addPrefixFlows(update.getPrefix(), update.getRibEntry());
- //processRibAdd(update);
RibEntry rib = ptree.lookup(update.getPrefix());
if (rib != null && rib.equals(update.getRibEntry())) {
log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
@@ -1056,7 +955,7 @@
//and the next hop is the same as our update. The prefix could
//have been removed while we were waiting for the ARP, or the
//next hop could have changed.
- addPrefixFlows(update.getPrefix(), rib);
+ _processRibAdd(update);
} else {
log.debug("Received ARP response, but {},{} is no longer in ptree",
update.getPrefix(), update.getRibEntry());
@@ -1070,32 +969,12 @@
setupBgpPaths();
setupFullMesh();
- //Traverse ptree and create flows for all routes
- /*
- for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)){
- if (node.rib != null){
- prefixAdded(node);
- }
- }
- */
-
- /*
- synchronized (ptree) {
- Iterator<IPatriciaTrie.Entry> it = ptree.iterator();
- while (it.hasNext()) {
- IPatriciaTrie.Entry entry = it.next();
- addPrefixFlows(entry.getPrefix(), entry.getRib());
- }
- }
- */
-
bgpUpdatesExecutor.execute(new Runnable() {
@Override
public void run() {
doUpdatesThread();
}
});
-
}
private void checkSwitchesConnected(){
@@ -1131,8 +1010,6 @@
}
private void checkStatus(){
- log.debug("In checkStatus, swC {}, toRe {}", switchesConnected, topologyReady);
-
if (!switchesConnected){
checkSwitchesConnected();
}
@@ -1144,19 +1021,7 @@
beginRouting();
}
}
-
- @Override
- public void startUp(FloodlightModuleContext context) {
- restApi.addRestletRoutable(new BgpRouteWebRoutable());
- floodlightProvider.addOFSwitchListener(this);
- topology.addListener(this);
-
- floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
-
- //Retrieve the RIB from BGPd during startup
- retrieveRib();
- }
-
+
private void doUpdatesThread() {
boolean interrupted = false;
try {
@@ -1172,8 +1037,10 @@
break;
}
} catch (InterruptedException e) {
- log.debug("interrupted", e);
+ log.debug("Interrupted while taking from updates queue", e);
interrupted = true;
+ } catch (Exception e) {
+ log.debug("exception", e);
}
}
} finally {
@@ -1206,23 +1073,4 @@
topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
}
}
-
- //TODO determine whether we need to listen for switch joins
- @Override
- public void addedSwitch(IOFSwitch sw) {
- //checkStatus();
- }
-
- @Override
- public void removedSwitch(IOFSwitch sw) {
- // TODO Auto-generated method stub
- }
-
- @Override
- public void switchPortChanged(Long switchId) {}
-
- @Override
- public String getName() {
- return "BgpRoute";
- }
}
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 c9b3265..f058843 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteResource.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRouteResource.java
@@ -60,7 +60,7 @@
}
else {
//Ptree ptree = bgpRoute.getPtree();
- IPatriciaTrie ptree = bgpRoute.getPtree();
+ IPatriciaTrie<RibEntry> ptree = bgpRoute.getPtree();
output += "{\n \"rib\": [\n";
boolean printed = false;
@@ -78,16 +78,16 @@
}*/
synchronized(ptree) {
- Iterator<IPatriciaTrie.Entry> it = ptree.iterator();
+ Iterator<IPatriciaTrie.Entry<RibEntry>> it = ptree.iterator();
while (it.hasNext()) {
- IPatriciaTrie.Entry entry = it.next();
+ IPatriciaTrie.Entry<RibEntry> entry = it.next();
if (printed == true) {
output += ",\n";
}
output += " {\"prefix\": \"" + entry.getPrefix() +"\", ";
- output += "\"nexthop\": \"" + entry.getRib().getNextHop().getHostAddress() +"\"}";
+ output += "\"nexthop\": \"" + entry.getValue().getNextHop().getHostAddress() +"\"}";
//output += ",\n";
printed = true;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/IBgpRouteService.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/IBgpRouteService.java
index ba912ce..954976c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/IBgpRouteService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/IBgpRouteService.java
@@ -7,7 +7,7 @@
//public RibEntry lookupRib(byte[] dest);
//public Ptree getPtree();
- public IPatriciaTrie getPtree();
+ public IPatriciaTrie<RibEntry> getPtree();
public String getBGPdRestIp();
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/IPatriciaTrie.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/IPatriciaTrie.java
index 7fd7382..1fb0716 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/IPatriciaTrie.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/IPatriciaTrie.java
@@ -2,19 +2,19 @@
import java.util.Iterator;
-public interface IPatriciaTrie {
- public RibEntry put(Prefix p, RibEntry r);
+public interface IPatriciaTrie<V> {
+ public V put(Prefix prefix, V value);
- public RibEntry lookup(Prefix p);
+ public V lookup(Prefix prefix);
- public RibEntry match(Prefix p);
+ public V match(Prefix prefix);
- public boolean remove(Prefix p, RibEntry r);
+ public boolean remove(Prefix prefix, V value);
- public Iterator<Entry> iterator();
+ public Iterator<Entry<V>> iterator();
- interface Entry {
+ interface Entry<V> {
public Prefix getPrefix();
- public RibEntry getRib();
+ public V getValue();
}
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Path.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Path.java
new file mode 100644
index 0000000..5cf4b09
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Path.java
@@ -0,0 +1,61 @@
+package net.onrc.onos.ofcontroller.bgproute;
+
+import java.net.InetAddress;
+import java.util.Collections;
+import java.util.List;
+
+/*
+ * A path is always assumed to be from all other interfaces (external-facing
+ * switchports) to the destination interface.
+ */
+
+public class Path {
+
+ private Interface dstInterface;
+ private InetAddress dstIpAddress;
+ private int numUsers = 0;
+
+ private List<PushedFlowMod> flowMods = null;
+ private boolean permanent = false;
+
+ public Path(Interface dstInterface, InetAddress dstIpAddress) {
+ this.dstInterface = dstInterface;
+ this.dstIpAddress = dstIpAddress;
+ }
+
+ public Interface getDstInterface() {
+ return dstInterface;
+ }
+
+ public InetAddress getDstIpAddress() {
+ return dstIpAddress;
+ }
+
+ public void incrementUsers() {
+ numUsers++;
+ }
+
+ public void decrementUsers() {
+ numUsers--;
+ }
+
+ public int getUsers() {
+ return numUsers;
+ }
+
+ public List<PushedFlowMod> getFlowMods() {
+ return Collections.unmodifiableList(flowMods);
+ }
+
+ public void setFlowMods(List<PushedFlowMod> flowMods) {
+ this.flowMods = flowMods;
+ }
+
+ public boolean isPermanent() {
+ return permanent;
+ }
+
+ public void setPermanent() {
+ permanent = true;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/PathUpdate.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/PathUpdate.java
deleted file mode 100644
index 1d2a47b..0000000
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/PathUpdate.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package net.onrc.onos.ofcontroller.bgproute;
-
-import java.net.InetAddress;
-
-/*
- * A path is always assumed to be from all other interfaces (external-facing
- * switchports) to the destination interface.
- */
-
-public class PathUpdate {
-
- private Interface dstInterface;
- private InetAddress dstIpAddress;
-
- public PathUpdate(Interface dstInterface, InetAddress dstIpAddress) {
- this.dstInterface = dstInterface;
- this.dstIpAddress = dstIpAddress;
- }
-
- public Interface getDstInterface() {
- return dstInterface;
- }
-
- public InetAddress getDstIpAddress() {
- return dstIpAddress;
- }
-}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/PatriciaTrie.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/PatriciaTrie.java
index 86bc8cf..89dfb30 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/PatriciaTrie.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/PatriciaTrie.java
@@ -3,7 +3,7 @@
import java.util.Iterator;
import java.util.NoSuchElementException;
-public class PatriciaTrie implements IPatriciaTrie{
+public class PatriciaTrie<V> implements IPatriciaTrie<V> {
private final byte maskBits[] = {(byte)0x00, (byte)0x80, (byte)0xc0, (byte)0xe0, (byte)0xf0,
(byte)0xf8, (byte)0xfc, (byte)0xfe, (byte)0xff};
@@ -15,14 +15,15 @@
this.maxPrefixLength = maxPrefixLength;
}
- public synchronized RibEntry put(Prefix p, RibEntry r) {
- if (p.getPrefixLength() > maxPrefixLength) {
+ @Override
+ public synchronized V put(Prefix prefix, V value) {
+ if (prefix.getPrefixLength() > maxPrefixLength) {
throw new IllegalArgumentException(String.format(
"Prefix length %d is greater than max prefix length %d",
- p.getPrefixLength(), maxPrefixLength));
+ prefix.getPrefixLength(), maxPrefixLength));
}
- if (p == null || r == null) {
+ if (prefix == null || value == null) {
throw new NullPointerException();
}
@@ -30,23 +31,23 @@
Node match = null;
while (node != null
- && node.prefix.getPrefixLength() <= p.getPrefixLength()
- && key_match(node.prefix.getAddress(), node.prefix.getPrefixLength(), p.getAddress(), p.getPrefixLength()) == true) {
- if (node.prefix.getPrefixLength() == p.getPrefixLength()) {
+ && node.prefix.getPrefixLength() <= prefix.getPrefixLength()
+ && key_match(node.prefix.getAddress(), node.prefix.getPrefixLength(), prefix.getAddress(), prefix.getPrefixLength()) == true) {
+ if (node.prefix.getPrefixLength() == prefix.getPrefixLength()) {
/*
* Prefix is already in tree. This may be an aggregate node, in which case
* we are inserting a new prefix, or it could be an actual node, in which
* case we are inserting a new nexthop for the prefix and should return
* the old nexthop.
*/
- RibEntry oldRib = node.rib;
- node.rib = r;
- return oldRib;
+ V oldValue = node.value;
+ node.value = value;
+ return oldValue;
}
match = node;
- if (bit_check(p.getAddress(), node.prefix.getPrefixLength()) == true) {
+ if (bit_check(prefix.getAddress(), node.prefix.getPrefixLength()) == true) {
node = node.right;
} else {
node = node.left;
@@ -56,7 +57,9 @@
Node add = null;
if (node == null) {
- add = new Node(p, r);
+ //add = new Node(p, r);
+ add = new Node(prefix);
+ add.value = value;
if (match != null) {
node_link(match, add);
@@ -64,7 +67,7 @@
top = add;
}
} else {
- add = node_common(node, p.getAddress(), p.getPrefixLength());
+ add = node_common(node, prefix.getAddress(), prefix.getPrefixLength());
if (add == null) {
//I think this is -ENOMEM?
//return null;
@@ -77,14 +80,16 @@
}
node_link(add, node);
- if (add.prefix.getPrefixLength() != p.getPrefixLength()) {
+ if (add.prefix.getPrefixLength() != prefix.getPrefixLength()) {
match = add;
- add = new Node(p, r);
+ //add = new Node(p, r);
+ add = new Node(prefix);
+ add.value = value;
node_link(match, add);
}
else {
- add.rib = r;
+ add.value = value;
}
}
@@ -94,10 +99,9 @@
}
/*exact match*/
- public synchronized RibEntry lookup(Prefix p) {
- //TODO
-
- if (p.getPrefixLength() > maxPrefixLength) {
+ @Override
+ public synchronized V lookup(Prefix prefix) {
+ if (prefix.getPrefixLength() > maxPrefixLength) {
return null;
}
@@ -120,28 +124,36 @@
}
*/
- Node node = findNode(p);
+ Node node = findNode(prefix);
- return node == null ? null : node.rib;
+ return node == null ? null : node.value;
}
/*closest containing prefix*/
- public synchronized RibEntry match(Prefix p) {
+ @Override
+ public synchronized V match(Prefix prefix) {
//TODO
- return null;
+ if (prefix.getPrefixLength() > maxPrefixLength) {
+ return null;
+ }
+
+ Node closestNode = findClosestNode(prefix);
+
+ return closestNode == null ? null : closestNode.value;
}
- public synchronized boolean remove(Prefix p, RibEntry r) {
+ @Override
+ public synchronized boolean remove(Prefix prefix, V value) {
Node child;
Node parent;
- if (p == null || r == null) {
+ if (prefix == null || value == null) {
return false;
}
- Node node = findNode(p);
+ Node node = findNode(prefix);
- if (node == null || node.rib == null || !node.rib.equals(r)) {
+ if (node == null || node.isAggregate() || !node.value.equals(value)) {
//Given <prefix, nexthop> mapping is not in the tree
return false;
}
@@ -151,7 +163,7 @@
//In the future, maybe we should re-evaluate what the aggregate prefix should be?
//It shouldn't necessarily stay the same.
//More complicated if the above prefix is also aggregate.
- node.rib = null;
+ node.value = null;
return true;
}
@@ -192,22 +204,23 @@
return true;
}
- public Iterator<Entry> iterator() {
+ @Override
+ public Iterator<Entry<V>> iterator() {
return new PatriciaTrieIterator(top);
}
- private Node findNode(Prefix p) {
+ private Node findNode(Prefix prefix) {
Node node = top;
while (node != null
- && node.prefix.getPrefixLength() <= p.getPrefixLength()
- && key_match(node.prefix.getAddress(), node.prefix.getPrefixLength(), p.getAddress(), p.getPrefixLength()) == true) {
- if (node.prefix.getPrefixLength() == p.getPrefixLength()) {
+ && node.prefix.getPrefixLength() <= prefix.getPrefixLength()
+ && key_match(node.prefix.getAddress(), node.prefix.getPrefixLength(), prefix.getAddress(), prefix.getPrefixLength()) == true) {
+ if (node.prefix.getPrefixLength() == prefix.getPrefixLength()) {
//return addReference(node);
return node;
}
- if (bit_check(p.getAddress(), node.prefix.getPrefixLength()) == true) {
+ if (bit_check(prefix.getAddress(), node.prefix.getPrefixLength()) == true) {
node = node.right;
} else {
node = node.left;
@@ -217,6 +230,27 @@
return null;
}
+ private Node findClosestNode(Prefix prefix) {
+ Node node = top;
+ Node match = null;
+
+ while (node != null
+ && node.prefix.getPrefixLength() <= prefix.getPrefixLength()
+ && key_match(node.prefix.getAddress(), node.prefix.getPrefixLength(), prefix.getAddress(), prefix.getPrefixLength()) == true) {
+ if (!node.isAggregate()) {
+ match = node;
+ }
+
+ if (bit_check(prefix.getAddress(), node.prefix.getPrefixLength()) == true) {
+ node = node.right;
+ } else {
+ node = node.left;
+ }
+ }
+
+ return match;
+ }
+
/*
* Receives a 1-based bit index
* Returns a 1-based byte index
@@ -325,7 +359,8 @@
if (boundary != 0)
newPrefix[j] = (byte)(node.prefix.getAddress()[j] & maskBits[common_len % 8]);
- return new Node(new Prefix(newPrefix, common_len), null);
+ //return new Node(new Prefix(newPrefix, common_len), null);
+ return new Node(new Prefix(newPrefix, common_len));
//return add;
}
@@ -334,26 +369,33 @@
public Node left = null;
public Node right = null;
- public Prefix prefix;
- public RibEntry rib;
+ public final Prefix prefix;
+ public V value;
- public Node(Prefix p, RibEntry r) {
+ //public Node(Prefix p, RibEntry r) {
+ // this.prefix = p;
+ // this.rib = r;
+ //}
+ public Node(Prefix p) {
this.prefix = p;
- this.rib = r;
}
- public Entry getEntry() {
- return new PatriciaTrieEntry(prefix, rib);
+ public boolean isAggregate() {
+ return value == null;
+ }
+
+ public Entry<V> getEntry() {
+ return new PatriciaTrieEntry(prefix, value);
}
}
- private class PatriciaTrieEntry implements Entry {
+ private class PatriciaTrieEntry implements Entry<V> {
private Prefix prefix;
- private RibEntry rib;
+ private V value;
- public PatriciaTrieEntry(Prefix prefix, RibEntry rib) {
+ public PatriciaTrieEntry(Prefix prefix, V value) {
this.prefix = prefix;
- this.rib = rib;
+ this.value = value;
}
@Override
@@ -362,12 +404,12 @@
}
@Override
- public RibEntry getRib() {
- return rib;
+ public V getValue() {
+ return value;
}
}
- private class PatriciaTrieIterator implements Iterator<Entry> {
+ private class PatriciaTrieIterator implements Iterator<Entry<V>> {
private Node current;
private boolean started = false;
@@ -376,7 +418,7 @@
current = start;
//If the start is an aggregate node fast forward to find the next valid node
- if (current != null && current.rib == null) {
+ if (current != null && current.isAggregate()) {
current = findNext(current);
}
}
@@ -395,7 +437,7 @@
}
@Override
- public Entry next() {
+ public Entry<V> next() {
if (current == null) {
throw new NoSuchElementException();
}
@@ -452,9 +494,9 @@
return null;
}
- //If the node doesn't have a rib, it's not an actual node, it's an artifically
+ //If the node doesn't have a value, it's not an actual node, it's an artifically
//inserted aggregate node. We don't want to return these to the user.
- if (next.rib == null) {
+ if (next.isAggregate()) {
return findNext(next);
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Prefix.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Prefix.java
index 21dd45c..05ce0a4 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Prefix.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Prefix.java
@@ -4,6 +4,8 @@
import java.net.UnknownHostException;
import java.util.Arrays;
+import com.google.common.net.InetAddresses;
+
public class Prefix {
private final int MAX_BYTES = 4;
@@ -31,11 +33,7 @@
public Prefix(String strAddress, int prefixLength) {
byte[] addr = null;
- try {
- addr = InetAddress.getByName(strAddress).getAddress();
- } catch (UnknownHostException e) {
- throw new IllegalArgumentException("Invalid IP inetAddress argument");
- }
+ addr = InetAddresses.forString(strAddress).getAddress();
if (addr == null || addr.length != MAX_BYTES ||
prefixLength < 0 || prefixLength > MAX_BYTES * Byte.SIZE) {
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/PushedFlowMod.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/PushedFlowMod.java
new file mode 100644
index 0000000..56f4c04
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/PushedFlowMod.java
@@ -0,0 +1,25 @@
+package net.onrc.onos.ofcontroller.bgproute;
+
+import org.openflow.protocol.OFFlowMod;
+
+public class PushedFlowMod {
+ private long dpid;
+ private OFFlowMod flowMod;
+
+ public PushedFlowMod(long dpid, OFFlowMod flowMod) {
+ this.dpid = dpid;
+ try {
+ this.flowMod = flowMod.clone();
+ } catch (CloneNotSupportedException e) {
+ this.flowMod = flowMod;
+ }
+ }
+
+ public long getDpid() {
+ return dpid;
+ }
+
+ public OFFlowMod getFlowMod() {
+ return flowMod;
+ }
+}
\ No newline at end of file
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 c27f962..8087471 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/RibEntry.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/RibEntry.java
@@ -1,7 +1,8 @@
package net.onrc.onos.ofcontroller.bgproute;
import java.net.InetAddress;
-import java.net.UnknownHostException;
+
+import com.google.common.net.InetAddresses;
public class RibEntry {
private InetAddress routerId;
@@ -13,12 +14,8 @@
}
public RibEntry(String routerId, String nextHop) {
- try {
- this.routerId = InetAddress.getByName(routerId);
- this.nextHop = InetAddress.getByName(nextHop);
- } catch (UnknownHostException e) {
- throw new IllegalArgumentException("Invalid address format");
- }
+ this.routerId = InetAddresses.forString(routerId);
+ this.nextHop = InetAddresses.forString(nextHop);
}
public InetAddress getNextHop() {
diff --git a/src/test/java/net/onrc/onos/ofcontroller/bgproute/PatriciaTrieTest.java b/src/test/java/net/onrc/onos/ofcontroller/bgproute/PatriciaTrieTest.java
index 1af0416..571d37d 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/bgproute/PatriciaTrieTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/bgproute/PatriciaTrieTest.java
@@ -4,7 +4,6 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
import java.util.HashMap;
import java.util.Iterator;
@@ -12,18 +11,17 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
public class PatriciaTrieTest {
- IPatriciaTrie ptrie;
+ IPatriciaTrie<RibEntry> ptrie;
Prefix[] prefixes;
Map<Prefix, RibEntry> mappings;
@Before
public void setUp() throws Exception {
- ptrie = new PatriciaTrie(32);
+ ptrie = new PatriciaTrie<RibEntry>(32);
mappings = new HashMap<Prefix, RibEntry>();
prefixes = new Prefix[] {
@@ -50,7 +48,7 @@
@Test
public void testPut() {
- IPatriciaTrie ptrie = new PatriciaTrie(32);
+ IPatriciaTrie<RibEntry> ptrie = new PatriciaTrie<RibEntry>(32);
Prefix p1 = new Prefix("192.168.240.0", 20);
RibEntry r1 = new RibEntry("192.168.10.101", "192.168.60.2");
@@ -107,10 +105,27 @@
assertTrue(retval.equals(r2));
}
- @Ignore
+ //@Ignore
@Test
public void testMatch() {
- fail("Not yet implemented");
+ Prefix p1 = new Prefix("192.168.10.30", 32);
+ Prefix p2 = new Prefix("192.168.10.30", 31);
+ Prefix p3 = new Prefix("192.168.8.241", 32);
+ Prefix p4 = new Prefix("1.0.0.0", 32);
+ Prefix p5 = new Prefix("192.168.8.0", 22);
+ Prefix p6 = new Prefix("192.168.8.0", 21);
+
+ assertTrue(ptrie.match(p1).equals(mappings.get(prefixes[0])));
+ assertTrue(ptrie.match(p2).equals(mappings.get(prefixes[0])));
+ assertTrue(ptrie.match(p3).equals(mappings.get(prefixes[1])));
+ assertNull(ptrie.match(p4));
+ assertTrue(ptrie.match(p5).equals(mappings.get(prefixes[2])));
+ //System.out.println(ptrie.match(p6).getNextHop().getHostAddress());
+ assertTrue(ptrie.match(p6).equals(mappings.get(prefixes[8])));
+
+
+ //TODO more extensive tests
+ //fail("Not yet implemented");
}
@Test
@@ -169,19 +184,19 @@
public void testIterator() {
int[] order = new int[] {7, 5, 3, 8, 2, 1, 0, 4, 6};
- Iterator<IPatriciaTrie.Entry> it = ptrie.iterator();
+ Iterator<IPatriciaTrie.Entry<RibEntry>> it = ptrie.iterator();
int i = 0;
assertTrue(it.hasNext());
while (it.hasNext()) {
- IPatriciaTrie.Entry entry = it.next();
+ IPatriciaTrie.Entry<RibEntry> entry = it.next();
assertTrue(entry.getPrefix().equals(prefixes[order[i]]));
i++;
}
assertFalse(it.hasNext());
assertTrue(i == order.length);
- IPatriciaTrie pt = new PatriciaTrie(32);
- Iterator<IPatriciaTrie.Entry> it2 = pt.iterator();
+ IPatriciaTrie<RibEntry> pt = new PatriciaTrie<RibEntry>(32);
+ Iterator<IPatriciaTrie.Entry<RibEntry>> it2 = pt.iterator();
assertFalse(it2.hasNext());
it.next(); //throws NoSuchElementException
}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/bgproute/PtreeTest.java b/src/test/java/net/onrc/onos/ofcontroller/bgproute/PtreeTest.java
index 6af9d30..1135407 100644
--- a/src/test/java/net/onrc/onos/ofcontroller/bgproute/PtreeTest.java
+++ b/src/test/java/net/onrc/onos/ofcontroller/bgproute/PtreeTest.java
@@ -25,14 +25,14 @@
private Logger log = LoggerFactory.getLogger(PtreeTest.class);
private Ptree ptree;
- private PatriciaTrie ooptrie;
+ private PatriciaTrie<RibEntry> ooptrie;
private Map<String, byte[]> byteAddresses;
@Before
public void setUp() throws Exception {
ptree = new Ptree(32);
- ooptrie = new PatriciaTrie(32);
+ ooptrie = new PatriciaTrie<RibEntry>(32);
String[] strPrefixes = {
"192.168.10.0/24",
@@ -176,6 +176,7 @@
fail("Not yet implemented");
}
+ @Ignore
@Test
public void testMisc() {
int bitIndex = -1;
@@ -197,10 +198,10 @@
@Test
public void testIteration() {
- Iterator<IPatriciaTrie.Entry> it = ooptrie.iterator();
+ Iterator<IPatriciaTrie.Entry<RibEntry>> it = ooptrie.iterator();
while (it.hasNext()) {
- IPatriciaTrie.Entry entry = it.next();
+ IPatriciaTrie.Entry<RibEntry> entry = it.next();
log.debug("PatriciaTrie prefix {} \t {}", entry.getPrefix(), entry.getPrefix().printAsBits());
}