/*
* Copyright 2016 christopher.metter.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.uniwuerzburg.info3.ofcprobe.vswitch.connection.flowtable;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import org.openflow.protocol.OFMatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.uniwuerzburg.info3.ofcprobe.util.OFMatsch;
import de.uniwuerzburg.info3.ofcprobe.util.Util;
import de.uniwuerzburg.info3.ofcprobe.vswitch.main.config.Config;
/**
* The FlowTable Representation for a ofSwitch
*
* @author Christopher Metter(christopher.metter@informatik.uni-wuerzburg.de)
*
*/
public class OFFlowTable {
/**
* logger
*/
private static final Logger logger = LoggerFactory.getLogger(OFFlowTable.class);
/**
* The Flow Table
*/
private TreeMap<OFMatsch, OFFlowTableEntry> flow_table;
/**
* Max Flow Entries
*/
private int maxSize;
/**
* The Dpid
*/
private String dpid;
/**
* The Comparator for the FlowTable! TODO: FIX DIRTY HACK!
*
* @author Christopher
* Metter(christopher.metter@informatik.uni-wuerzburg.de)
*
*/
class flowTableComp implements Comparator<OFMatsch> {
@Override
public int compare(OFMatsch o1, OFMatsch o2) {
if (Util.equalsFlow(o1, o2) || Util.equalsFlow(o2, o1)) {
return 0;
}
if (o1.subsumes(o2)) {
return 1;
}
if (o2.subsumes(o1)) {
return -1;
}
return o1.toString().compareTo(o2.toString());
// return 1;
}
}
/**
* Constructor
*
* @param config
*/
public OFFlowTable(Config config) {
NumberFormat dpidFormatter = new DecimalFormat("#000");
this.dpid = dpidFormatter.format(config.getSwitchConfig().getDpid());
this.maxSize = config.getSwitchConfig().getFlowTableSize();
this.flow_table = new TreeMap<OFMatsch, OFFlowTableEntry>(new flowTableComp());
}
// Vor = Zuerst
// Weniger WildCards vor mehjr WildCards
// GleichvieleWildCards --> Unterscheidung durch Prioritaeten
// OFMatch1 subsumes(match2) -> True -> match1 allgemeiner match2 --> match2
// braucht nicht geaddet werden
/**
* Insert Flow
*
* @param match the Match
* @param tableEntry the TableEntries
*/
public void insert(OFMatch match, OFFlowTableEntry tableEntry) {
// logger.info("[Switch#{}]: insert({}, {})", this.dpid, match, tableEntry);
OFMatsch matsch = new OFMatsch(match);
// if (this.flow_table.containsKey(matsch)) {
// this.flow_table.remove(matsch);
// }
this.flow_table.put(matsch, tableEntry);
// logger.trace("[Switch#{}]: Flow-Table: {}", this.flow_table.toString());
// System.err.println(this.dpid + " has " +this.flow_table.size() + " flows stored");
}
/**
* Get Matching Flows
*
* @param match Flow to Match
* @param strictFlag strict matching? -> See OFSpec v1.0
* @return Map of Matching Flows
*/
public Map<OFMatch, OFFlowTableEntry> getMatchingFlows(OFMatch match, boolean strictFlag) {
logger.trace("[Switch#{}]: getMatchingFlows({}, {})", this.dpid, match, strictFlag);
Iterator<Map.Entry<OFMatsch, OFFlowTableEntry>> iter = this.flow_table.entrySet().iterator();
Map<OFMatch, OFFlowTableEntry> output = new HashMap<OFMatch, OFFlowTableEntry>();
OFMatsch matsch = new OFMatsch(match);
while (iter.hasNext()) {
Map.Entry<OFMatsch, OFFlowTableEntry> entry = iter.next();
OFMatsch entryMatch = entry.getKey();
if (strictFlag) {
if (Util.equalsFlow(entryMatch, matsch)) {
output.put(entryMatch, entry.getValue());
}
} else {
if (entryMatch.subsumes(matsch) || matsch.subsumes(entryMatch) || Util.equalsFlow(entryMatch, matsch)) {
output.put(entryMatch, entry.getValue());
}
}
}
logger.trace("[Switch#{}]: getMatchingFlowsOutput: {}", this.dpid, output.toString());
return output;
}
/**
* Modifiy Matching Flows
*
* @param modifiedFlows Map of Flows to modify
*/
public void modifyMatchingFlows(Map<OFMatch, OFFlowTableEntry> modifiedFlows) {
logger.trace("[Switch#{}]: modifyMatchingFlows({})", this.dpid, modifiedFlows.toString());
Iterator<Map.Entry<OFMatch, OFFlowTableEntry>> matchIter = modifiedFlows.entrySet().iterator();
while (matchIter.hasNext()) {
Entry<OFMatch, OFFlowTableEntry> entry = matchIter.next();
this.flow_table.put((OFMatsch) entry.getKey(), entry.getValue());
}
logger.trace("[Switch#{}]: modifyMatchingFlows-Result: {}", this.dpid, this.flow_table.toString());
}
/**
* Remove Matching Flows
*
* @param match the match
* @param strictFlag strictFlag -> OFSpec v1.0
* @param sendFlowRemoved send FlowRemovedMsg?
* @return List of Removed Flows if sendFlowRemoved = true
*/
public List<OFMatch> removeMatchingFlows(OFMatch match, boolean strictFlag, boolean sendFlowRemoved) {
sendFlowRemoved = true;
logger.trace("[Switch#{}]: removeMatchingFlows({}, {}, {}", this.dpid, match, strictFlag, sendFlowRemoved);
List<OFMatch> output = new ArrayList<OFMatch>();
// check if match is a empty one -> would mean to clear flowtable
// but doesnt work like this :(
// empty does match for everything
// OFMatch empty = new OFMatch();
// if (Util.equalsFlow(match, empty)) {
// System.err.println("what? " + match.toString() + ";" + empty.toString());
// if (sendFlowRemoved) {
// output.addAll(this.flow_table.keySet());
// }
// // OFMatch is empty, so every FLOW in FLOW_DB has to be deleted
// this.flow_table.clear();
// }
Iterator<Map.Entry<OFMatsch, OFFlowTableEntry>> iter = this.flow_table.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<OFMatsch, OFFlowTableEntry> entry = iter.next();
OFMatch entryMatch = entry.getKey();
if (strictFlag) {
if (Util.equalsFlow(entryMatch, match)) {
if (sendFlowRemoved) {
output.add(entryMatch);
}
iter.remove();
}
} else {
if (entryMatch.subsumes(match) || match.subsumes(entryMatch) || Util.equalsFlow(match, entryMatch)) {
if (sendFlowRemoved) {
output.add(entryMatch);
}
iter.remove();
}
}
}
logger.trace("[Switch#{}]: removeMatchingFlows-Result: {} - Output: {}", this.dpid, this.flow_table.toString(), output.toString());
return output;
}
/**
* Get specific Flow Table Entry
*
* @param match the flow
* @param strictFlag the strictFlag -> OFSpec v1.0
* @return the Entry
*/
public OFFlowTableEntry getEntry(OFMatch match, boolean strictFlag) {
return this.flow_table.get(match);
}
/**
* Remove specific Entry
*
* @param match the Match
* @return true if remove action was successfull
*/
public boolean removeEntry(OFMatch match) {
return false;
}
/**
* Does FlowTable contain Match?
*
* @param match the Match
* @return true if Map containsKey(OFMatch)
*/
public boolean containsMatch(OFMatch match) {
logger.trace("[Switch#{}]: containsMatch({})", this.dpid, match.toString());
return this.flow_table.containsKey(new OFMatsch(match));
}
/**
* Clear FlowTable
*/
public void clear() {
logger.trace("[Switch#{}]: Flow-Table cleared()", this.dpid);
this.flow_table.clear();
}
/**
* Maximum FlowTable Size
*
* @return the flow table size
*/
public int size() {
logger.trace("[Switch#{}]: Flow-Table Size: {}", this.dpid, this.flow_table.size());
return this.flow_table.size();
}
/**
* Is the Flow Table Full?
*
* @return table.size >= maxSize?; Currently always false!
*/
public boolean isFull() {
// logger.trace("[Switch#{}]: Flow-Table isFull()-Output: {}", this.dpid, this.flow_table.size() >= this.maxSize);
// return this.flow_table.size() >= this.maxSize;
return false;
}
/**
* the switch must check that there are no conflicting entries with the same
* priority If there is one, the flow mod fails and an error code is
* returned.
*
* @param match
* @return
*/
public boolean checkOverlap(OFMatch match) {
// TODO Auto-generated method stub
return false;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((flow_table == null) ? 0 : flow_table.hashCode());
result = prime * result + maxSize;
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
OFFlowTable other = (OFFlowTable) obj;
if (flow_table == null) {
if (other.flow_table != null) {
return false;
}
} else if (!flow_table.equals(other.flow_table)) {
return false;
}
if (maxSize != other.maxSize) {
return false;
}
return true;
}
/**
* Max Size
*
* @return the maxSize
*/
public int capacity() {
return this.maxSize;
}
}