alshabib

implementing flowremoved handling

package org.onlab.onos.of.controller.impl;
import static org.onlab.util.Tools.namedThreads;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
......@@ -13,6 +19,7 @@ import org.apache.felix.scr.annotations.Service;
import org.onlab.onos.of.controller.DefaultOpenFlowPacketContext;
import org.onlab.onos.of.controller.Dpid;
import org.onlab.onos.of.controller.OpenFlowController;
import org.onlab.onos.of.controller.OpenFlowEventListener;
import org.onlab.onos.of.controller.OpenFlowPacketContext;
import org.onlab.onos.of.controller.OpenFlowSwitch;
import org.onlab.onos.of.controller.OpenFlowSwitchListener;
......@@ -22,10 +29,12 @@ import org.onlab.onos.of.controller.driver.OpenFlowAgent;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFPacketIn;
import org.projectfloodlight.openflow.protocol.OFPortStatus;
import org.projectfloodlight.openflow.protocol.OFType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
@Component(immediate = true)
......@@ -35,6 +44,10 @@ public class OpenFlowControllerImpl implements OpenFlowController {
private static final Logger log =
LoggerFactory.getLogger(OpenFlowControllerImpl.class);
private final ExecutorService executor = Executors.newFixedThreadPool(16,
namedThreads("of-event-dispatch-%d"));
protected ConcurrentHashMap<Dpid, OpenFlowSwitch> connectedSwitches =
new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
protected ConcurrentHashMap<Dpid, OpenFlowSwitch> activeMasterSwitches =
......@@ -43,11 +56,12 @@ public class OpenFlowControllerImpl implements OpenFlowController {
new ConcurrentHashMap<Dpid, OpenFlowSwitch>();
protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
protected Set<OpenFlowSwitchListener> ofEventListener = new HashSet<>();
protected Set<OpenFlowSwitchListener> ofSwitchListener = new HashSet<>();
protected Multimap<Integer, PacketListener> ofPacketListener =
ArrayListMultimap.create();
protected Map<OFType, List<OpenFlowEventListener>> ofEventListener = Maps.newHashMap();
private final Controller ctrl = new Controller();
......@@ -93,14 +107,14 @@ public class OpenFlowControllerImpl implements OpenFlowController {
@Override
public void addListener(OpenFlowSwitchListener listener) {
if (!ofEventListener.contains(listener)) {
this.ofEventListener.add(listener);
if (!ofSwitchListener.contains(listener)) {
this.ofSwitchListener.add(listener);
}
}
@Override
public void removeListener(OpenFlowSwitchListener listener) {
this.ofEventListener.remove(listener);
this.ofSwitchListener.remove(listener);
}
@Override
......@@ -122,7 +136,7 @@ public class OpenFlowControllerImpl implements OpenFlowController {
public void processPacket(Dpid dpid, OFMessage msg) {
switch (msg.getType()) {
case PORT_STATUS:
for (OpenFlowSwitchListener l : ofEventListener) {
for (OpenFlowSwitchListener l : ofSwitchListener) {
l.portChanged(dpid, (OFPortStatus) msg);
}
break;
......@@ -134,6 +148,12 @@ public class OpenFlowControllerImpl implements OpenFlowController {
p.handlePacket(pktCtx);
}
break;
case FLOW_REMOVED:
case ERROR:
case STATS_REPLY:
case BARRIER_REPLY:
executor.submit(new OFMessageHandler(dpid, msg));
break;
default:
log.warn("Handling message type {} not yet implemented {}",
msg.getType(), msg);
......@@ -164,7 +184,7 @@ public class OpenFlowControllerImpl implements OpenFlowController {
} else {
log.error("Added switch {}", dpid);
connectedSwitches.put(dpid, sw);
for (OpenFlowSwitchListener l : ofEventListener) {
for (OpenFlowSwitchListener l : ofSwitchListener) {
l.switchAdded(dpid);
}
return true;
......@@ -277,7 +297,7 @@ public class OpenFlowControllerImpl implements OpenFlowController {
if (sw == null) {
sw = activeEqualSwitches.remove(dpid);
}
for (OpenFlowSwitchListener l : ofEventListener) {
for (OpenFlowSwitchListener l : ofSwitchListener) {
l.switchRemoved(dpid);
}
}
......@@ -288,5 +308,26 @@ public class OpenFlowControllerImpl implements OpenFlowController {
}
}
private final class OFMessageHandler implements Runnable {
private final OFMessage msg;
private final Dpid dpid;
public OFMessageHandler(Dpid dpid, OFMessage msg) {
this.msg = msg;
this.dpid = dpid;
}
@Override
public void run() {
List<OpenFlowEventListener> listeners =
ofEventListener.get(OFType.FLOW_REMOVED);
for (OpenFlowEventListener listener : listeners) {
listener.handleMessage(dpid, msg);
}
}
}
}
......
......@@ -2,58 +2,29 @@ package org.onlab.onos.provider.of.flow.impl;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.flow.DefaultFlowRule;
import org.onlab.onos.net.flow.FlowEntry;
import org.onlab.onos.net.flow.FlowRule;
import org.onlab.onos.net.flow.FlowRuleProvider;
import org.onlab.onos.net.flow.FlowRuleProviderRegistry;
import org.onlab.onos.net.flow.FlowRuleProviderService;
import org.onlab.onos.net.flow.criteria.Criteria.EthCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.EthTypeCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.IPCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.IPProtocolCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.PortCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.VlanIdCriterion;
import org.onlab.onos.net.flow.criteria.Criteria.VlanPcpCriterion;
import org.onlab.onos.net.flow.criteria.Criterion;
import org.onlab.onos.net.flow.instructions.Instruction;
import org.onlab.onos.net.flow.instructions.Instructions.OutputInstruction;
import org.onlab.onos.net.flow.instructions.L2ModificationInstruction;
import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
import org.onlab.onos.net.flow.instructions.L3ModificationInstruction;
import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
import org.onlab.onos.net.provider.AbstractProvider;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.onos.net.topology.TopologyService;
import org.onlab.onos.of.controller.Dpid;
import org.onlab.onos.of.controller.OpenFlowController;
import org.onlab.onos.of.controller.OpenFlowEventListener;
import org.onlab.onos.of.controller.OpenFlowSwitch;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFFlowMod;
import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
import org.projectfloodlight.openflow.protocol.action.OFAction;
import org.projectfloodlight.openflow.protocol.match.Match;
import org.projectfloodlight.openflow.protocol.match.MatchField;
import org.projectfloodlight.openflow.types.EthType;
import org.projectfloodlight.openflow.types.IPv4Address;
import org.projectfloodlight.openflow.types.IpProtocol;
import org.projectfloodlight.openflow.types.MacAddress;
import org.projectfloodlight.openflow.types.OFBufferId;
import org.projectfloodlight.openflow.types.OFPort;
import org.projectfloodlight.openflow.types.OFVlanVidMatch;
import org.projectfloodlight.openflow.types.VlanPcp;
import org.projectfloodlight.openflow.types.VlanVid;
import org.onlab.onos.of.controller.OpenFlowSwitchListener;
import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFPortStatus;
import org.slf4j.Logger;
/**
......@@ -105,168 +76,10 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
private void applyRule(FlowRule flowRule) {
OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
Match match = buildMatch(flowRule.selector().criteria(), sw.factory());
List<OFAction> actions =
buildActions(flowRule.treatment().instructions(), sw.factory());
//TODO: what to do without bufferid? do we assume that there will be a pktout as well?
OFFlowMod fm = sw.factory().buildFlowModify()
.setBufferId(OFBufferId.NO_BUFFER)
.setActions(actions)
.setMatch(match)
.setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
.setIdleTimeout(10)
.setHardTimeout(10)
.setPriority(flowRule.priority())
.build();
sw.sendMsg(fm);
}
private List<OFAction> buildActions(List<Instruction> instructions, OFFactory factory) {
List<OFAction> acts = new LinkedList<>();
for (Instruction i : instructions) {
switch (i.type()) {
case DROP:
log.warn("Saw drop action; assigning drop action");
return new LinkedList<>();
case L2MODIFICATION:
acts.add(buildL2Modification(i, factory));
case L3MODIFICATION:
acts.add(buildL3Modification(i, factory));
case OUTPUT:
OutputInstruction out = (OutputInstruction) i;
acts.add(factory.actions().buildOutput().setPort(
OFPort.of((int) out.port().toLong())).build());
break;
case GROUP:
default:
log.warn("Instruction type {} not yet implemented.", i.type());
}
}
return acts;
sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowMod());
}
private OFAction buildL3Modification(Instruction i, OFFactory factory) {
L3ModificationInstruction l3m = (L3ModificationInstruction) i;
ModIPInstruction ip;
switch (l3m.subtype()) {
case L3_DST:
ip = (ModIPInstruction) i;
return factory.actions().setNwDst(IPv4Address.of(ip.ip().toInt()));
case L3_SRC:
ip = (ModIPInstruction) i;
return factory.actions().setNwSrc(IPv4Address.of(ip.ip().toInt()));
default:
log.warn("Unimplemented action type {}.", l3m.subtype());
break;
}
return null;
}
private OFAction buildL2Modification(Instruction i, OFFactory factory) {
L2ModificationInstruction l2m = (L2ModificationInstruction) i;
ModEtherInstruction eth;
switch (l2m.subtype()) {
case L2_DST:
eth = (ModEtherInstruction) l2m;
return factory.actions().setDlDst(MacAddress.of(eth.mac().toLong()));
case L2_SRC:
eth = (ModEtherInstruction) l2m;
return factory.actions().setDlSrc(MacAddress.of(eth.mac().toLong()));
case VLAN_ID:
ModVlanIdInstruction vlanId = (ModVlanIdInstruction) l2m;
return factory.actions().setVlanVid(VlanVid.ofVlan(vlanId.vlanId.toShort()));
case VLAN_PCP:
ModVlanPcpInstruction vlanPcp = (ModVlanPcpInstruction) l2m;
return factory.actions().setVlanPcp(VlanPcp.of(vlanPcp.vlanPcp()));
default:
log.warn("Unimplemented action type {}.", l2m.subtype());
break;
}
return null;
}
private Match buildMatch(List<Criterion> criteria, OFFactory factory) {
Match.Builder mBuilder = factory.buildMatch();
EthCriterion eth;
IPCriterion ip;
for (Criterion c : criteria) {
switch (c.type()) {
case IN_PORT:
PortCriterion inport = (PortCriterion) c;
mBuilder.setExact(MatchField.IN_PORT, OFPort.of((int) inport.port().toLong()));
break;
case ETH_SRC:
eth = (EthCriterion) c;
mBuilder.setExact(MatchField.ETH_SRC, MacAddress.of(eth.mac().toLong()));
break;
case ETH_DST:
eth = (EthCriterion) c;
mBuilder.setExact(MatchField.ETH_DST, MacAddress.of(eth.mac().toLong()));
break;
case ETH_TYPE:
EthTypeCriterion ethType = (EthTypeCriterion) c;
mBuilder.setExact(MatchField.ETH_TYPE, EthType.of(ethType.ethType()));
break;
case IPV4_DST:
ip = (IPCriterion) c;
mBuilder.setExact(MatchField.IPV4_DST, IPv4Address.of(ip.ip().toInt()));
break;
case IPV4_SRC:
ip = (IPCriterion) c;
mBuilder.setExact(MatchField.IPV4_SRC, IPv4Address.of(ip.ip().toInt()));
break;
case IP_PROTO:
IPProtocolCriterion p = (IPProtocolCriterion) c;
mBuilder.setExact(MatchField.IP_PROTO, IpProtocol.of(p.protocol()));
break;
case VLAN_PCP:
VlanPcpCriterion vpcp = (VlanPcpCriterion) c;
mBuilder.setExact(MatchField.VLAN_PCP, VlanPcp.of(vpcp.priority()));
break;
case VLAN_VID:
VlanIdCriterion vid = (VlanIdCriterion) c;
mBuilder.setExact(MatchField.VLAN_VID,
OFVlanVidMatch.ofVlanVid(VlanVid.ofVlan(vid.vlanId().toShort())));
break;
case ARP_OP:
case ARP_SHA:
case ARP_SPA:
case ARP_THA:
case ARP_TPA:
case ICMPV4_CODE:
case ICMPV4_TYPE:
case ICMPV6_CODE:
case ICMPV6_TYPE:
case IN_PHY_PORT:
case IPV6_DST:
case IPV6_EXTHDR:
case IPV6_FLABEL:
case IPV6_ND_SLL:
case IPV6_ND_TARGET:
case IPV6_ND_TLL:
case IPV6_SRC:
case IP_DSCP:
case IP_ECN:
case METADATA:
case MPLS_BOS:
case MPLS_LABEL:
case MPLS_TC:
case PBB_ISID:
case SCTP_DST:
case SCTP_SRC:
case TCP_DST:
case TCP_SRC:
case TUNNEL_ID:
case UDP_DST:
case UDP_SRC:
default:
log.warn("Action type {} not yet implemented.", c.type());
}
}
return mBuilder.build();
}
@Override
public void removeFlowRule(FlowRule... flowRules) {
......@@ -283,6 +96,45 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
//TODO: InternalFlowRuleProvider listening to stats and error and flowremoved.
// possibly barriers as well. May not be internal at all...
private class InternalFlowProvider
implements OpenFlowSwitchListener, OpenFlowEventListener {
@Override
public void switchAdded(Dpid dpid) {
}
@Override
public void switchRemoved(Dpid dpid) {
}
@Override
public void portChanged(Dpid dpid, OFPortStatus status) {
//TODO: Decide whether to evict flows internal store.
}
@Override
public void handleMessage(Dpid dpid, OFMessage msg) {
switch (msg.getType()) {
case FLOW_REMOVED:
OFFlowRemoved removed = (OFFlowRemoved) msg;
FlowRule fr = new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)), null, null);
providerService.flowRemoved(fr);
break;
case STATS_REPLY:
case BARRIER_REPLY:
case ERROR:
default:
log.warn("Unhandled message type: {}", msg.getType());
}
}
}
}
......
......@@ -46,7 +46,7 @@ public class OpenFlowCorePacketContext extends DefaultPacketContext {
private void sendBufferedPacket() {
List<Instruction> ins = treatmentBuilder().build().instructions();
OFPort p = null;
//TODO: support arbitrary list of treatments
//TODO: support arbitrary list of treatments must be supported in ofPacketContext
for (Instruction i : ins) {
if (i.type() == Type.OUTPUT) {
p = buildPort(((OutputInstruction) i).port());
......
......@@ -226,6 +226,10 @@ public final class IpAddress {
return new IpAddress(version, host, netmask);
}
public boolean isMasked() {
return mask() != 0;
}
@Override
public int hashCode() {
final int prime = 31;
......