/* ONF SampleTap Software License
Copyright ©2014 Open Networking Foundation
This ONF SampleTap software is 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 original
license at http://www.apache.org/licenses/LICENSE-2.0 and also in
the main directory of the source distribution.
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.
End of ONF SampleTap Software License
*/
package org.opendaylight.controller.samples.onftappingapp;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.bson.types.ObjectId;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.WriteResult;
import org.opendaylight.controller.forwardingrulesmanager.FlowEntry;
import org.opendaylight.controller.sal.action.Action;
import org.opendaylight.controller.sal.core.Node;
import org.opendaylight.controller.sal.flowprogrammer.Flow;
import org.opendaylight.controller.sal.match.Match;
import org.opendaylight.controller.samples.onftappingapp.internal.ONFTappingAppImpl;
public class MatchCriteria {
private long referenceCount = 0;
private String objectId = "";
private String name = "";
private boolean enabled = true;
private boolean reflexive;
private int priority;
// Values to match
List<MatchField> matchFieldList = new ArrayList<MatchField>();
private static Logger logger = LoggerFactory.getLogger(ONFTappingAppImpl.class);
public MatchCriteria() {
this.referenceCount = 0;
}
// Copy constructor
public MatchCriteria(MatchCriteria matchCriteria) {
this.objectId = matchCriteria.getObjectId();
this.name = matchCriteria.getName();
this.enabled = matchCriteria.getEnabled();
this.reflexive = matchCriteria.getReflexive();
this.priority = matchCriteria.getPriority();
this.matchFieldList = new ArrayList<MatchField>(matchCriteria.getFields());
}
public MatchCriteria(DBObject matchCriteriaObj) {
this.setName((String) matchCriteriaObj.get("name"));
this.setReferenceCount((long) matchCriteriaObj.get("refCount"));
ObjectId oid = (ObjectId) matchCriteriaObj.get("_id");
this.setObjectId(oid.toString());
this.setEnabled( (Boolean) matchCriteriaObj.get("enabled"));
this.setReflexive((Boolean) matchCriteriaObj.get("reflexive"));
this.setPriority((int) matchCriteriaObj.get("priority"));
BasicDBList mfList = (BasicDBList) matchCriteriaObj.get("matchFields");
BasicDBObject[] mfArray = mfList.toArray(new BasicDBObject[0]);
for(BasicDBObject dbObj : mfArray) {
MatchField matchField = new MatchField();
matchField.setType(dbObj.getString("type"));
matchField.setValue(dbObj.getString("value"));
// Add the match field to the match criteria
this.addMatchField(matchField);
}
}
public long getReferenceCount(){
return this.referenceCount;
}
public void setReferenceCount(final long refCount){
this.referenceCount = refCount;
}
public String getObjectId(){
return this.objectId;
}
public void setObjectId(String objId){
this.objectId = objId;
}
public boolean isReflexive() {
return reflexive;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public boolean getEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean getReflexive() {
return this.reflexive;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public void setReflexive(boolean reflexive1) {
this.reflexive = reflexive1;
}
public List<MatchField> getFields() {
List<MatchField> cloneList = new ArrayList<MatchField>(matchFieldList.size());
Iterator<MatchField> it = matchFieldList.iterator();
while (it.hasNext()) {
MatchField matchField = it.next();
cloneList.add(matchField);
}
return cloneList;
}
// Construct the match criteria fields from a list of MatchField key/value pairs
public void addMatchField(MatchField matchField)
{
logger.info(matchField.toString());
// Copy the match criteria into the map and set the bit mask to indicate it is part of the match
switch(matchField.getType()) {
case MatchField.UNDEFINED:
// Ignored
break;
case MatchField.ETH_TYPE:
case MatchField.IP_PROTO:
case MatchField.IP_TOS:
case MatchField.VLAN_TAG:
case MatchField.SOURCE_IP:
case MatchField.SOURCE_MAC:
case MatchField.DEST_IP:
case MatchField.DEST_MAC:
case MatchField.PROTO_SVC:
case MatchField.PROTO_PORT:
matchFieldList.add(matchField);
break;
default:
logger.warn("Unhandled Match Field Type " + matchField.getType() );
break;
}
}
// Construct the match criteria fields from a list of MatchField key/value pairs
public void setFields(List<MatchField> matchFields) {
Iterator<MatchField> it = matchFields.iterator();
while (it.hasNext()) {
MatchField matchField = it.next();
addMatchField(matchField);
}
}
public String toString() {
String objString;
objString = "Match Criteria: Object ID: " + getObjectId() + " Name:" + getName();
Iterator<MatchField> it = matchFieldList.iterator();
while (it.hasNext()) {
MatchField matchField = it.next();
objString += ", " + matchField.toString();
}
return objString;
}
public BasicDBObject getAsDocument() {
BasicDBObject document = new BasicDBObject();
document.put("refCount", this.getReferenceCount());
document.put("name", this.getName());
document.put("enabled", this.getEnabled());
document.put("reflexive", this.getReflexive());
document.put("priority", this.getPriority());
List<Object> matchFieldsDoc = new BasicDBList();
for ( int i = 0; i < matchFieldList.size(); i++) {
MatchField matchField = matchFieldList.get(i);
matchFieldsDoc.add(matchField.getAsDocument());
}
document.put("matchFields", matchFieldsDoc);
return document;
}
public static boolean adjustReferenceCount(final ReferenceCountEnum adjType, String matchCriteriaId) throws NotFoundException {
DB database = TappingApp.getDatabase();
DBCollection table = database.getCollection(DatabaseNames.getMatchCriteriaTableName());
// Look for the Match Criteria object by object ID in the database
BasicDBObject searchQuery = new BasicDBObject();
ObjectId id = new ObjectId(matchCriteriaId);
searchQuery.put("_id", id);
DBObject dbObj = table.findOne(searchQuery);
if (dbObj == null)
throw new NotFoundException();
// create an increment query
DBObject modifier = new BasicDBObject("refCount", (adjType == ReferenceCountEnum.DECREMENT) ? -1 : 1);
DBObject incQuery = new BasicDBObject("$inc", modifier);
// increment a counter value atomically
WriteResult result = table.update(searchQuery, incQuery);
return (result != null) ? true : false;
}
public void generateFlowRules(List<FlowEntry> flowRules, List<Action> actions, Node node) {
// Add a Match for the set of MatchFields in the MatchCriteria
List<MatchField> matchFields = this.getFields();
// OpenDaylight Match object
Match match = new Match();
for (MatchField matchField : matchFields) {
try {
logger.info("MatchField " + matchField);
// Get the OpenDaylight Match object for this match field
matchField.addODLMatch(match);
} catch (UnknownHostException e) {
logger.info("Unable to resolve hostname for a MatchField used by MatchCritera " + this.getName());
} catch (IllegalArgumentException e) {
logger.info("Cannot create flow from " + matchField + " used by MatchCriteria " + this.getName() + ": Illegal Argument");
}
}
Flow flow = new Flow(match, actions);
// Install the flows permanently (no timeouts)
flow.setIdleTimeout((short) 0);
flow.setHardTimeout((short) 0);
// Set the priority based on the user input
flow.setPriority((short) this.getPriority());
if (this.isReflexive()) {
logger.info("MatchCriteria is reflexive ... adding reverse flow");
// TODO -- add this here
}
FlowEntry flowEntry = new FlowEntry("ONFTappingApp", this.getName(), flow, node);
flowRules.add(flowEntry);
}
}