Cherry-pick from https://gerrit.onos.onlab.us/#/c/335/

Move to FlowManager & Running SDN-IP on multiple onos instances (ONOS-668)

Make DISCARD_FIRST_HOP_ENTRY, KEEP_ONLY_FIRST_HOP_ENTRY accessible

Add a new type of BroadcastPacketOutNotification without inSwitch/inPort

Send Arp Request to all ONOS instances, not just to the local one

Get rid of BgpProxyArpManager.java

Improvements patch (ONOS-668)

change FlowPathFlag from private to public

delete BroadcastPacketOutNotification with no dpid/port

sendPacketOutNotification to specific out-dpid/our-port

Conflicts:

	src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
	src/main/java/net/onrc/onos/ofcontroller/proxyarp/BgpProxyArpManager.java

NOTE: The above conflicts have been resolved by hand.

Change-Id: I449717d2289d14c2655af10ae7f628ea62187c63
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 4f6c310..1363c19 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
@@ -3,6 +3,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.net.InetAddress;
+import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
@@ -33,20 +34,36 @@
 import net.floodlightcontroller.topology.ITopologyService;
 import net.floodlightcontroller.util.MACAddress;
 import net.onrc.onos.ofcontroller.bgproute.RibUpdate.Operation;
+import net.onrc.onos.ofcontroller.core.IDeviceStorage;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoSwitchService;
 import net.onrc.onos.ofcontroller.core.config.IConfigInfoService;
+import net.onrc.onos.ofcontroller.core.internal.DeviceStorageImpl;
 import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
+import net.onrc.onos.ofcontroller.core.internal.TopoSwitchServiceImpl;
+import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
 import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
 import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
 import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
-import net.onrc.onos.ofcontroller.proxyarp.BgpProxyArpManager;
 import net.onrc.onos.ofcontroller.proxyarp.IArpRequester;
+import net.onrc.onos.ofcontroller.proxyarp.IProxyArpService;
 import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
 import net.onrc.onos.ofcontroller.topology.Topology;
 import net.onrc.onos.ofcontroller.topology.TopologyManager;
+import net.onrc.onos.ofcontroller.util.CallerId;
 import net.onrc.onos.ofcontroller.util.DataPath;
 import net.onrc.onos.ofcontroller.util.Dpid;
-import net.onrc.onos.ofcontroller.util.FlowEntry;
+import net.onrc.onos.ofcontroller.util.FlowEntryAction;
+import net.onrc.onos.ofcontroller.util.FlowEntryActions;
+import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
+import net.onrc.onos.ofcontroller.util.FlowId;
+import net.onrc.onos.ofcontroller.util.FlowPath;
+import net.onrc.onos.ofcontroller.util.FlowPathFlags;
+import net.onrc.onos.ofcontroller.util.FlowPathType;
+import net.onrc.onos.ofcontroller.util.FlowPathUserState;
+import net.onrc.onos.ofcontroller.util.IPv4Net;
 import net.onrc.onos.ofcontroller.util.Port;
 import net.onrc.onos.ofcontroller.util.SwitchPort;
 import net.sf.json.JSONArray;
@@ -60,9 +77,7 @@
 import org.openflow.protocol.OFMatch;
 import org.openflow.protocol.OFPacketOut;
 import org.openflow.protocol.OFPort;
-import org.openflow.protocol.OFType;
 import org.openflow.protocol.action.OFAction;
-import org.openflow.protocol.action.OFActionDataLayerDestination;
 import org.openflow.protocol.action.OFActionOutput;
 import org.openflow.util.HexString;
 import org.slf4j.Logger;
@@ -86,8 +101,10 @@
 	private ITopologyNetService topologyNetService;
 	private ILinkDiscoveryService linkDiscoveryService;
 	private IRestApiService restApi;
-	
-	private BgpProxyArpManager proxyArp;
+	private IProxyArpService proxyArp;
+	protected volatile IFlowService flowManagerService;
+	private IDeviceStorage deviceStorage;
+	private ITopoSwitchService topoSwitchService;
 	
 	private IPatriciaTrie<RibEntry> ptree;
 	private IPatriciaTrie<Interface> interfacePtrie;
@@ -139,12 +156,13 @@
 	
 	private Map<InetAddress, Path> pushedPaths;
 	private Map<Prefix, Path> prefixToPath;
-	private Multimap<Prefix, PushedFlowMod> pushedFlows;
+//	private Multimap<Prefix, PushedFlowMod> pushedFlows;
+	private Multimap<Prefix, FlowId> pushedFlowIds;
 	
 	private FlowCache flowCache;
 	
 	private volatile Topology topology = null;
-		
+	
 	private class TopologyChangeDetector implements Runnable {
 		@Override
 		public void run() {
@@ -232,7 +250,7 @@
 		l.add(IConfigInfoService.class);
 		return l;
 	}
-
+	
 	@Override
 	public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
 		Map<Class<? extends IFloodlightService>, IFloodlightService> m 
@@ -255,38 +273,38 @@
 	@Override
 	public void init(FloodlightModuleContext context)
 			throws FloodlightModuleException {
-	    
+		
 		ptree = new PatriciaTrie<RibEntry>(32);
 		interfacePtrie = new PatriciaTrie<Interface>(32);
-	    
-	    ribUpdates = new LinkedBlockingQueue<RibUpdate>();
-	    	
+		
+		ribUpdates = new LinkedBlockingQueue<RibUpdate>();
+		
 		// Register floodlight provider and REST handler.
 		floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
 		topologyService = context.getServiceImpl(ITopologyService.class);
 		linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
 		restApi = context.getServiceImpl(IRestApiService.class);
-		
-		//TODO We'll initialise this here for now, but it should really be done as
-		//part of the controller core
-		//proxyArp = new ProxyArpManager(floodlightProvider, topologyService, this, restApi);
-		proxyArp = new BgpProxyArpManager();
-		proxyArp.init(floodlightProvider, topologyService, this, restApi);
-		//proxyArp = context.getServiceImpl(IProxyArpService.class);
-		
+		flowManagerService = context.getServiceImpl(IFlowService.class);
+		proxyArp = context.getServiceImpl(IProxyArpService.class);
+
+		deviceStorage = new DeviceStorageImpl();
+		deviceStorage.init("", "");
+
 		linkUpdates = new ArrayList<LDUpdate>();
 		ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
 		topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
 
 		topologyNetService = new TopologyManager(context);
-		
+		topoSwitchService = new TopoSwitchServiceImpl();
+
 		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();
+//		pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
+		pushedFlowIds = HashMultimap.<Prefix, FlowId>create();
 		
 		flowCache = new FlowCache(floodlightProvider);
 		
@@ -311,7 +329,7 @@
 		else {
 			log.info("RouterId set to {}", routerId);
 		}
-		
+
 		String configFilenameParameter = context.getConfigParams(this).get("configfile");
 		if (configFilenameParameter != null){
 			configFilename = configFilenameParameter;
@@ -326,11 +344,7 @@
 		restApi.addRestletRoutable(new BgpRouteWebRoutable());
 		topologyService.addListener(this);
 		floodlightProvider.addOFSwitchListener(this);
-		
-		proxyArp.startUp();
-		
-		//floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
-		
+
 		//Retrieve the RIB from BGPd during startup
 		retrieveRib();
 	}
@@ -390,7 +404,7 @@
 			}
 			
 			RibEntry rib = new RibEntry(router_id, nexthop);
-
+			
 			try {
 				ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
 			} catch (InterruptedException e) {
@@ -439,11 +453,24 @@
 		RibEntry rib = update.getRibEntry();
 		
 		InetAddress dstIpAddress = rib.getNextHop();
+		MACAddress nextHopMacAddress;
+
+		// See if we know the MAC address of the next hop
+		// TODO if we do not treat the next hop as a device in the future, we need to update this
+		IDeviceObject nextHopDevice =
+				deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(dstIpAddress));
 		
-		//See if we know the MAC address of the next hop
-		MACAddress nextHopMacAddress = proxyArp.getMacAddress(rib.getNextHop());
+		if (nextHopDevice == null){
+			log.debug("NextHopDevice for IP: {} is null", dstIpAddress);
+			prefixesWaitingOnArp.put(dstIpAddress,
+					new RibUpdate(Operation.UPDATE, prefix, rib));
+			proxyArp.sendArpRequest(dstIpAddress, this, true);
+			return;
+
+		}
+		nextHopMacAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
 		
-		//Find the attachment point (egress interface) of the next hop
+		// Find the attachment point (egress interface) of the next hop
 		Interface egressInterface = null;
 		if (bgpPeers.containsKey(dstIpAddress)) {
 			//Route to a peer
@@ -488,11 +515,34 @@
 		}
 	}
 	
-	private void addPrefixFlows(Prefix prefix, Interface egressInterface, MACAddress nextHopMacAddress) {		
+	/**
+	 * Add a flow to match dst-IP prefix and rewrite MAC for one IP prefix
+	 * to all other border switches
+	 */
+	private void addPrefixFlows(Prefix prefix, Interface egressInterface,
+			MACAddress nextHopMacAddress) {
 		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
+		FlowPath flowPath = new FlowPath();
+		flowPath.setInstallerId(new CallerId("SDNIP"));
+		
+		// Set flowPath FlowPathType and FlowPathUserState
+		flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
+		flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
+
+		// Insert dst-ip prefix based forwarding and MAC rewrite flow entry
+		// only to the first-host switches
+		FlowPathFlags flowPathFlags = new FlowPathFlags();
+		flowPathFlags.setFlags(FlowPathFlags.KEEP_ONLY_FIRST_HOP_ENTRY);
+		flowPath.setFlowPathFlags(flowPathFlags);
+
+		// Create the DataPath object: dstSwitchPort
+		SwitchPort dstPort = new SwitchPort();
+		dstPort.setDpid(new Dpid(egressInterface.getDpid()));
+		dstPort.setPort(new Port(egressInterface.getPort()));
+
+		// We only need one flow mod per switch, so pick one interface on each switch
 		Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
 		for (Interface intf : interfaces.values()) {
 			if (!srcInterfaces.containsKey(intf.getDpid()) 
@@ -500,77 +550,56 @@
 				srcInterfaces.put(intf.getDpid(), intf);
 			}
 		}
-		
-		//Add a flow to rewrite mac for this prefix to all other border switches
 		for (Interface srcInterface : srcInterfaces.values()) {
-			DataPath shortestPath; 
-			if (topology == null) {
-				shortestPath = topologyNetService.getDatabaseShortestPath(
-						srcInterface.getSwitchPort(),
-						egressInterface.getSwitchPort());
+
+			if (egressInterface.equals(srcInterface)){
+				continue;
 			}
-			else {
-				shortestPath = topologyNetService.getTopologyShortestPath(
-						topology, srcInterface.getSwitchPort(),
-						egressInterface.getSwitchPort());
-			}
-			
-			if (shortestPath == null){
-				log.debug("Shortest path between {} and {} not found",
-						srcInterface.getSwitchPort(),
-						egressInterface.getSwitchPort());
-				return; // just quit here?
-			}
-			
-			//Set up the flow mod
-			OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
-					.getMessage(OFType.FLOW_MOD);
-			
-	        fm.setIdleTimeout((short)0)
-	        .setHardTimeout((short)0)
-	        .setBufferId(OFPacketOut.BUFFER_ID_NONE)
-	        .setCookie(MAC_RW_COOKIE)
-	        .setCommand(OFFlowMod.OFPFC_ADD)
-	        .setPriority(SDNIP_PRIORITY)
-	        .setLengthU(OFFlowMod.MINIMUM_LENGTH
-	        		+ OFActionDataLayerDestination.MINIMUM_LENGTH
-	        		+ OFActionOutput.MINIMUM_LENGTH);
-	        
-	        OFMatch match = new OFMatch();
-	        match.setDataLayerType(Ethernet.TYPE_IPv4);
-	        match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
-	        
-	        match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
-	        fm.setMatch(match);
-	        
-	        //Set up MAC rewrite action
-	        OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
-	        macRewriteAction.setDataLayerAddress(nextHopMacAddress.toBytes());
-	        
-	        //Set up output action
-	        OFActionOutput outputAction = new OFActionOutput();
-	        outputAction.setMaxLength((short)0xffff);
-	        Port outputPort = shortestPath.flowEntries().get(0).outPort();
-	        outputAction.setPort(outputPort.value());
-	        
-	        List<OFAction> actions = new ArrayList<OFAction>();
-	        actions.add(macRewriteAction);
-	        actions.add(outputAction);
-	        fm.setActions(actions);
-	        
-	        pushedFlows.put(prefix, new PushedFlowMod(srcInterface.getDpid(), fm));
-	        flowCache.write(srcInterface.getDpid(), fm);
+
+			// Create flowPath FlowId
+			//FlowId returnByRefFlowId = new FlowId(flowManagerService.getNextFlowEntryId());
+			//flowPath.setFlowId(returnByRefFlowId);
+			flowPath.setFlowId(new FlowId());
+
+			// Create DataPath object: srcSwitchPort
+			SwitchPort srcPort = new SwitchPort();
+			srcPort.setDpid(new Dpid(srcInterface.getDpid()));
+			srcPort.setPort(new Port(srcInterface.getPort()));
+
+			DataPath dataPath = new DataPath();
+			dataPath.setSrcPort(srcPort);
+			dataPath.setDstPort(dstPort);
+			flowPath.setDataPath(dataPath);
+
+			// Create flow path matching condition(s): IPv4 Prefix
+			FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
+			flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
+			IPv4Net dstIPv4Net= new IPv4Net(prefix.toString());
+			flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
+			flowPath.setFlowEntryMatch(flowEntryMatch);
 
 			/*
-			 * XXX Rate limit hack!
-			 * This should be solved properly by adding a rate limiting
-			 * layer on top of the switches if we know they need it.
+			 * Create the Flow Entry Action(s): dst-MAC rewrite action
 			 */
-	        try {
-				Thread.sleep(1);
-			} catch (InterruptedException e) {
-				// TODO handle this properly
-				log.error("Interrupted", e);
+			FlowEntryActions flowEntryActions = new FlowEntryActions();
+			FlowEntryAction flowEntryAction1 = new FlowEntryAction();
+			flowEntryAction1.setActionSetEthernetDstAddr(nextHopMacAddress);
+			// flowEntryAction1.actionSetEthernetDstAddr(nextHopMacAddress);
+			flowEntryActions.addAction(flowEntryAction1);
+			flowPath.setFlowEntryActions(flowEntryActions);
+
+			// Flow Path installation, only to first hop switches
+			if (flowManagerService.addFlow(flowPath) == null) {
+				log.error("Failed to install flow path to the first hop for " +
+						"prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
+						nextHopMacAddress);
+			}
+			else {
+				log.debug("Successfully installed flow path to the first hop " +
+						"for prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
+						nextHopMacAddress);
+
+				pushedFlowIds.put(prefix, flowPath.flowId());
 			}
 		}
 	}
@@ -600,7 +629,7 @@
 			if (path != null) {
 				//path could be null if we added to the Ptree but didn't push
 				//flows yet because we were waiting to resolve ARP
-			
+				
 				path.decrementUsers();
 				if (path.getUsers() <= 0 && !path.isPermanent()) {
 					deletePath(path);
@@ -610,51 +639,53 @@
 		}
 	}
 	
+	// TODO have not tested this module
 	private void deletePrefixFlows(Prefix prefix) {
 		log.debug("Deleting flows for prefix {}", prefix);
 		
-		Collection<PushedFlowMod> pushedFlowMods 
-				= pushedFlows.removeAll(prefix);
-		
-		for (PushedFlowMod pfm : pushedFlowMods) {
+		Collection<FlowId> flowIds = pushedFlowIds.removeAll(prefix);
+		for (FlowId flowId : flowIds) {
 			if (log.isTraceEnabled()) {
-				log.trace("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
-						new Object[] {HexString.toHexString(pfm.getDpid()),
-						pfm.getFlowMod().getMatch().getNetworkDestination() + 
-						pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
-						HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
-								.getDataLayerAddress())});
+				//Trace the flow status by flowPath in the switch before deleting it
+				log.trace("Pushing a DELETE flow mod to flowPath : {}",
+						flowManagerService.getFlow(flowId).toString());
 			}
 			
-			sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
+			if( flowManagerService.deleteFlow(flowId))
+			{
+				log.debug("Successfully deleted FlowId: {}",flowId);
+			}
+			else
+			{
+				log.debug("Failed to delete FlowId: {}",flowId);
+			}
 		}
 	}
 	
+	// TODO need to record the path and then delete here
 	private void deletePath(Path path) {
 		log.debug("Deleting flows for path to {}", 
 				path.getDstIpAddress().getHostAddress());
 		
-		for (PushedFlowMod pfm : path.getFlowMods()) {
+		// TODO need update
+		/*for (PushedFlowMod pfm : path.getFlowMods()) {
 			if (log.isTraceEnabled()) {
 				log.trace("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) {
-		flowCache.delete(dpid, addFlowMod);
-	}
 	
 	//TODO test next-hop changes
 	//TODO check delete/add synchronization
-	
-	/*
-	 * On startup we need to calculate a full mesh of paths between all gateway
+
+	/**
+	 * On startup, we need to calculate a full mesh of paths between all gateway
 	 * switches
 	 */
 	private void setupFullMesh(){
@@ -674,12 +705,24 @@
 			
 			//See if we know the MAC address of the peer. If not we can't
 			//do anything until we learn it
-			MACAddress macAddress = proxyArp.getMacAddress(peer.getIpAddress());
+			MACAddress macAddress;
+			IDeviceObject nextHopDevice =
+					deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(peer.getIpAddress()));
+
+			if(nextHopDevice == null){
+				log.debug("There is no DeviceObject for {}", peer.getIpAddress().getHostAddress());
+				//Put in the pending paths list first
+				pathsWaitingOnArp.put(peer.getIpAddress(), path);
+				proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
+				continue;
+			}
+			
+			macAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
+
 			if (macAddress == null) {
 				log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
 				//Put in the pending paths list first
 				pathsWaitingOnArp.put(peer.getIpAddress(), path);
-				
 				proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
 				continue;
 			}
@@ -688,225 +731,271 @@
 			calculateAndPushPath(path, macAddress);
 		}
 	}
-	
+		
 	private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
 		Interface dstInterface = path.getDstInterface();
 		
 		log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
 				dstMacAddress);
-		
-		List<PushedFlowMod> pushedFlows = new ArrayList<PushedFlowMod>();
-		
+
+		FlowPath flowPath = new FlowPath();
+
+		flowPath.setInstallerId(new CallerId("SDNIP"));
+
+		// Set flowPath FlowPathType and FlowPathUserState
+		flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
+		flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
+
+		// Insert the dest-mac based forwarding flow entry to the non-first-hop switches
+		FlowPathFlags flowPathFlags = new FlowPathFlags();
+		flowPathFlags.setFlags(FlowPathFlags.DISCARD_FIRST_HOP_ENTRY);
+		flowPath.setFlowPathFlags(flowPathFlags);
+
+		// Create the DataPath object: dstSwitchPort
+		SwitchPort dstPort = new SwitchPort();
+		dstPort.setDpid(new Dpid(dstInterface.getDpid()));
+		dstPort.setPort(new Port(dstInterface.getPort()));
+
 		for (Interface srcInterface : interfaces.values()) {
+
 			if (dstInterface.equals(srcInterface)){
 				continue;
 			}
-			
-			DataPath shortestPath;
-			if (topology == null) {
-				shortestPath = topologyNetService.getDatabaseShortestPath(
-						srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
+
+			// Create flowPath FlowId
+			//FlowId returnByRefFlowId = new FlowId(flowManagerService.getNextFlowEntryId());
+			//flowPath.setFlowId(returnByRefFlowId);
+			flowPath.setFlowId(new FlowId());
+
+			// Create the DataPath object: srcSwitchPort
+			SwitchPort srcPort = new SwitchPort();
+			srcPort.setDpid(new Dpid(srcInterface.getDpid()));
+			srcPort.setPort(new Port(srcInterface.getPort()));
+
+			DataPath dataPath = new DataPath();
+			dataPath.setSrcPort(srcPort);
+			dataPath.setDstPort(dstPort);
+			flowPath.setDataPath(dataPath);
+
+			// Create the Flow Path Match condition(s)
+			FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
+			flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
+			flowEntryMatch.enableDstMac(dstMacAddress);
+			flowPath.setFlowEntryMatch(flowEntryMatch);
+
+			// NOTE: No need to add ACTION_OUTPUT. It is implied when creating
+			// Shortest Path Flow, and is always the last action for the Flow Entries
+			log.debug("FlowPath of MAC based forwarding: {}", flowPath.toString());
+			if (flowManagerService.addFlow(flowPath) == null) {
+				log.error("Failed to set up MAC based forwarding path to {}, {}",
+						path.getDstIpAddress().getHostAddress(),dstMacAddress);
 			}
 			else {
-				shortestPath = topologyNetService.getTopologyShortestPath(topology, 
-						srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
+				log.debug("Successfully set up MAC based forwarding path to {}, {}",
+						path.getDstIpAddress().getHostAddress(),dstMacAddress);
 			}
-			
-			if (shortestPath == null){
-				log.warn("Shortest path between {} and {} not found",
-						srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
-				return;
-			}
-			
-			List<PushedFlowMod> pushedFlowMods = installPath(shortestPath.flowEntries(), dstMacAddress);
-			pushedFlows.addAll(pushedFlowMods);
 		}
-		
-		path.setFlowMods(pushedFlows);
 	}
-	
-	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()
-                                              .getMessage(OFType.FLOW_MOD);
-		
-        OFActionOutput action = new OFActionOutput();
-        action.setMaxLength((short)0xffff);
-        List<OFAction> actions = new ArrayList<OFAction>();
-        actions.add(action);
-        
-        fm.setIdleTimeout((short)0)
-        .setHardTimeout((short)0)
-        .setBufferId(OFPacketOut.BUFFER_ID_NONE)
-        .setCookie(L2_FWD_COOKIE)
-        .setCommand(OFFlowMod.OFPFC_ADD)
-        .setPriority(SDNIP_PRIORITY)
-        .setActions(actions)
-        .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
-        
-        //Don't push the first flow entry. We need to push entries in the
-		//first switch based on IP prefix which we don't know yet.
-        for (int i = 1; i < flowEntries.size(); i++){        	
-        	FlowEntry flowEntry = flowEntries.get(i);
-           
-            OFMatch match = new OFMatch();
-            match.setDataLayerDestination(dstMacAddress.toBytes());
-            match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
-            ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
-            
-            fm.setMatch(match);
-            
-            flowMods.add(new PushedFlowMod(flowEntry.dpid().value(), fm));
-            
-            flowCache.write(flowEntry.dpid().value(), fm);
-                        
-            try {
-                fm = fm.clone();
-            } catch (CloneNotSupportedException e1) {
-                log.error("Failure cloning flow mod", e1);
-            }
-		}
-        
-        return flowMods;
-	}
-	
-	private void setupBgpPaths(){
-		for (BgpPeer bgpPeer : bgpPeers.values()){
-			Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
-			
-			DataPath path = topologyNetService.getDatabaseShortestPath(
-					peerInterface.getSwitchPort(), bgpdAttachmentPoint);
-			
-			if (path == null){
-				log.debug("Unable to compute path for BGP traffic for {}",
-							bgpPeer.getIpAddress());
-				continue;
-			}
-			
-			//Set up the flow mod
-			OFFlowMod fm =
-	                (OFFlowMod) floodlightProvider.getOFMessageFactory()
-	                                              .getMessage(OFType.FLOW_MOD);
-			
-	        OFActionOutput action = new OFActionOutput();
-	        action.setMaxLength((short)0xffff);
-	        List<OFAction> actions = new ArrayList<OFAction>();
-	        actions.add(action);
-	        
-	        fm.setIdleTimeout((short)0)
-	        .setHardTimeout((short)0)
-	        .setBufferId(OFPacketOut.BUFFER_ID_NONE)
-	        .setCookie(BGP_COOKIE)
-	        .setCommand(OFFlowMod.OFPFC_ADD)
-	        .setPriority(SDNIP_PRIORITY)
-	        .setActions(actions)
-	        .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
 
-	        //Forward = gateway -> bgpd, reverse = bgpd -> gateway
-	        OFMatch forwardMatchSrc = new OFMatch();
-	        
-	        String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress() 
-	        					+ "/32";
-	        String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
-	        					+ "/32";
-	        
-	        //Common match fields
-	        forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
-	        forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
-	        //forwardMatchSrc.setTransportDestination(BGP_PORT);
-	        forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
-	        				& ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
-	        
-	        
-	        OFMatch reverseMatchSrc = forwardMatchSrc.clone();
-	        
-	        forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
-	        forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
-	        
-	        OFMatch forwardMatchDst = forwardMatchSrc.clone();
-	        
-	        forwardMatchSrc.setTransportSource(BGP_PORT);
-	        forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
-	        forwardMatchDst.setTransportDestination(BGP_PORT);
-	        forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
-	        
-	        reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
-	        reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
-	        
-	        OFMatch reverseMatchDst = reverseMatchSrc.clone();
-	        
-	        reverseMatchSrc.setTransportSource(BGP_PORT);
-	        reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
-	        reverseMatchDst.setTransportDestination(BGP_PORT);
-	        reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
-	        
-	        fm.setMatch(forwardMatchSrc);
-	        
-	        OFMatch forwardIcmpMatch = new OFMatch();
-	        forwardIcmpMatch.setDataLayerType(Ethernet.TYPE_IPv4);
-	        forwardIcmpMatch.setNetworkProtocol(IPv4.PROTOCOL_ICMP);
-	        forwardIcmpMatch.setWildcards(forwardIcmpMatch.getWildcards() &
-	        		~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
-	        
-	        OFMatch reverseIcmpMatch = forwardIcmpMatch.clone();
-	        forwardIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
-	        reverseIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
-	        
-			for (FlowEntry flowEntry : path.flowEntries()){
-				OFFlowMod forwardFlowModSrc, forwardFlowModDst;
-				OFFlowMod reverseFlowModSrc, reverseFlowModDst;
-				OFFlowMod forwardIcmp, reverseIcmp;
-				try {
-					forwardFlowModSrc = fm.clone();
-					forwardFlowModDst = fm.clone();
-					reverseFlowModSrc = fm.clone();
-					reverseFlowModDst = fm.clone();
-					forwardIcmp = fm.clone();
-					reverseIcmp = fm.clone();
-				} catch (CloneNotSupportedException e) {
-					log.warn("Clone failed", e);
-					continue;
-				}
-				
-				forwardMatchSrc.setInputPort(flowEntry.inPort().value());
-				forwardFlowModSrc.setMatch(forwardMatchSrc);
-				((OFActionOutput)forwardFlowModSrc.getActions().get(0))
-						.setPort(flowEntry.outPort().value());
-				
-				forwardMatchDst.setInputPort(flowEntry.inPort().value());
-				forwardFlowModDst.setMatch(forwardMatchDst);
-				((OFActionOutput)forwardFlowModDst.getActions().get(0))
-						.setPort(flowEntry.outPort().value());
-				
-				reverseMatchSrc.setInputPort(flowEntry.outPort().value());
-				reverseFlowModSrc.setMatch(reverseMatchSrc);
-				((OFActionOutput)reverseFlowModSrc.getActions().get(0))
-						.setPort(flowEntry.inPort().value());
-				
-				reverseMatchDst.setInputPort(flowEntry.outPort().value());
-				reverseFlowModDst.setMatch(reverseMatchDst);
-				((OFActionOutput)reverseFlowModDst.getActions().get(0))
-						.setPort(flowEntry.inPort().value());
-				
-				((OFActionOutput)forwardIcmp.getActions().get(0))
-						.setPort(flowEntry.outPort().value());
-				forwardIcmp.setMatch(forwardIcmpMatch);
-				
-				((OFActionOutput)reverseIcmp.getActions().get(0))
-						.setPort(flowEntry.inPort().value());
-				reverseIcmp.setMatch(reverseIcmpMatch);
-				
-				List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(6);
-				flowModList.add(forwardFlowModSrc);
-				flowModList.add(forwardFlowModDst);
-				flowModList.add(reverseFlowModSrc);
-				flowModList.add(reverseFlowModDst);
-				flowModList.add(forwardIcmp);
-				flowModList.add(reverseIcmp);
-				flowCache.write(flowEntry.dpid().value(), flowModList);
+	/**
+	 *  Pre-actively install all BGP traffic paths from BGP host attachment point
+	 *  in SDN network to all the virtual gateways to BGP peers in other networks
+	 */
+	private void setupBgpPaths(){
+
+		for (BgpPeer bgpPeer : bgpPeers.values()){
+
+			FlowPath flowPath = new FlowPath();
+			flowPath.setInstallerId(new CallerId("SDNIP"));
+
+			// Set flowPath FlowPathType and FlowPathUserState
+			flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
+			flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
+
+			// Install flow paths between BGPd and its peers
+			// There is no need to set the FlowPathFlags
+			flowPath.setFlowPathFlags(new FlowPathFlags(0));
+
+			Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
+
+			// set flowPath FlowId
+			//FlowId returnByRefFlowId = new FlowId(flowManagerService.getNextFlowEntryId());
+			//flowPath.setFlowId(returnByRefFlowId);
+
+
+			// Create the Flow Path Match condition(s)
+			FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
+			flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
+
+			// Match both source address and dest address
+			IPv4Net dstIPv4Net= new IPv4Net(bgpPeer.getIpAddress().getHostAddress()+"/32");
+			flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
+
+			IPv4Net srcIPv4Net= new IPv4Net(peerInterface.getIpAddress().getHostAddress()+"/32");
+			flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
+
+			// Match TCP protocol
+			flowEntryMatch.enableIpProto(IPv4.PROTOCOL_TCP);
+
+			// Match destination TCP port
+			flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
+			flowPath.setFlowEntryMatch(flowEntryMatch);
+
+			/**
+			 * Create the DataPath: BGP -> BGP peer
+			 */
+			// Flow path for src-TCP-port
+			DataPath dataPath = new DataPath();
+
+			SwitchPort srcPort = new SwitchPort();
+			srcPort.setDpid(bgpdAttachmentPoint.dpid());
+			srcPort.setPort(bgpdAttachmentPoint.port());
+			dataPath.setSrcPort(srcPort);
+
+			SwitchPort dstPort = new SwitchPort();
+			dstPort.setDpid(new Dpid(peerInterface.getDpid()));
+			dstPort.setPort(new Port(peerInterface.getSwitchPort().port()));
+			dataPath.setDstPort(dstPort);
+
+			flowPath.setDataPath(dataPath);
+
+			if (flowManagerService.addFlow(flowPath) == null) {
+				log.error("Failed to set up path BGP -> peer {}"+"; dst-TCP-port:179",
+						bgpPeer.getIpAddress().getHostAddress());
+			}
+			else {
+				log.debug("Successfully set up path BGP -> peer {}"+"; dst-TCP-port:179",
+						bgpPeer.getIpAddress().getHostAddress());
+			}
+
+			// Disable dst-TCP-port, and set src-TCP-port
+			flowEntryMatch.disableDstTcpUdpPort();
+			flowEntryMatch.enableSrcTcpUdpPort(BGP_PORT);
+			flowPath.setFlowEntryMatch(flowEntryMatch);
+
+			// Create a new FlowId
+			//FlowId returnByRefFlowId2 = new FlowId(flowManagerService.getNextFlowEntryId());
+			//flowPath.setFlowId(returnByRefFlowId2);
+			flowPath.setFlowId(new FlowId());
+
+			if (flowManagerService.addFlow(flowPath) == null) {
+				log.error("Failed to set up path BGP -> Peer {}" + "; src-TCP-port:179",
+						bgpPeer.getIpAddress().getHostAddress());
+			}
+			else {
+				log.debug("Successfully set up path BGP -> Peer {}" + "; src-TCP-port:179",
+						bgpPeer.getIpAddress().getHostAddress());
+			}
+
+			/**
+			 * Create the DataPath: BGP <-BGP peer
+			 */
+			// Reversed BGP flow path for src-TCP-port
+			//FlowId returnByRefFlowId3 = new FlowId(flowManagerService.getNextFlowEntryId());
+			//flowPath.setFlowId(returnByRefFlowId3);
+			flowPath.setFlowId(new FlowId());
+
+			DataPath reverse_dataPath = new DataPath();
+
+			SwitchPort reverse_dstPort = new SwitchPort();
+			reverse_dstPort.setDpid(bgpdAttachmentPoint.dpid());
+			reverse_dstPort.setPort(bgpdAttachmentPoint.port());
+			reverse_dataPath.setDstPort(reverse_dstPort);
+
+			SwitchPort reverse_srcPort = new SwitchPort();
+			reverse_srcPort.setDpid(new Dpid(peerInterface.getDpid()));
+			reverse_srcPort.setPort(new Port(peerInterface.getSwitchPort().port()));
+			reverse_dataPath.setSrcPort(reverse_srcPort);
+			flowPath.setDataPath(reverse_dataPath);
+
+			// reverse the dst IP and src IP addresses
+			flowEntryMatch.enableDstIPv4Net(srcIPv4Net);
+			flowEntryMatch.enableSrcIPv4Net(dstIPv4Net);
+			flowPath.setFlowEntryMatch(flowEntryMatch);
+
+			log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
+
+			if (flowManagerService.addFlow(flowPath) == null) {
+
+				log.error("Failed to set up path BGP <- Peer {}" + "; src-TCP-port:179",
+						bgpPeer.getIpAddress().getHostAddress());
+			}
+			else {
+				log.debug("Successfully set up path BGP <- Peer {}" + "; src-TCP-port:179",
+						bgpPeer.getIpAddress().getHostAddress());
+			}
+
+			// Reversed BGP flow path for dst-TCP-port
+			//FlowId returnByRefFlowId4 = new FlowId(flowManagerService.getNextFlowEntryId());
+			//flowPath.setFlowId(returnByRefFlowId4);
+			flowPath.setFlowId(new FlowId());
+
+			// Disable src-TCP-port, and set the dst-TCP-port
+			flowEntryMatch.disableSrcTcpUdpPort();
+			flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
+			flowPath.setFlowEntryMatch(flowEntryMatch);
+
+			log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
+			
+			if (flowManagerService.addFlow(flowPath) == null) {
+				log.error("Failed to setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
+						bgpPeer.getIpAddress().getHostAddress());
+			}
+			else {
+				log.debug("Successfully setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
+						bgpPeer.getIpAddress().getHostAddress());
+			}
+
+			/**
+			 * ICMP paths between BGPd and its peers
+			 */
+			//match ICMP protocol BGP <- Peer
+			//FlowId returnByRefFlowId5 = new FlowId(flowManagerService.getNextFlowEntryId());
+			//flowPath.setFlowId(returnByRefFlowId5);
+			flowPath.setFlowId(new FlowId());
+
+			flowEntryMatch.enableIpProto(IPv4.PROTOCOL_ICMP);
+			flowEntryMatch.disableSrcTcpUdpPort();
+			flowEntryMatch.disableDstTcpUdpPort();
+
+			flowPath.setFlowEntryMatch(flowEntryMatch);
+
+			flowPath.setDataPath(reverse_dataPath);
+
+			log.debug("Reversed ICMP FlowPath: {}", flowPath.toString());
+
+			if (flowManagerService.addFlow(flowPath) == null) {
+
+				log.error("Failed to set up ICMP path BGP <- Peer {}",
+						bgpPeer.getIpAddress().getHostAddress());
+			}
+			else {
+				log.debug("Successfully set up ICMP path BGP <- Peer {}",
+						bgpPeer.getIpAddress().getHostAddress());
+			}
+
+			//match ICMP protocol BGP -> Peer
+			//FlowId returnByRefFlowId6 = new FlowId(flowManagerService.getNextFlowEntryId());
+			//flowPath.setFlowId(returnByRefFlowId6);
+			flowPath.setFlowId(new FlowId());
+
+			flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
+			flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
+			flowPath.setFlowEntryMatch(flowEntryMatch);
+
+			flowPath.setDataPath(dataPath);
+
+			log.debug("ICMP flowPath: {}", flowPath.toString());
+
+
+			if (flowManagerService.addFlow(flowPath) == null) {
+
+				log.error("Failed to set up ICMP path BGP -> Peer {}",
+						bgpPeer.getIpAddress().getHostAddress());
+			}
+			else {
+				log.debug("Successfully set up ICMP path BGP -> Peer {}",
+						bgpPeer.getIpAddress().getHostAddress());
 			}
 		}
 	}
@@ -965,6 +1054,7 @@
 		}
 	}
 	
+	//TODO wait the priority module of the flow Manager
 	private void setupArpFlows() {
 		OFMatch match = new OFMatch();
 		match.setDataLayerType(Ethernet.TYPE_ARP);
@@ -981,36 +1071,36 @@
 		fm.setActions(actions);
 		
 		fm.setIdleTimeout((short)0)
-        .setHardTimeout((short)0)
-        .setBufferId(OFPacketOut.BUFFER_ID_NONE)
-        .setCookie(0)
-        .setCommand(OFFlowMod.OFPFC_ADD)
-        .setPriority(ARP_PRIORITY)
+		.setHardTimeout((short)0)
+		.setBufferId(OFPacketOut.BUFFER_ID_NONE)
+		.setCookie(0)
+		.setCommand(OFFlowMod.OFPFC_ADD)
+		.setPriority(ARP_PRIORITY)
 		.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
 		
 		for (String strdpid : switches){
 			flowCache.write(HexString.toLong(strdpid), fm);
 		}
 	}
-	
+	//TODO need update, waiting for the priority feature from flow Manager
 	private void setupDefaultDropFlows() {
 		OFFlowMod fm = new OFFlowMod();
 		fm.setMatch(new OFMatch());
 		fm.setActions(new ArrayList<OFAction>()); //No action means drop
 		
 		fm.setIdleTimeout((short)0)
-        .setHardTimeout((short)0)
-        .setBufferId(OFPacketOut.BUFFER_ID_NONE)
-        .setCookie(0)
-        .setCommand(OFFlowMod.OFPFC_ADD)
-        .setPriority((short)0)
+		.setHardTimeout((short)0)
+		.setBufferId(OFPacketOut.BUFFER_ID_NONE)
+		.setCookie(0)
+		.setCommand(OFFlowMod.OFPFC_ADD)
+		.setPriority((short)0)
 		.setLengthU(OFFlowMod.MINIMUM_LENGTH);
 		
 		OFFlowMod fmLLDP;
 		OFFlowMod fmBDDP;
 		try {
-			 fmLLDP = fm.clone();
-			 fmBDDP = fm.clone();
+			fmLLDP = fm.clone();
+			fmBDDP = fm.clone();
 		} catch (CloneNotSupportedException e1) {
 			log.error("Error cloning flow mod", e1);
 			return;
@@ -1054,8 +1144,9 @@
 		log.debug("Topology is now ready, beginning routing function");
 		topology = topologyNetService.newDatabaseTopology();
 		
-		setupArpFlows();
-		setupDefaultDropFlows();
+		// Wait Pavlin's API. We need the following functions.
+		/*setupArpFlows();
+		setupDefaultDropFlows();*/
 		
 		setupBgpPaths();
 		setupFullMesh();
@@ -1073,11 +1164,22 @@
 		});
 	}
 	
+	// Before inserting the paths for BGP traffic, we should check
+	// whether all the switches in the configure file are discovered by onos.
 	private void checkSwitchesConnected(){
 		for (String dpid : switches){
-			if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
-				log.debug("Not all switches are here yet");
-				return;
+			Iterator<ISwitchObject> activeSwitches = topoSwitchService.
+					getActiveSwitches().iterator();
+			while(activeSwitches.hasNext())
+			{
+				ISwitchObject switchObject = activeSwitches.next();
+				if (switchObject.getDPID().equals(dpid)) {
+					break;
+				}
+				if(activeSwitches.hasNext() == false) {
+					log.debug("Not all switches are here yet");
+					return;
+				}
 			}
 		}
 		switchesConnected = true;