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;
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/BgpProxyArpManager.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/BgpProxyArpManager.java
deleted file mode 100644
index 3dba4f8..0000000
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/BgpProxyArpManager.java
+++ /dev/null
@@ -1,637 +0,0 @@
-package net.onrc.onos.ofcontroller.proxyarp;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.Timer;
-import java.util.TimerTask;
-
-import net.floodlightcontroller.core.FloodlightContext;
-import net.floodlightcontroller.core.IFloodlightProviderService;
-import net.floodlightcontroller.core.IOFMessageListener;
-import net.floodlightcontroller.core.IOFSwitch;
-import net.floodlightcontroller.packet.ARP;
-import net.floodlightcontroller.packet.Ethernet;
-import net.floodlightcontroller.packet.IPv4;
-import net.floodlightcontroller.restserver.IRestApiService;
-import net.floodlightcontroller.topology.ITopologyService;
-import net.floodlightcontroller.util.MACAddress;
-import net.onrc.onos.ofcontroller.bgproute.Interface;
-import net.onrc.onos.ofcontroller.core.IDeviceStorage;
-import net.onrc.onos.ofcontroller.core.config.IConfigInfoService;
-import net.onrc.onos.ofcontroller.core.internal.DeviceStorageImpl;
-
-import org.openflow.protocol.OFMessage;
-import org.openflow.protocol.OFPacketIn;
-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.OFActionOutput;
-import org.openflow.util.HexString;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Multimaps;
-import com.google.common.collect.SetMultimap;
-
-public class BgpProxyArpManager implements IProxyArpService, IOFMessageListener {
- private final static Logger log = LoggerFactory.getLogger(BgpProxyArpManager.class);
-
- private final long ARP_TIMER_PERIOD = 60000; //ms (== 1 min)
-
- private static final int ARP_REQUEST_TIMEOUT = 2000; //ms
-
- private IFloodlightProviderService floodlightProvider;
- private ITopologyService topology;
- //private IDeviceService deviceService;
- private IConfigInfoService configService;
- private IRestApiService restApi;
-
- private IDeviceStorage deviceStorage;
-
- private short vlan;
- private static final short NO_VLAN = 0;
-
- private ArpCache arpCache;
-
- private SetMultimap<InetAddress, ArpRequest> arpRequests;
-
- private static class ArpRequest {
- private final IArpRequester requester;
- private final boolean retry;
- private long requestTime;
-
- public ArpRequest(IArpRequester requester, boolean retry){
- this.requester = requester;
- this.retry = retry;
- this.requestTime = System.currentTimeMillis();
- }
-
- public ArpRequest(ArpRequest old) {
- this.requester = old.requester;
- this.retry = old.retry;
- this.requestTime = System.currentTimeMillis();
- }
-
- public boolean isExpired() {
- return (System.currentTimeMillis() - requestTime) > ARP_REQUEST_TIMEOUT;
- }
-
- public boolean shouldRetry() {
- return retry;
- }
-
- public void dispatchReply(InetAddress ipAddress, MACAddress replyMacAddress) {
- requester.arpResponse(ipAddress, replyMacAddress);
- }
- }
-
- private class HostArpRequester implements IArpRequester {
- private final ARP arpRequest;
- private final long dpid;
- private final short port;
-
- public HostArpRequester(ARP arpRequest, long dpid, short port) {
- this.arpRequest = arpRequest;
- this.dpid = dpid;
- this.port = port;
- }
-
- @Override
- public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
- BgpProxyArpManager.this.sendArpReply(arpRequest, dpid, port, macAddress);
- }
- }
-
- /*
- public ProxyArpManager(IFloodlightProviderService floodlightProvider,
- ITopologyService topology, IConfigInfoService configService,
- IRestApiService restApi){
-
- }
- */
-
- public void init(IFloodlightProviderService floodlightProvider,
- ITopologyService topology,
- IConfigInfoService config, IRestApiService restApi){
- this.floodlightProvider = floodlightProvider;
- this.topology = topology;
- //this.deviceService = deviceService;
- this.configService = config;
- this.restApi = restApi;
-
- arpCache = new ArpCache();
-
- arpRequests = Multimaps.synchronizedSetMultimap(
- HashMultimap.<InetAddress, ArpRequest>create());
- }
-
- public void startUp() {
- this.vlan = configService.getVlan();
- log.info("vlan set to {}", this.vlan);
-
- restApi.addRestletRoutable(new ArpWebRoutable());
- floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
-
- deviceStorage = new DeviceStorageImpl();
- deviceStorage.init("","");
-
- Timer arpTimer = new Timer("arp-processing");
- arpTimer.scheduleAtFixedRate(new TimerTask() {
- @Override
- public void run() {
- doPeriodicArpProcessing();
- }
- }, 0, ARP_TIMER_PERIOD);
- }
-
- /*
- * Function that runs periodically to manage the asynchronous request mechanism.
- * It basically cleans up old ARP requests if we don't get a response for them.
- * The caller can designate that a request should be retried indefinitely, and
- * this task will handle that as well.
- */
- private void doPeriodicArpProcessing() {
- SetMultimap<InetAddress, ArpRequest> retryList
- = HashMultimap.<InetAddress, ArpRequest>create();
-
- //Have to synchronize externally on the Multimap while using an iterator,
- //even though it's a synchronizedMultimap
- synchronized (arpRequests) {
- log.debug("Current have {} outstanding requests",
- arpRequests.size());
-
- Iterator<Map.Entry<InetAddress, ArpRequest>> it
- = arpRequests.entries().iterator();
-
- while (it.hasNext()) {
- Map.Entry<InetAddress, ArpRequest> entry
- = it.next();
- ArpRequest request = entry.getValue();
- if (request.isExpired()) {
- log.debug("Cleaning expired ARP request for {}",
- entry.getKey().getHostAddress());
-
- it.remove();
-
- if (request.shouldRetry()) {
- retryList.put(entry.getKey(), request);
- }
- }
- }
- }
-
- for (Map.Entry<InetAddress, Collection<ArpRequest>> entry
- : retryList.asMap().entrySet()) {
-
- InetAddress address = entry.getKey();
-
- log.debug("Resending ARP request for {}", address.getHostAddress());
-
- sendArpRequestForAddress(address);
-
- for (ArpRequest request : entry.getValue()) {
- arpRequests.put(address, new ArpRequest(request));
- }
- }
- }
-
- @Override
- public String getName() {
- return "proxyarpmanager";
- }
-
- @Override
- public boolean isCallbackOrderingPrereq(OFType type, String name) {
- if (type == OFType.PACKET_IN) {
- return "devicemanager".equals(name);
- }
- else {
- return false;
- }
- }
-
- @Override
- public boolean isCallbackOrderingPostreq(OFType type, String name) {
- return false;
- }
-
- @Override
- public Command receive(
- IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
-
- if (msg.getType() != OFType.PACKET_IN){
- return Command.CONTINUE;
- }
-
- OFPacketIn pi = (OFPacketIn) msg;
-
- Ethernet eth = IFloodlightProviderService.bcStore.get(cntx,
- IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
-
- if (eth.getEtherType() == Ethernet.TYPE_ARP){
- ARP arp = (ARP) eth.getPayload();
-
- if (arp.getOpCode() == ARP.OP_REQUEST) {
- //TODO check what the DeviceManager does about propagating
- //or swallowing ARPs. We want to go after DeviceManager in the
- //chain but we really need it to CONTINUE ARP packets so we can
- //get them.
- handleArpRequest(sw, pi, arp);
- }
- else if (arp.getOpCode() == ARP.OP_REPLY) {
- handleArpReply(sw, pi, arp);
- }
- }
-
- //TODO should we propagate ARP or swallow it?
- //Always propagate for now so DeviceManager can learn the host location
- return Command.CONTINUE;
- }
-
- private void handleArpRequest(IOFSwitch sw, OFPacketIn pi, ARP arp) {
- if (log.isTraceEnabled()) {
- log.trace("ARP request received for {}",
- inetAddressToString(arp.getTargetProtocolAddress()));
- }
-
- InetAddress target;
- try {
- target = InetAddress.getByAddress(arp.getTargetProtocolAddress());
- } catch (UnknownHostException e) {
- log.debug("Invalid address in ARP request", e);
- return;
- }
-
- if (configService.fromExternalNetwork(sw.getId(), pi.getInPort())) {
- //If the request came from outside our network, we only care if
- //it was a request for one of our interfaces.
- if (configService.isInterfaceAddress(target)) {
- log.trace("ARP request for our interface. Sending reply {} => {}",
- target.getHostAddress(), configService.getRouterMacAddress());
-
- sendArpReply(arp, sw.getId(), pi.getInPort(),
- configService.getRouterMacAddress());
- }
-
- return;
- }
-
- MACAddress macAddress = arpCache.lookup(target);
-
- //IDevice dstDevice = deviceService.fcStore.get(cntx, IDeviceService.CONTEXT_DST_DEVICE);
- //Iterator<? extends IDevice> it = deviceService.queryDevices(
- //null, null, InetAddresses.coerceToInteger(target), null, null);
-
- //IDevice targetDevice = null;
- //if (it.hasNext()) {
- //targetDevice = it.next();
- //}
- /*IDeviceObject targetDevice =
- deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(target));
-
- if (targetDevice != null) {
- //We have the device in our database, so send a reply
- MACAddress macAddress = MACAddress.valueOf(targetDevice.getMACAddress());
-
- if (log.isTraceEnabled()) {
- log.trace("Sending reply: {} => {} to host at {}/{}", new Object [] {
- inetAddressToString(arp.getTargetProtocolAddress()),
- macAddress.toString(),
- HexString.toHexString(sw.getId()), pi.getInPort()});
- }
-
- sendArpReply(arp, sw.getId(), pi.getInPort(), macAddress);
- }*/
-
- if (macAddress == null){
- //MAC address is not in our ARP cache.
-
- //Record where the request came from so we know where to send the reply
- arpRequests.put(target, new ArpRequest(
- new HostArpRequester(arp, sw.getId(), pi.getInPort()), false));
-
- //Flood the request out edge ports
- sendArpRequestToSwitches(target, pi.getPacketData(), sw.getId(), pi.getInPort());
- }
- else {
- //We know the address, so send a reply
- if (log.isTraceEnabled()) {
- log.trace("Sending reply: {} => {} to host at {}/{}", new Object [] {
- inetAddressToString(arp.getTargetProtocolAddress()),
- macAddress.toString(),
- HexString.toHexString(sw.getId()), pi.getInPort()});
- }
-
- sendArpReply(arp, sw.getId(), pi.getInPort(), macAddress);
- }
- }
-
- private void handleArpReply(IOFSwitch sw, OFPacketIn pi, ARP arp){
- if (log.isTraceEnabled()) {
- log.trace("ARP reply recieved: {} => {}, on {}/{}", new Object[] {
- inetAddressToString(arp.getSenderProtocolAddress()),
- HexString.toHexString(arp.getSenderHardwareAddress()),
- HexString.toHexString(sw.getId()), pi.getInPort()});
- }
-
- InetAddress senderIpAddress;
- try {
- senderIpAddress = InetAddress.getByAddress(arp.getSenderProtocolAddress());
- } catch (UnknownHostException e) {
- log.debug("Invalid address in ARP reply", e);
- return;
- }
-
- MACAddress senderMacAddress = MACAddress.valueOf(arp.getSenderHardwareAddress());
-
- arpCache.update(senderIpAddress, senderMacAddress);
-
- //See if anyone's waiting for this ARP reply
- Set<ArpRequest> requests = arpRequests.get(senderIpAddress);
-
- //Synchronize on the Multimap while using an iterator for one of the sets
- List<ArpRequest> requestsToSend = new ArrayList<ArpRequest>(requests.size());
- synchronized (arpRequests) {
- Iterator<ArpRequest> it = requests.iterator();
- while (it.hasNext()) {
- ArpRequest request = it.next();
- it.remove();
- requestsToSend.add(request);
- }
- }
-
- //Don't hold an ARP lock while dispatching requests
- for (ArpRequest request : requestsToSend) {
- request.dispatchReply(senderIpAddress, senderMacAddress);
- }
- }
-
- private void sendArpRequestForAddress(InetAddress ipAddress) {
- //TODO what should the sender IP address and MAC address be if no
- //IP addresses are configured? Will there ever be a need to send
- //ARP requests from the controller in that case?
- //All-zero MAC address doesn't seem to work - hosts don't respond to it
-
- byte[] zeroIpv4 = {0x0, 0x0, 0x0, 0x0};
- byte[] zeroMac = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
- byte[] genericNonZeroMac = {0x0, 0x0, 0x0, 0x0, 0x0, 0x01};
- byte[] broadcastMac = {(byte)0xff, (byte)0xff, (byte)0xff,
- (byte)0xff, (byte)0xff, (byte)0xff};
-
- ARP arpRequest = new ARP();
-
- arpRequest.setHardwareType(ARP.HW_TYPE_ETHERNET)
- .setProtocolType(ARP.PROTO_TYPE_IP)
- .setHardwareAddressLength((byte)Ethernet.DATALAYER_ADDRESS_LENGTH)
- .setProtocolAddressLength((byte)IPv4.ADDRESS_LENGTH)
- .setOpCode(ARP.OP_REQUEST)
- .setTargetHardwareAddress(zeroMac)
- .setTargetProtocolAddress(ipAddress.getAddress());
-
- MACAddress routerMacAddress = configService.getRouterMacAddress();
- //TODO hack for now as it's unclear what the MAC address should be
- byte[] senderMacAddress = genericNonZeroMac;
- if (routerMacAddress != null) {
- senderMacAddress = routerMacAddress.toBytes();
- }
- arpRequest.setSenderHardwareAddress(senderMacAddress);
-
- byte[] senderIPAddress = zeroIpv4;
- Interface intf = configService.getOutgoingInterface(ipAddress);
- if (intf != null) {
- senderIPAddress = intf.getIpAddress().getAddress();
- }
-
- arpRequest.setSenderProtocolAddress(senderIPAddress);
-
- Ethernet eth = new Ethernet();
- eth.setSourceMACAddress(senderMacAddress)
- .setDestinationMACAddress(broadcastMac)
- .setEtherType(Ethernet.TYPE_ARP)
- .setPayload(arpRequest);
-
- if (vlan != NO_VLAN) {
- eth.setVlanID(vlan)
- .setPriorityCode((byte)0);
- }
-
- sendArpRequestToSwitches(ipAddress, eth.serialize());
- }
-
- private void sendArpRequestToSwitches(InetAddress dstAddress, byte[] arpRequest) {
- sendArpRequestToSwitches(dstAddress, arpRequest,
- 0, OFPort.OFPP_NONE.getValue());
- }
-
- private void sendArpRequestToSwitches(InetAddress dstAddress, byte[] arpRequest,
- long inSwitch, short inPort) {
-
- if (configService.hasLayer3Configuration()) {
- Interface intf = configService.getOutgoingInterface(dstAddress);
- if (intf != null) {
- sendArpRequestOutPort(arpRequest, intf.getDpid(), intf.getPort());
- }
- else {
- //TODO here it should be broadcast out all non-interface edge ports.
- //I think we can assume that if it's not a request for an external
- //network, it's an ARP for a host in our own network. So we want to
- //send it out all edge ports that don't have an interface configured
- //to ensure it reaches all hosts in our network.
- log.debug("No interface found to send ARP request for {}",
- dstAddress.getHostAddress());
- }
- }
- else {
- broadcastArpRequestOutEdge(arpRequest, inSwitch, inPort);
- }
- }
-
- private void broadcastArpRequestOutEdge(byte[] arpRequest, long inSwitch, short inPort) {
- for (IOFSwitch sw : floodlightProvider.getSwitches().values()){
- Collection<Short> enabledPorts = sw.getEnabledPortNumbers();
- Set<Short> linkPorts = topology.getPortsWithLinks(sw.getId());
-
- if (linkPorts == null){
- //I think this means the switch doesn't have any links.
- //continue;
- linkPorts = new HashSet<Short>();
- }
-
-
- OFPacketOut po = new OFPacketOut();
- po.setInPort(OFPort.OFPP_NONE)
- .setBufferId(-1)
- .setPacketData(arpRequest);
-
- List<OFAction> actions = new ArrayList<OFAction>();
-
- for (short portNum : enabledPorts){
- if (linkPorts.contains(portNum) ||
- (sw.getId() == inSwitch && portNum == inPort)){
- //If this port isn't an edge port or is the ingress port
- //for the ARP, don't broadcast out it
- continue;
- }
-
- actions.add(new OFActionOutput(portNum));
- }
-
- po.setActions(actions);
- short actionsLength = (short) (actions.size() * OFActionOutput.MINIMUM_LENGTH);
- po.setActionsLength(actionsLength);
- po.setLengthU(OFPacketOut.MINIMUM_LENGTH + actionsLength
- + arpRequest.length);
-
- List<OFMessage> msgList = new ArrayList<OFMessage>();
- msgList.add(po);
-
- try {
- sw.write(msgList, null);
- sw.flush();
- } catch (IOException e) {
- log.error("Failure writing packet out to switch", e);
- }
- }
- }
-
- private void sendArpRequestOutPort(byte[] arpRequest, long dpid, short port) {
- if (log.isTraceEnabled()) {
- log.trace("Sending ARP request out {}/{}",
- HexString.toHexString(dpid), port);
- }
-
- OFPacketOut po = new OFPacketOut();
- po.setInPort(OFPort.OFPP_NONE)
- .setBufferId(-1)
- .setPacketData(arpRequest);
-
- List<OFAction> actions = new ArrayList<OFAction>();
- actions.add(new OFActionOutput(port));
- po.setActions(actions);
- short actionsLength = (short) (actions.size() * OFActionOutput.MINIMUM_LENGTH);
- po.setActionsLength(actionsLength);
- po.setLengthU(OFPacketOut.MINIMUM_LENGTH + actionsLength
- + arpRequest.length);
-
- IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
-
- if (sw == null) {
- log.warn("Switch not found when sending ARP request");
- return;
- }
-
- try {
- sw.write(po, null);
- sw.flush();
- } catch (IOException e) {
- log.error("Failure writing packet out to switch", e);
- }
- }
-
- private void sendArpReply(ARP arpRequest, long dpid, short port, MACAddress targetMac) {
- if (log.isTraceEnabled()) {
- log.trace("Sending reply {} => {} to {}", new Object[] {
- inetAddressToString(arpRequest.getTargetProtocolAddress()),
- targetMac,
- inetAddressToString(arpRequest.getSenderProtocolAddress())});
- }
-
- ARP arpReply = new ARP();
- arpReply.setHardwareType(ARP.HW_TYPE_ETHERNET)
- .setProtocolType(ARP.PROTO_TYPE_IP)
- .setHardwareAddressLength((byte)Ethernet.DATALAYER_ADDRESS_LENGTH)
- .setProtocolAddressLength((byte)IPv4.ADDRESS_LENGTH)
- .setOpCode(ARP.OP_REPLY)
- .setSenderHardwareAddress(targetMac.toBytes())
- .setSenderProtocolAddress(arpRequest.getTargetProtocolAddress())
- .setTargetHardwareAddress(arpRequest.getSenderHardwareAddress())
- .setTargetProtocolAddress(arpRequest.getSenderProtocolAddress());
-
-
-
- Ethernet eth = new Ethernet();
- eth.setDestinationMACAddress(arpRequest.getSenderHardwareAddress())
- .setSourceMACAddress(targetMac.toBytes())
- .setEtherType(Ethernet.TYPE_ARP)
- .setPayload(arpReply);
-
- if (vlan != NO_VLAN) {
- eth.setVlanID(vlan)
- .setPriorityCode((byte)0);
- }
-
- List<OFAction> actions = new ArrayList<OFAction>();
- actions.add(new OFActionOutput(port));
-
- OFPacketOut po = new OFPacketOut();
- po.setInPort(OFPort.OFPP_NONE)
- .setBufferId(-1)
- .setPacketData(eth.serialize())
- .setActions(actions)
- .setActionsLength((short)OFActionOutput.MINIMUM_LENGTH)
- .setLengthU(OFPacketOut.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH
- + po.getPacketData().length);
-
- List<OFMessage> msgList = new ArrayList<OFMessage>();
- msgList.add(po);
-
- IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
-
- if (sw == null) {
- log.warn("Switch {} not found when sending ARP reply",
- HexString.toHexString(dpid));
- return;
- }
-
- try {
- sw.write(msgList, null);
- sw.flush();
- } catch (IOException e) {
- log.error("Failure writing packet out to switch", e);
- }
- }
-
- private String inetAddressToString(byte[] bytes) {
- try {
- return InetAddress.getByAddress(bytes).getHostAddress();
- } catch (UnknownHostException e) {
- log.debug("Invalid IP address", e);
- return "";
- }
- }
-
- /*
- * IProxyArpService methods
- */
-
- @Override
- public MACAddress getMacAddress(InetAddress ipAddress) {
- return arpCache.lookup(ipAddress);
- }
-
- @Override
- public void sendArpRequest(InetAddress ipAddress, IArpRequester requester,
- boolean retry) {
- arpRequests.put(ipAddress, new ArpRequest(requester, retry));
-
- //Sanity check to make sure we don't send a request for our own address
- if (!configService.isInterfaceAddress(ipAddress)) {
- sendArpRequestForAddress(ipAddress);
- }
- }
-
- @Override
- public List<String> getMappings() {
- return arpCache.getMappings();
- }
-}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
index f5fee45..c7d495c 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
@@ -229,7 +229,6 @@
// TODO check whether this is OK from this thread
IDeviceObject targetDevice =
deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(entry.getKey()));
-
if (targetDevice != null) {
deviceStorage.removeDevice(targetDevice);
if (log.isDebugEnabled()) {
@@ -253,6 +252,8 @@
log.debug("Resending ARP request for {}", address.getHostAddress());
+ // Only ARP requests sent by the controller will have the retry flag
+ // set, so for now we can just send a new ARP request for that address.
sendArpRequestForAddress(address);
for (ArpRequest request : entry.getValue()) {
@@ -433,8 +434,6 @@
MACAddress senderMacAddress = MACAddress.valueOf(arp.getSenderHardwareAddress());
- //arpCache.update(senderIpAddress, senderMacAddress);
-
//See if anyone's waiting for this ARP reply
Set<ArpRequest> requests = arpRequests.get(senderIpAddress);
@@ -504,7 +503,8 @@
.setPriorityCode((byte)0);
}
- sendArpRequestToSwitches(ipAddress, eth.serialize());
+ //sendArpRequestToSwitches(ipAddress, eth.serialize());
+ datagrid.sendPacketOutNotification(new SinglePacketOutNotification(eth.serialize(),intf.getDpid(),intf.getPort()));
}
private void sendArpRequestToSwitches(InetAddress dstAddress, byte[] arpRequest) {
@@ -531,7 +531,8 @@
}
}
else {
- broadcastArpRequestOutEdge(arpRequest, inSwitch, inPort);
+ //broadcastArpRequestOutEdge(arpRequest, inSwitch, inPort);
+ broadcastArpRequestOutMyEdge(arpRequest, inSwitch, inPort);
}
}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/util/FlowPathFlags.java b/src/main/java/net/onrc/onos/ofcontroller/util/FlowPathFlags.java
index 595eb5f..3c6ffc4 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/util/FlowPathFlags.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/util/FlowPathFlags.java
@@ -9,10 +9,10 @@
private long flags;
// Discard the first-hop Flow Entry
- private static final long DISCARD_FIRST_HOP_ENTRY = (1 << 0);
+ public static final long DISCARD_FIRST_HOP_ENTRY = (1 << 0);
// Keep only the first-hop Flow Entry
- private static final long KEEP_ONLY_FIRST_HOP_ENTRY = (1 << 1);
+ public static final long KEEP_ONLY_FIRST_HOP_ENTRY = (1 << 1);
/**
* Default constructor.
@@ -125,4 +125,5 @@
return ret;
}
+
}