Skip to content
Snippets Groups Projects
Commit 6668294a authored by Shudong Zhou's avatar Shudong Zhou
Browse files

Improve send LLDP and add a couple of forwarding utilities [#30267549]

parent a79a9e21
No related branches found
No related tags found
No related merge requests found
......@@ -26,6 +26,7 @@ import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
......@@ -142,6 +143,7 @@ public class LinkDiscoveryManager
protected IRoutingService routingEngine;
protected IThreadPoolService threadPool;
protected SingletonTask sendLLDPTask;
private static final byte[] LLDP_STANDARD_DST_MAC_STRING =
HexString.fromHexString("01:80:c2:00:00:00");
// BigSwitch OUI is 5C:16:C7, so 5D:16:C7 is the multicast version
......@@ -201,7 +203,8 @@ public class LinkDiscoveryManager
public void AddToSuppressLLDPs(IOFSwitch sw, short port)
{
this.suppressLLDPs.add(new SwitchPortTuple(sw, port));
SwitchPortTuple swt = new SwitchPortTuple(sw, port);
this.suppressLLDPs.add(swt);
}
public void RemoveFromSuppressLLDPs(IOFSwitch sw, short port)
......@@ -434,7 +437,7 @@ public class LinkDiscoveryManager
private Command handleLldp(LLDP lldp, IOFSwitch sw, OFPacketIn pi, boolean isStandard, FloodlightContext cntx) {
// If LLDP is suppressed on this port, ignore received packet as well
if (isLLDPSuppressed(sw, pi.getInPort()))
return Command.CONTINUE;
return Command.STOP;
// If this is a malformed LLDP, or not from us, exit
if (lldp.getPortId() == null || lldp.getPortId().getLength() != 3)
......@@ -496,6 +499,11 @@ public class LinkDiscoveryManager
log.debug("Ignoring link with disabled source port: switch {} port {}", remoteSwitch, remotePort);
return Command.STOP;
}
if (suppressLLDPs.contains(new SwitchPortTuple(remoteSwitch, remotePort))) {
log.debug("Ignoring link with suppressed src port: switch {} port {}",
remoteSwitch, remotePort);
return Command.STOP;
}
if (!sw.portEnabled(pi.getInPort())) {
log.debug("Ignoring link with disabled dest port: switch {} port {}", sw, pi.getInPort());
return Command.STOP;
......@@ -826,7 +834,8 @@ public class LinkDiscoveryManager
// cluster-merge. If it is a link delete then there is not need
// to send the LLDPs right away and instead we wait for the LLDPs
// to be sent on the timer as it is normally done
sendLLDPs(); // do it outside the write-lock
// do it outside the write-lock
sendLLDPTask.reschedule(1000, TimeUnit.MILLISECONDS);
}
return Command.CONTINUE;
}
......@@ -840,7 +849,7 @@ public class LinkDiscoveryManager
// It's probably overkill to send LLDP from all switches, but we don't
// know which switches might be connected to the new switch.
// Need to optimize when supporting a large number of switches.
sendLLDPs();
sendLLDPTask.reschedule(1000, TimeUnit.MILLISECONDS);
// Update event history
evHistTopoSwitch(sw, EvAction.SWITCH_CONNECTED, "None");
}
......@@ -1343,7 +1352,8 @@ public class LinkDiscoveryManager
this.updates = new LinkedBlockingQueue<LDUpdate>();
this.links = new HashMap<LinkTuple, LinkInfo>();
this.portLinks = new HashMap<SwitchPortTuple, Set<LinkTuple>>();
this.suppressLLDPs = new HashSet<SwitchPortTuple>();
this.suppressLLDPs =
Collections.synchronizedSet(new HashSet<SwitchPortTuple>());
this.portBroadcastDomainLinks = new HashMap<SwitchPortTuple, Set<LinkTuple>>();
this.switchLinks = new HashMap<IOFSwitch, Set<LinkTuple>>();
this.evHistTopologySwitch =
......@@ -1359,8 +1369,7 @@ public class LinkDiscoveryManager
// Create our storage tables
storageSource.createTable(LINK_TABLE_NAME, null);
storageSource.setTablePrimaryKeyName(LINK_TABLE_NAME, LINK_ID);
storageSource.createTable(LINK_TABLE_NAME, null);
storageSource.setTablePrimaryKeyName(LINK_TABLE_NAME, LINK_ID);
storageSource.deleteMatchingRows(LINK_TABLE_NAME, null);
// Register for storage updates for the switch table
try {
storageSource.addListener(SWITCH_CONFIG_TABLE_NAME, this);
......@@ -1370,29 +1379,28 @@ public class LinkDiscoveryManager
ScheduledExecutorService ses = threadPool.getScheduledExecutor();
// Setup sending out LLDPs
Runnable lldpSendTimer = new Runnable() {
@Override
public void run() {
try {
sendLLDPs();
sendLLDPTask = new SingletonTask(ses, new Runnable() {
@Override
public void run() {
try {
sendLLDPs();
if (!shuttingDown) {
sendLLDPTask.reschedule(lldpFrequency,
TimeUnit.MILLISECONDS);
}
} catch (StorageException e) {
log.error("Storage exception in LLDP send timer; " +
"terminating process", e);
floodlightProvider.terminate();
} catch (Exception e) {
log.error("Exception in LLDP send timer", e);
}
}
});
if (!shuttingDown) {
ScheduledExecutorService ses =
threadPool.getScheduledExecutor();
ses.schedule(this, lldpFrequency,
TimeUnit.MILLISECONDS);
}
} catch (StorageException e) {
log.error("Storage exception in LLDP send timer; " +
"terminating process", e);
floodlightProvider.terminate();
} catch (Exception e) {
log.error("Exception in LLDP send timer", e);
}
}
};
ses.schedule(lldpSendTimer, 1000, TimeUnit.MILLISECONDS);
// Setup sending out LLDPs
sendLLDPTask.reschedule(1000, TimeUnit.MILLISECONDS);
Runnable timeoutLinksTimer = new Runnable() {
@Override
......
......@@ -20,6 +20,8 @@ package net.floodlightcontroller.routing;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
......@@ -39,6 +41,7 @@ import net.floodlightcontroller.routing.IRoutingDecision;
import net.floodlightcontroller.routing.Link;
import net.floodlightcontroller.routing.Route;
import net.floodlightcontroller.topology.ITopologyService;
import net.floodlightcontroller.util.TimedCache;
import org.openflow.protocol.OFFlowMod;
import org.openflow.protocol.OFMatch;
......@@ -67,6 +70,11 @@ public abstract class ForwardingBase implements
protected IRoutingService routingEngine;
protected ITopologyService topology;
protected ICounterStoreService counterStore;
// for broadcast loop suppression
public final int prime = 2633; // for hash calculation
public TimedCache<Long> broadcastCache =
new TimedCache<Long>(100, 5*1000); // 5 seconds interval;
// flow-mod - for use in the cookie
public static final int FORWARDING_APP_ID = 2; // TODO: This must be managed
......@@ -368,6 +376,87 @@ public abstract class ForwardingBase implements
}
}
/**
* Write packetout message to sw with output actions to one or more
* output ports with inPort/outPorts passed in.
* Note that the packet in could be from a different switch.
* @param pi
* @param sw
* @param inPort
* @param ports
* @param cntx
*/
public void PacketOutMultiPort(OFPacketIn pi,
IOFSwitch sw,
short inPort,
HashSet<Integer> outPorts,
FloodlightContext cntx) {
//setting actions
List<OFAction> actions = new ArrayList<OFAction>();
Iterator<Integer> j = outPorts.iterator();
while (j.hasNext())
{
actions.add(new OFActionOutput(j.next().shortValue(),
(short) 0));
}
OFPacketOut po =
(OFPacketOut) floodlightProvider.getOFMessageFactory().
getMessage(OFType.PACKET_OUT);
po.setActions(actions);
po.setActionsLength((short) (OFActionOutput.MINIMUM_LENGTH *
outPorts.size()));
// set buffer-id to BUFFER_ID_NONE, and set in-port to OFPP_NONE
po.setBufferId(OFPacketOut.BUFFER_ID_NONE);
po.setInPort(inPort);
// data (note buffer_id is always BUFFER_ID_NONE) and length
short poLength = (short)(po.getActionsLength() +
OFPacketOut.MINIMUM_LENGTH);
byte[] packetData = pi.getPacketData();
poLength += packetData.length;
po.setPacketData(packetData);
po.setLength(poLength);
try {
counterStore.updatePktOutFMCounterStore(sw, po);
if (log.isTraceEnabled()) {
log.trace("write broadcast packet on switch-id={} " +
"interaces={} packet-in={} packet-out={}",
new Object[] {sw.getId(), outPorts, pi, po});
}
sw.write(po, cntx);
} catch (IOException e) {
log.error("Failure writing packet out", e);
}
}
protected boolean isInBroadcastCache(IOFSwitch sw, OFPacketIn pi,
FloodlightContext cntx) {
// Get the cluster id of the switch.
// Get the hash of the Ethernet packet.
if (sw == null) return true;
Ethernet eth =
IFloodlightProviderService.bcStore.get(cntx,
IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
Long broadcastHash;
broadcastHash = topology.getL2DomainId(sw.getId()) * prime
+ eth.hashCode();
if (broadcastCache.update(broadcastHash)) {
sw.updateBroadcastCache(broadcastHash, pi.getInPort());
return true;
} else {
return false;
}
}
public static boolean
blockHost(IFloodlightProviderService floodlightProvider,
SwitchPort sw_tup, long host_mac,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment