Skip to content
Snippets Groups Projects
Commit e4a099fc authored by Pengfei Lu's avatar Pengfei Lu
Browse files

Refactoring ACL.java and IACLService.java

- fix bug in processing allowing ACL rule
- update Javadoc
parent 13361a5f
No related branches found
No related tags found
No related merge requests found
......@@ -24,10 +24,10 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import net.floodlightcontroller.accesscontrollist.ACLRule.Action;
import net.floodlightcontroller.accesscontrollist.ap.AP;
......@@ -54,226 +54,254 @@ import org.slf4j.LoggerFactory;
public class ACL implements IACLService, IFloodlightModule, IDeviceListener {
// service modules needed
protected IRestApiService restApi;
protected IDeviceService deviceManager;
protected IStorageSourceService storageSource;
protected static Logger logger;
private APManager apManager;
// variable used
private APManager apManager;
private int lastRuleId = 1; // rule id counter
private List<ACLRule> ruleSet;
private Map<Integer, ACLRule> aclRules;
private Map<String, Integer> dpid2FlowPriority;
private Map<Integer, Set<String>> ruleId2Dpid;
private Map<Integer, Set<String>> ruleId2FlowName;
private Map<Integer, List<Integer>> deny2Allow;
private final int DEFAULT_PRIORITY = 30000;
/**
* Checks if an existing ACL rule already works in a given switch.
*/
private boolean checkIfRuleWorksInSwitch(int ruleId, String dpid) {
return ruleId2Dpid.containsKey(ruleId)
&& ruleId2Dpid.get(ruleId).contains(dpid);
}
/**
* Adds a new mapping from ACL rule to ACL flow.
*/
private void addRuleToFlowMapping(int ruleId, String flowName) {
if (!ruleId2FlowName.containsKey(ruleId)) {
ruleId2FlowName.put(ruleId, new HashSet<String>());
}
ruleId2FlowName.get(ruleId).add(flowName);
}
/**
* Adds a new mapping from ACL rule to switch.
*/
private void addRuleToSwitchMapping(int ruleId, String dpid) {
if (!ruleId2Dpid.containsKey(ruleId)) {
ruleId2Dpid.put(ruleId, new HashSet<String>());
}
ruleId2Dpid.get(ruleId).add(dpid);
}
/**
* used by REST API to query ACL rules
* Gets the current priority for new ACL flow by device id.
*/
private int getPriorityBySwitch(String dpid) {
if (!dpid2FlowPriority.containsKey(dpid)) {
dpid2FlowPriority.put(dpid, DEFAULT_PRIORITY - 1);
return DEFAULT_PRIORITY;
} else {
int priority = dpid2FlowPriority.get(dpid);
dpid2FlowPriority.put(dpid, priority - 1);
return priority;
}
}
@Override
public List<ACLRule> getRules() {
return this.ruleSet;
return new ArrayList<ACLRule>(aclRules.values());
}
/**
* check if the new rule matches an existing rule
* Checks if the new ACL rule matches an existing rule. If existing allowing
* rules matches the new denying rule, store the mappings.
*
* @return true if the new ACL rule matches an existing rule, false
* otherwise
*/
private boolean checkRuleMatch(ACLRule newRule) {
Iterator<ACLRule> iter = ruleSet.iterator();
while (iter.hasNext()) {
ACLRule existingRule = iter.next();
if(newRule.match(existingRule)){
logger.error("existing rule: " + existingRule);
List<Integer> allowRuleList = new ArrayList<>();
for (ACLRule existingRule : getRules()) {
if (newRule.match(existingRule)) {
return true;
}
if (existingRule.getAction() == Action.ALLOW
&& newRule.getAction() == Action.DENY) {
if (existingRule.match(newRule)) {
allowRuleList.add(existingRule.getId());
}
}
}
deny2Allow.put(newRule.getId(), allowRuleList);
return false;
}
/**
* used by REST API to add ACL rule
* @return if the new ACL rule is added successfully
*/
@Override
public boolean addRule(ACLRule rule) {
if(checkRuleMatch(rule)){
rule.setId(lastRuleId++);
if (checkRuleMatch(rule)) {
lastRuleId--;
return false;
}
rule.setId(lastRuleId++);
this.ruleSet.add(rule);
logger.info("No.{} ACL rule added.", rule.getId());
enforceAddedRule(rule);
aclRules.put(rule.getId(), rule);
logger.info("ACL rule(id:{}) is added.", rule.getId());
if (rule.getAction() != Action.ALLOW) {
enforceAddedRule(rule);
}
return true;
}
/**
* used by REST API to remove ACL rule
*/
@Override
public void removeRule(int ruleid) {
Iterator<ACLRule> iter = this.ruleSet.iterator();
while (iter.hasNext()) {
ACLRule rule = iter.next();
if (rule.getId() == ruleid) { iter.remove();
break;
}
}
logger.info("No.{} ACL rule removed.", ruleid);
enforceRemovedRule(ruleid);
public void removeRule(int ruleId) {
aclRules.remove(ruleId);
logger.info("ACL rule(id:{}) is removed.", ruleId);
enforceRemovedRule(ruleId);
}
/**
* used by REST API to clear ACL
*/
@Override
public void removeAllRules() {
this.lastRuleId = 1;
this.ruleSet = new ArrayList<ACLRule>();
this.dpid2FlowPriority = new HashMap<String, Integer>();
this.ruleId2Dpid = new HashMap<Integer, Set<String>>();
Iterator<Integer> ruleIdIter = ruleId2FlowName.keySet().iterator();
while (ruleIdIter.hasNext()) {
int ruleId = ruleIdIter.next();
Set<String> flowNameSet = ruleId2FlowName.get(ruleId);
logger.debug("No.{} ACL rule removed.", ruleId);
this.aclRules = new TreeMap<>();
this.dpid2FlowPriority = new HashMap<>();
this.ruleId2Dpid = new HashMap<>();
this.deny2Allow = new HashMap<>();
for (Set<String> flowNameSet : ruleId2FlowName.values()) {
for (String flowName : flowNameSet) {
removeFlow(flowName);
logger.debug("ACL flow {} removed.", flowName);
storageSource.deleteRowAsync("controller_staticflowtableentry",
flowName);
logger.debug("ACL flow(id:{}) is removed.", flowName);
}
}
this.ruleId2FlowName = new HashMap<Integer, Set<String>>();
this.ruleId2FlowName = new HashMap<>();
}
/**
* enforce new added rule
* Enforces denying ACL rule by ACL flow.
*/
private void enforceAddedRule(ACLRule rule) {
private void enforceAddedRule(ACLRule denyRule) {
Set<String> dpidSet;
if (rule.getNw_src() != null) {
dpidSet = apManager.getDpidSet(rule.getNw_src_prefix(),rule.getNw_src_maskbits());
if (denyRule.getNw_src() != null) {
dpidSet = apManager.getDpidSet(denyRule.getNw_src_prefix(),
denyRule.getNw_src_maskbits());
} else {
dpidSet = apManager.getDpidSet(rule.getNw_dst_prefix(),rule.getNw_dst_maskbits());
dpidSet = apManager.getDpidSet(denyRule.getNw_dst_prefix(),
denyRule.getNw_dst_maskbits());
}
Iterator<String> dpidIter = dpidSet.iterator();
Set<String> nameSet = new HashSet<String>();
while (dpidIter.hasNext()) {
String dpid = dpidIter.next();
String flowName = "ACLRule_" + rule.getId() + "_" + dpid;
generateFlow(rule, dpid, flowName);
nameSet.add(flowName);
for (String dpid : dpidSet) {
String flowName;
List<Integer> allowRuleList = deny2Allow.get(denyRule.getId());
for (int allowRuleId : allowRuleList) {
flowName = "ACLRule_" + allowRuleId + "_" + dpid;
generateFlow(aclRules.get(allowRuleId), dpid, flowName);
}
flowName = "ACLRule_" + denyRule.getId() + "_" + dpid;
generateFlow(denyRule, dpid, flowName);
}
ruleId2FlowName.put(rule.getId(), nameSet);
ruleId2Dpid.put(rule.getId(), dpidSet);
}
/**
* enforce removed rule
* Enforces removing an existing ACL rule.
*/
private void enforceRemovedRule(int ruleId) {
Set<String> flowEntryName = ruleId2FlowName.get(ruleId);
Iterator<String> iter = flowEntryName.iterator();
while (iter.hasNext()) {
String name = iter.next();
removeFlow(name);
logger.debug("ACL flow " + name + " removed.");
if (ruleId2FlowName.containsKey(ruleId)) {
for (String flowName : ruleId2FlowName.get(ruleId)) {
storageSource.deleteRowAsync("controller_staticflowtableentry",
flowName);
logger.debug("ACL flow(id:{}) is removed.", flowName);
}
ruleId2FlowName.remove(ruleId);
}
ruleId2Dpid.remove(ruleId);
deny2Allow.remove(ruleId);
}
/**
* generate and push ACL flow entry
* Generates ACL flow rule according to ACL rule
* and installs it into switch.
*/
private void generateFlow(ACLRule rule, String dpid, String flowName) {
int priority;
// get priority for the new flow entry
if (dpid2FlowPriority.get(dpid) == null) {
dpid2FlowPriority.put(dpid, 30000);
priority = 30000;
} else {
priority = dpid2FlowPriority.get(dpid);
if (rule == null || checkIfRuleWorksInSwitch(rule.getId(), dpid)) {
return;
}
int priority = getPriorityBySwitch(dpid);
if (rule.getNw_src() != null) {
HashMap<String,Object> flow = new HashMap<String,Object>();
HashMap<String, Object> flow = new HashMap<String, Object>();
flow.put(StaticFlowEntryPusher.COLUMN_SWITCH, dpid);
flow.put(StaticFlowEntryPusher.COLUMN_NAME, flowName);
flow.put(StaticFlowEntryPusher.COLUMN_ACTIVE, Boolean.toString(true));
flow.put(StaticFlowEntryPusher.COLUMN_ACTIVE,
Boolean.toString(true));
flow.put(StaticFlowEntryPusher.COLUMN_COOKIE, "0");
flow.put(StaticFlowEntryPusher.COLUMN_PRIORITY, Integer.toString(priority));
dpid2FlowPriority.put(dpid, --priority);
flow.put(StaticFlowEntryPusher.COLUMN_PRIORITY,
Integer.toString(priority));
flow.put(StaticFlowEntryPusher.COLUMN_DL_TYPE, "2048");
flow.put(StaticFlowEntryPusher.COLUMN_NW_SRC, rule.getNw_src());
// process for the nw_dst attribute
if (rule.getNw_dst() != null) {
flow.put(StaticFlowEntryPusher.COLUMN_NW_DST, rule.getNw_dst());
}
if (rule.getNw_proto() != 0) {
flow.put(StaticFlowEntryPusher.COLUMN_NW_PROTO, Integer.toString(rule.getNw_proto()));
flow.put(StaticFlowEntryPusher.COLUMN_NW_PROTO,
Integer.toString(rule.getNw_proto()));
}
if (rule.getAction() == Action.ALLOW) {
flow.put(StaticFlowEntryPusher.COLUMN_ACTIONS, "output=controller");
flow.put(StaticFlowEntryPusher.COLUMN_ACTIONS,
"output=controller");
}
if (rule.getTp_dst() != 0) {
flow.put(StaticFlowEntryPusher.COLUMN_TP_DST, Integer.toString(rule.getTp_dst()));
flow.put(StaticFlowEntryPusher.COLUMN_TP_DST,
Integer.toString(rule.getTp_dst()));
}
storageSource.insertRowAsync(StaticFlowEntryPusher.TABLE_NAME, flow);
storageSource
.insertRowAsync(StaticFlowEntryPusher.TABLE_NAME, flow);
} else {
HashMap<String,Object> flow = new HashMap<String,Object>();
HashMap<String, Object> flow = new HashMap<String, Object>();
flow.put(StaticFlowEntryPusher.COLUMN_SWITCH, dpid);
flow.put(StaticFlowEntryPusher.COLUMN_NAME, flowName);
flow.put(StaticFlowEntryPusher.COLUMN_ACTIVE, Boolean.toString(true));
flow.put(StaticFlowEntryPusher.COLUMN_ACTIVE,
Boolean.toString(true));
flow.put(StaticFlowEntryPusher.COLUMN_COOKIE, "0");
flow.put(StaticFlowEntryPusher.COLUMN_PRIORITY, Integer.toString(priority));
dpid2FlowPriority.put(dpid, --priority);
flow.put(StaticFlowEntryPusher.COLUMN_PRIORITY,
Integer.toString(priority));
flow.put(StaticFlowEntryPusher.COLUMN_DL_TYPE, "2048");
flow.put(StaticFlowEntryPusher.COLUMN_NW_DST, rule.getNw_dst());
if (rule.getNw_proto() != 0) {
flow.put(StaticFlowEntryPusher.COLUMN_NW_PROTO, Integer.toString(rule.getNw_proto()));
flow.put(StaticFlowEntryPusher.COLUMN_NW_PROTO,
Integer.toString(rule.getNw_proto()));
}
if (rule.getAction() == Action.ALLOW) {
flow.put(StaticFlowEntryPusher.COLUMN_ACTIONS, "output=controller");
flow.put(StaticFlowEntryPusher.COLUMN_ACTIONS,
"output=controller");
}
if (rule.getTp_dst() != 0) {
flow.put(StaticFlowEntryPusher.COLUMN_TP_DST, Integer.toString(rule.getTp_dst()));
flow.put(StaticFlowEntryPusher.COLUMN_TP_DST,
Integer.toString(rule.getTp_dst()));
}
storageSource.insertRowAsync(StaticFlowEntryPusher.TABLE_NAME, flow);
}
logger.info("ACL flow " + flowName + " added in " + dpid);
}
/**
* remove ACL flow entry
*/
private void removeFlow(String name) {
storageSource.deleteRowAsync("controller_staticflowtableentry", name);
}
storageSource
.insertRowAsync(StaticFlowEntryPusher.TABLE_NAME, flow);
}
addRuleToSwitchMapping(rule.getId(), dpid);
addRuleToFlowMapping(rule.getId(), flowName);
logger.debug("ACL flow(id:{}) is added in {}.", flowName, dpid);
}
@Override
public Collection<Class<? extends IFloodlightService>> getModuleServices() {
......@@ -306,11 +334,12 @@ public class ACL implements IACLService, IFloodlightModule, IDeviceListener {
logger = LoggerFactory.getLogger(ACL.class);
storageSource = context.getServiceImpl(IStorageSourceService.class);
ruleSet = new ArrayList<ACLRule>();
aclRules = new TreeMap<>();
apManager = new APManager();
ruleId2FlowName = new HashMap<Integer, Set<String>>();
ruleId2Dpid = new HashMap<Integer, Set<String>>();
dpid2FlowPriority = new HashMap<String, Integer>();
ruleId2FlowName = new HashMap<>();
ruleId2Dpid = new HashMap<>();
dpid2FlowPriority = new HashMap<>();
deny2Allow = new HashMap<>();
}
@Override
......@@ -320,60 +349,55 @@ public class ACL implements IACLService, IFloodlightModule, IDeviceListener {
deviceManager.addListener(this);
}
/**
* listen for new device
*/
@Override
public void deviceAdded(IDevice device) {
SwitchPort[] switchPort = device.getAttachmentPoints();
IPv4Address[] ips = device.getIPv4Addresses();
if(ips.length == 0){
if (ips.length == 0) {
// A new no-ip device added
return;
}
String dpid = HexString.toHexString(switchPort[0].getSwitchDPID().getLong());
String dpid = HexString.toHexString(switchPort[0].getSwitchDPID()
.getLong());
String ip = IPv4.fromIPv4Address(ips[0].getInt());
logger.debug("New AP added. [dpid:" + dpid + " ip:" + ip + "]");
logger.debug("AP(dpid:{},ip:{}) is added", dpid, ip);
AP ap = new AP(ip,dpid);
AP ap = new AP(ip, dpid);
apManager.addAP(ap);
processAPAdded(ap);
}
/**
* push ACL flow given the new device
* Generates new ACL flow when a new device appears
* and existing ACL rules denies its traffic.
*/
private void processAPAdded(AP ap) {
String dpid = ap.getDpid();
int ip = IPv4.toIPv4Address(ap.getIp());
Iterator<ACLRule> iter = this.ruleSet.iterator();
while (iter.hasNext()) {
ACLRule rule = iter.next();
if (rule.getNw_src() != null) {
if (IPAddressUtil.containIP(rule.getNw_src_prefix(),
rule.getNw_src_maskbits(), ip)) {
// check if there is a flow entry in the switch for the rule
if (ruleId2Dpid.get(rule.getId()).contains(dpid)) {
continue;
for (ACLRule rule : getRules()) {
if (rule.getAction() != Action.ALLOW) {
if (rule.getNw_src() != null) {
if (IPAddressUtil.containIP(rule.getNw_src_prefix(),
rule.getNw_src_maskbits(), ip)) {
if (checkIfRuleWorksInSwitch(rule.getId(), dpid)) {
continue;
}
String flowName = "ACLRule_" + rule.getId() + "_"
+ dpid;
generateFlow(rule, dpid, flowName);
}
String flowName = "ACLRule_" + rule.getId() + "_" + dpid;
ruleId2FlowName.get(rule.getId()).add(flowName);
ruleId2Dpid.get(rule.getId()).add(dpid);
generateFlow(rule, dpid, flowName);
}
} else {
if (IPAddressUtil.containIP(rule.getNw_dst_prefix(),
rule.getNw_dst_maskbits(), ip)) {
// check if there is a flow entry in the switch for the rule
if (ruleId2Dpid.get(rule.getId()).contains(dpid)) {
continue;
} else {
if (IPAddressUtil.containIP(rule.getNw_dst_prefix(),
rule.getNw_dst_maskbits(), ip)) {
if (checkIfRuleWorksInSwitch(rule.getId(), dpid)) {
continue;
}
String flowName = "ACLRule_" + rule.getId() + "_"
+ dpid;
generateFlow(rule, dpid, flowName);
}
String flowName = "ACLRule_" + rule.getId() + "_" + dpid;
ruleId2FlowName.get(rule.getId()).add(flowName);
ruleId2Dpid.get(rule.getId()).add(dpid);
generateFlow(rule, dpid, flowName);
}
}
}
......@@ -391,22 +415,23 @@ public class ACL implements IACLService, IFloodlightModule, IDeviceListener {
@Override
public void deviceIPV4AddrChanged(IDevice device) {
SwitchPort[] switchPort = device.getAttachmentPoints();
IPv4Address[] ips = device.getIPv4Addresses();
String dpid = HexString.toHexString(switchPort[0].getSwitchDPID().getLong());
String dpid = HexString.toHexString(switchPort[0].getSwitchDPID()
.getLong());
String ip = null;
// some device may first appear with no IP address(default set to 0.0.0.0), ignore it
for(IPv4Address i : ips){
if(i.getInt() != 0){
// some device may first appear with no IP address(default set to
// 0.0.0.0), ignore it
for (IPv4Address i : ips) {
if (i.getInt() != 0) {
ip = IPv4.fromIPv4Address(i.getInt());
break;
}
}
logger.info("New AP added. [dpid:" + dpid + " ip:" + ip + "]");
logger.debug("AP(dpid:{},ip:{}) is added", dpid, ip);
AP ap = new AP(ip, dpid);
apManager.addAP(ap);
processAPAdded(ap);
......@@ -419,7 +444,7 @@ public class ACL implements IACLService, IFloodlightModule, IDeviceListener {
@Override
public String getName() {
return null;
return "ACL manager";
}
@Override
......
/**
* Copyright 2015, Big Switch Networks, Inc.
* Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China
* Advisers: Keqiu Li and Heng Qi
* This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002)
* and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute.
*
* 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 net.floodlightcontroller.accesscontrollist;
import java.util.List;
import net.floodlightcontroller.core.module.IFloodlightService;
public interface IACLService extends IFloodlightService {
public List<ACLRule> getRules();
/**
* add a new ACL rule
* @param rule
* @return whether the rule is added successfully
*/
public boolean addRule(ACLRule rule);
public void removeRule(int ruleid);
public void removeAllRules();
}
/**
* Copyright 2015, Big Switch Networks, Inc.
* Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China
* Advisers: Keqiu Li and Heng Qi
* This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002)
* and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute.
*
* 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 net.floodlightcontroller.accesscontrollist;
import java.util.List;
import net.floodlightcontroller.core.module.IFloodlightService;
/**
* Service interface exported by ACL module
*/
public interface IACLService extends IFloodlightService {
/**
* Gets a list containing all ACL rules.
* @return a list containing all ACL rules
*/
public List<ACLRule> getRules();
/**
* Add a new ACL rule.
* @param rule ACL rule
* @return true if successfully added, otherwise false
*/
public boolean addRule(ACLRule rule);
/**
* Removes an existing ACL rule by rule id.
* @param ruleId ACL rule identifier
*/
public void removeRule(int ruleid);
/**
* Clears ACL and resets all.
*/
public void removeAllRules();
}
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