/* * Copyright (c) 2013 Big Switch Networks, Inc. * * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/legal/epl-v10.html * * 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 org.sdnplatform.netvirt.core; import java.util.ArrayList; import java.util.List; import org.sdnplatform.core.ListenerContext; import org.sdnplatform.core.util.MutableInteger; import org.sdnplatform.devicemanager.IDevice; import org.sdnplatform.devicemanager.IDeviceService; import org.sdnplatform.netvirt.virtualrouting.internal.VirtualRouting; import org.sdnplatform.packet.Ethernet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Represents an access control list. It is associated with a NetVirt and contain one or more entries. * @author shudong.zhou@bigswitch.com */ public class VNSAccessControlList implements Comparable<VNSAccessControlList> { public static enum VNSAclMatchResult { ACL_NO_MATCH, ACL_PERMIT, ACL_DENY }; protected static Logger logger = LoggerFactory.getLogger(VNSAccessControlList.class); protected String name; protected String description; protected int priority; protected List<VNSAccessControlListEntry> entries; /* Used to garbage collect stale config data */ protected boolean marked; /** * @param parentNetVirt the parent of the interface rule */ public VNSAccessControlList(String name) { super(); this.setName(name); this.priority = 32768; // default as specified in PRD entries = new ArrayList<VNSAccessControlListEntry>(); } public String getName() { return name; } public void setName(String name) { if (name == null) throw new NullPointerException("name cannot be null"); this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public int getPriority() { return priority; } public void setPriority(int priority) { this.priority = priority; } /** * Add acl entry to list in the order they are applied */ public void addAclEntry(VNSAccessControlListEntry entry) { int index; entry.setParentACL(this); for (index = 0; index < entries.size(); index++) { if (entry.compareTo(entries.get(index)) < 0) continue; // no dups at the same sequence number if (entry.compareTo(entries.get(index)) == 0) entries.remove(index); break; } entries.add(index, entry); } /** * Apply acl to a packet and get the matching action * If this is for an explain packet then populate the context with the acl * entry that was hit */ public VNSAclMatchResult applyAcl (Ethernet eth, MutableInteger wildcards, ListenerContext cntx, String direction) { /* * Extract source device and destination device information from the * listener context. */ IDevice srcDev = IDeviceService.fcStore.get( cntx, IDeviceService.CONTEXT_SRC_DEVICE); IDevice dstDev = IDeviceService.fcStore.get( cntx, IDeviceService.CONTEXT_DST_DEVICE); // The entries list is sorted with sequence number for (VNSAccessControlListEntry entry : entries) { VNSAclMatchResult result = entry.matchAcl(eth, srcDev, dstDev, wildcards); if (result != VNSAclMatchResult.ACL_NO_MATCH) { if (logger.isTraceEnabled()) logger.trace("{} matched ACL entry {}", eth, entry); // Note down the acl entry hit for explain packet if ((cntx != null) && (direction != null)) { if (NetVirtExplainPacket.isExplainPktCntx(cntx)) { String aclDirection = NetVirtExplainPacket.KEY_EXPLAIN_PKT_OUT_ACL_ENTRY; if (direction.equals(VirtualRouting.ACL_DIRECTION_INPUT)) { aclDirection = NetVirtExplainPacket.KEY_EXPLAIN_PKT_INP_ACL_ENTRY; } // split() below converts "ACL: default|acl-test2-out seqNo: 10 permit ip any any" to // "10 permit ip any any", for example // TODO - this sucks, it depends upon specific string format. NetVirtExplainPacket.explainPacketSetContext(cntx, aclDirection, entry.toString().split(":", 3)[2]); } } return result; } } // Implicit deny if no ACL entry matches if ((cntx != null) && (direction != null)) { String aclDirection = NetVirtExplainPacket.KEY_EXPLAIN_PKT_OUT_ACL_ENTRY; if (direction.equals(VirtualRouting.ACL_DIRECTION_INPUT)) { aclDirection = NetVirtExplainPacket.KEY_EXPLAIN_PKT_INP_ACL_ENTRY; } NetVirtExplainPacket.explainPacketSetContext(cntx, aclDirection, "Implicit deny"); } return VNSAclMatchResult.ACL_DENY; } @Override public boolean equals(Object arg0) { if (arg0 instanceof VNSAccessControlList) { return this.name.equals(((VNSAccessControlList)arg0).name); } return super.equals(arg0); } @Override public int hashCode() { return this.name.hashCode(); } @Override public int compareTo(VNSAccessControlList o) { // higher priority is sorted first if (priority != o.priority) return (new Integer(o.priority)).compareTo(priority); return (name.compareTo(o.name)); } @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append(name); sb.append(" [Priority: " + priority + "]"); sb.append(" [Number of entries: " + entries.size() + "]"); return sb.toString(); } }