Commit fbca53f6 authored by Ryan Izard's avatar Ryan Izard
Browse files

Merge pull request #609 from rizard/master

Add OF-DPA helper functions
parents b5b1648d eaad2b6f
Loading
Loading
Loading
Loading
+0 −147
Original line number Diff line number Diff line
@@ -3,7 +3,6 @@ package net.floodlightcontroller.core.internal;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -23,13 +22,11 @@ import net.floodlightcontroller.core.IOFSwitchBackend;
import net.floodlightcontroller.core.PortChangeEvent;
import net.floodlightcontroller.core.SwitchDescription;
import net.floodlightcontroller.core.internal.OFSwitchAppHandshakePlugin.PluginResultType;
import net.floodlightcontroller.util.OFDPAUtils;

import org.projectfloodlight.openflow.protocol.OFActionType;
import org.projectfloodlight.openflow.protocol.OFBadRequestCode;
import org.projectfloodlight.openflow.protocol.OFBarrierReply;
import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
import org.projectfloodlight.openflow.protocol.OFBucket;
import org.projectfloodlight.openflow.protocol.OFControllerRole;
import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFDescStatsRequest;
@@ -46,7 +43,6 @@ import org.projectfloodlight.openflow.protocol.OFFlowModFailedCode;
import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
import org.projectfloodlight.openflow.protocol.OFGetConfigReply;
import org.projectfloodlight.openflow.protocol.OFGetConfigRequest;
import org.projectfloodlight.openflow.protocol.OFGroupAdd;
import org.projectfloodlight.openflow.protocol.OFGroupDelete;
import org.projectfloodlight.openflow.protocol.OFGroupType;
import org.projectfloodlight.openflow.protocol.OFMessage;
@@ -54,7 +50,6 @@ import org.projectfloodlight.openflow.protocol.OFNiciraControllerRole;
import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleReply;
import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleRequest;
import org.projectfloodlight.openflow.protocol.OFPacketIn;
import org.projectfloodlight.openflow.protocol.OFPortDesc;
import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFPortStatus;
import org.projectfloodlight.openflow.protocol.OFQueueGetConfigReply;
@@ -73,18 +68,12 @@ import org.projectfloodlight.openflow.protocol.action.OFAction;
import org.projectfloodlight.openflow.protocol.actionid.OFActionId;
import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
import org.projectfloodlight.openflow.protocol.match.MatchField;
import org.projectfloodlight.openflow.types.DatapathId;
import org.projectfloodlight.openflow.types.OFAuxId;
import org.projectfloodlight.openflow.types.OFBufferId;
import org.projectfloodlight.openflow.types.OFGroup;
import org.projectfloodlight.openflow.types.OFPort;
import org.projectfloodlight.openflow.types.OFVlanVidMatch;
import org.projectfloodlight.openflow.types.TableId;
import org.projectfloodlight.openflow.types.U16;
import org.projectfloodlight.openflow.types.U64;
import org.projectfloodlight.openflow.types.VlanVid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@@ -555,142 +544,6 @@ public class OFSwitchHandshakeHandler implements IOFConnectionListener {
		}
	}

	private void addBroadcomOFDPAFlows() {
		/*
		 * By default, we'll assume everyone's on the same VLAN,
		 * and all switch ports are configured as access ports.
		 * As such, all packets on the wire will be untagged
		 * and will only be tagged internally in the switch for 
		 * pipeline processing.
		 * 
		 * If you would like to configure trunks on switches, then
		 * each switch will need to be configured specifically, as
		 * we won't be able to automatically handle such a topology.
		 * 
		 * Ingress port table (0)     = empty --> default to VLAN table
		 * VLAN table (10)            = match untagged, apply internal tag, goto termination MAC
		 * Termination MAC table (20) = match vlan tag and dst MAC, goto bridging table (default miss-->bridging)
		 * 							  	match only vlan tag, goto controller (DLF or Dest Lookup Failure)
		 * Bridging table (50)        = default send to policy ACL table
		 * Policy ACL table (60)      = priority=0 go to controller
		 *                              write action group of forwarding decision
		 * Group tables
		 *   One per interface per VLAN
		 *   One per VLAN (for flooding)
		 *   
		 *  TABLE_INGRESS = 0
		 *  TABLE_VLAN = 10
		 *  TABLE_MAC = 20
		 *  TABLE_UNICAST = 30
		 *  TABLE_MULTICAST = 40
		 *  TABLE_BRIDGING = 50
		 *  TABLE_ACL = 60
		 */

		/*
		 * Add flow to match all untagged packets from all ports in VLAN table
		 */
		List<OFAction> al = new ArrayList<OFAction>(1);
		/* al.add(factory.actions().pushVlan(EthType.IPv4)); might not need this */
		al.add(factory.actions().setVlanVid(VlanVid.ofVlan(1))); /* we'll use 1 internally, just because */

		List<OFInstruction> il = new ArrayList<OFInstruction>(2);
		il.add(factory.instructions().gotoTable(TableId.of(20))); /* 20 is the termination MAC table */
		il.add(factory.instructions().applyActions(al));
		OFFlowAdd fa = factory.buildFlowAdd()
				.setTableId(TableId.of(10))
				.setOutPort(OFPort.ANY)
				.setBufferId(OFBufferId.NO_BUFFER)
				.setCookie(U64.ZERO)
				.setMatch(factory.buildMatch()
						.setExact(MatchField.VLAN_VID, OFVlanVidMatch.UNTAGGED) /* this flow handles untagged */
						/* do we have to match on the in port here? */
						.build()
						)
						.setInstructions(il)
						.setPriority(1000)
						.build();
		sw.write(fa);

		/*
		 * The termination MAC flow table must proactively forward to controller specific dst MACs,
		 * so we need to wait to do wildcarded dst MACs in bridging table upon a miss. Send to bridging
		 * table by default here.
		 */

		/*
		 * Add flow to match all vlan=1 packets to forward to controller in bridging table (DLF).
		 * Default is to send to policy ACL if this does not match.
		 */
		al = new ArrayList<OFAction>(1);
		al.add(factory.actions().output(OFPort.CONTROLLER, 0xffFFffFF));

		il = new ArrayList<OFInstruction>(1);
		il.add(factory.instructions().applyActions(al));
		fa = factory.buildFlowAdd()
				.setTableId(TableId.of(50))
				.setOutPort(OFPort.ANY)
				.setBufferId(OFBufferId.NO_BUFFER)
				.setCookie(U64.ZERO)
				.setMatch(factory.buildMatch()
						.setExact(MatchField.VLAN_VID, OFVlanVidMatch.ofVlan(1)) /* this flow handles recently-tagged VLAN=1 */
						.build()
						)
						.setInstructions(il) 
						.setPriority(1)
						.build();
		sw.write(fa);

		/*
		 * Lastly, add a group for flooding and for each port.
		 * This group is only for VLAN=1.
		 * 
		 * The flood group has buckets with goto group actions
		 * for each port's individual L2 group for VLAN=1.
		 * 
		 * This means we must first add the individual groups.
		 */
		ArrayList<OFBucket> buckets = new ArrayList<OFBucket>();
		for (OFPortDesc pd : this.sw.getPorts()) {
			OFPort p = pd.getPortNo();
			if ((p.getShortPortNumber() & 0xFF00) == 0) { /* TODO Is this correct for special ports? */
				OFGroupAdd ga = factory.buildGroupAdd()
						.setGroupType(OFGroupType.INDIRECT)
						.setBuckets(Collections.singletonList(factory.buildBucket()
								.setActions(
										Collections.singletonList((OFAction) factory.actions().buildOutput()
												.setMaxLen(0xffFFffFF)
												.setPort(p)
												.build()))
												.build()))
												.setGroup(OFDPAUtils.GroupIds.createL2Interface(p, VlanVid.ofVlan(100)))
												.build();
				sw.write(ga);

				/*
				 * Add the port+bucket for creating the FLOOD group below.
				 * All L2_INTERFACE groups in a VLAN should be within a
				 * corresponding L2_FLOOD group of type ALL.
				 */
				buckets.add(factory.buildBucket().setActions(
						Collections.singletonList(
								(OFAction) factory.actions().buildOutput()
								.setMaxLen(0xffFFffFF)
								.setPort(p)
								.build()
								)
						).build());
			}
		}

		OFGroupAdd ga = factory.buildGroupAdd()
				.setGroupType(OFGroupType.ALL)
				.setBuckets(buckets)
				.setGroup(OFDPAUtils.GroupIds.createL2Flood(U16.ZERO, VlanVid.ofVlan(100)))
				.build();
		sw.write(ga);
	}

	/**
	 * Default implementation for message handlers in any state.
	 *
+62 −1
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@ import java.util.Set;
import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.IOFSwitchListener;
import net.floodlightcontroller.core.PortChangeType;
import net.floodlightcontroller.core.internal.IOFSwitchService;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.module.FloodlightModuleException;
@@ -49,11 +51,16 @@ import net.floodlightcontroller.routing.IRoutingService;
import net.floodlightcontroller.routing.Route;
import net.floodlightcontroller.topology.ITopologyService;
import net.floodlightcontroller.topology.NodePortTuple;
import net.floodlightcontroller.util.OFDPAUtils;
import net.floodlightcontroller.util.OFPortMode;
import net.floodlightcontroller.util.OFPortModeTuple;

import org.projectfloodlight.openflow.protocol.OFFlowMod;
import org.projectfloodlight.openflow.protocol.OFFlowModCommand;
import org.projectfloodlight.openflow.protocol.OFGroupType;
import org.projectfloodlight.openflow.protocol.OFPacketIn;
import org.projectfloodlight.openflow.protocol.OFPacketOut;
import org.projectfloodlight.openflow.protocol.OFPortDesc;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.protocol.action.OFAction;
import org.projectfloodlight.openflow.protocol.match.Match;
@@ -65,14 +72,16 @@ import org.projectfloodlight.openflow.types.IPv6Address;
import org.projectfloodlight.openflow.types.IpProtocol;
import org.projectfloodlight.openflow.types.MacAddress;
import org.projectfloodlight.openflow.types.OFBufferId;
import org.projectfloodlight.openflow.types.OFGroup;
import org.projectfloodlight.openflow.types.OFPort;
import org.projectfloodlight.openflow.types.OFVlanVidMatch;
import org.projectfloodlight.openflow.types.TableId;
import org.projectfloodlight.openflow.types.U64;
import org.projectfloodlight.openflow.types.VlanVid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Forwarding extends ForwardingBase implements IFloodlightModule {
public class Forwarding extends ForwardingBase implements IFloodlightModule, IOFSwitchListener {
	protected static Logger log = LoggerFactory.getLogger(Forwarding.class);

	@Override
@@ -509,5 +518,57 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule {
	@Override
	public void startUp(FloodlightModuleContext context) {
		super.startUp();
		switchService.addOFSwitchListener(this);
	}

	@Override
	public void switchAdded(DatapathId switchId) {
	}

	@Override
	public void switchRemoved(DatapathId switchId) {		
	}

	@Override
	public void switchActivated(DatapathId switchId) {
		IOFSwitch sw = switchService.getSwitch(switchId);
		if (sw == null) {
			log.warn("Switch {} was activated but had no switch object in the switch service. Perhaps it quickly disconnected", switchId);
			return;
		}
		if (OFDPAUtils.isOFDPASwitch(sw)) {
			sw.write(sw.getOFFactory().buildFlowDelete()
					.setTableId(TableId.ALL)
					.build()
					);
			sw.write(sw.getOFFactory().buildGroupDelete()
					.setGroup(OFGroup.ANY)
					.setGroupType(OFGroupType.ALL)
					.build()
					);
			sw.write(sw.getOFFactory().buildGroupDelete()
					.setGroup(OFGroup.ANY)
					.setGroupType(OFGroupType.INDIRECT)
					.build()
					);
			sw.write(sw.getOFFactory().buildBarrierRequest().build());
			
			List<OFPortModeTuple> portModes = new ArrayList<OFPortModeTuple>();
			for (OFPortDesc p : sw.getPorts()) {
				portModes.add(OFPortModeTuple.of(p.getPortNo(), OFPortMode.ACCESS));
			}
			if (log.isWarnEnabled()) {
				log.warn("For OF-DPA switch {}, initializing VLAN {} on ports {}", new Object[] { switchId, VlanVid.ZERO, portModes});
			}
			OFDPAUtils.addLearningSwitchPrereqs(sw, VlanVid.ZERO, portModes);
		}
	}

	@Override
	public void switchPortChanged(DatapathId switchId, OFPortDesc port, PortChangeType type) {		
	}

	@Override
	public void switchChanged(DatapathId switchId) {
	}
}
+14 −2
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import net.floodlightcontroller.routing.Route;
import net.floodlightcontroller.topology.ITopologyService;
import net.floodlightcontroller.topology.NodePortTuple;
import net.floodlightcontroller.util.MatchUtils;
import net.floodlightcontroller.util.OFDPAUtils;
import net.floodlightcontroller.util.OFMessageDamper;
import net.floodlightcontroller.util.TimedCache;

@@ -263,7 +264,18 @@ public abstract class ForwardingBase implements IOFMessageListener {
							fmb.getMatch().get(MatchField.IN_PORT),
							outPort });
				}
				
				if (OFDPAUtils.isOFDPASwitch(sw)) {
					OFDPAUtils.addLearningSwitchFlow(sw, cookie, 
							FLOWMOD_DEFAULT_PRIORITY, 
							FLOWMOD_DEFAULT_HARD_TIMEOUT,
							FLOWMOD_DEFAULT_IDLE_TIMEOUT,
							fmb.getMatch(), 
							null, // TODO how to determine output VLAN for lookup of L2 interface group
							outPort);
				} else {
					messageDamper.write(sw, fmb.build());
				}

				/* Push the packet out the first hop switch */
				if (sw.getId().equals(pinSwitch) &&
+148 −153

File changed.

Preview size limit exceeded, changes collapsed.

+2 −3
Original line number Diff line number Diff line
@@ -2,13 +2,12 @@ package net.floodlightcontroller.util;

/**
 * Define the different operating modes of a switch
 * port as trunk, access, and both (trunk and access).
 * port as trunk or access.
 * 
 * @author Ryan Izard, ryan.izard@bigswitch.com, rizard@g.clemson.edu
 */

public enum OFPortMode {
	TRUNK,
	ACCESS,
	TRUNK_AND_ACCESS
	ACCESS
}
Loading