import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.groupbasedpolicy.endpoint.AbstractEndpointRegistry;
import org.opendaylight.groupbasedpolicy.resolver.EgKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.groupbasedpolicy.resolver.EndpointProvider;
+import org.opendaylight.groupbasedpolicy.util.SetUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.Endpoints;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
-
/**
* Keep track of endpoints on the system. Maintain an index of endpoints
* and their locations for renderering. The endpoint manager will maintain
*/
public class EndpointManager
extends AbstractEndpointRegistry
- implements AutoCloseable, DataChangeListener
+ implements AutoCloseable, DataChangeListener, EndpointProvider
{
private static final Logger LOG =
LoggerFactory.getLogger(EndpointManager.class);
return Collections2.transform(ebn, indexTransform);
}
- /**
- * Get a collection of endpoints in a particular endpoint group
- * @param nodeId the nodeId of the switch to get endpoints for
- * @return a collection of {@link Endpoint} objects.
- */
- public Collection<Endpoint> getEndpointsForGroup(TenantId tenantId,
- EndpointGroupId egId) {
- EgKey eg = new EgKey(tenantId, egId);
- Collection<EpKey> ebg = endpointsByGroup.get(eg);
- if (ebg == null) return Collections.emptyList();
- return Collections2.transform(ebg, indexTransform);
- }
-
/**
* Get the endpoint object for the given key
* @param epKey the key
public void setLearningMode(LearningMode learningMode) {
// No-op for now
}
-
+
+ // ****************
+ // EndpointProvider
+ // ****************
+
+ @Override
+ public Collection<Endpoint> getEndpointsForGroup(EgKey eg) {
+ Collection<EpKey> ebg = endpointsByGroup.get(eg);
+ if (ebg == null) return Collections.emptyList();
+ return Collections2.transform(ebg, indexTransform);
+ }
+
+ @Override
+ public List<ConditionName> getCondsForEndpoint(Endpoint endpoint) {
+ // XXX TODO consider group conditions as well. Also need to notify
+ // endpoint updated if the endpoint group conditions change
+ if (endpoint.getCondition() != null)
+ return endpoint.getCondition();
+ else return Collections.emptyList();
+ }
+
// ************************
// AbstractEndpointRegistry
// ************************
if (newLoc != null) {
Set<EpKey> eps = getEpNSet(newLoc);
eps.add(epKey);
- LOG.info("Endpoint {} added to node {}", epKey, newLoc);
+ LOG.debug("Endpoint {} added to node {}", epKey, newLoc);
notifyNewLoc = true;
}
if (newKey != null) {
Set<EpKey> gns = getEpGSet(newKey);
gns.add(epKey);
- LOG.info("Endpoint {} added to group {}", epKey, newKey);
+ LOG.debug("Endpoint {} added to group {}", epKey, newKey);
notifyNewEg = true;
}
int numCPU = Runtime.getRuntime().availableProcessors();
executor = Executors.newScheduledThreadPool(numCPU * 2);
- policyResolver = new PolicyResolver(dataProvider, executor);
switchManager = new SwitchManager(dataProvider, executor);
endpointManager = new EndpointManager(dataProvider, rpcRegistry,
executor, switchManager);
+ policyResolver = new PolicyResolver(dataProvider, executor);
policyManager = new PolicyManager(dataProvider,
policyResolver,
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PolicyEnforcer;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PortSecurity;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.SourceMapper;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures;
+import org.opendaylight.groupbasedpolicy.resolver.ConditionGroup;
import org.opendaylight.groupbasedpolicy.resolver.EgKey;
+import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
import org.opendaylight.groupbasedpolicy.resolver.PolicyListener;
import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver;
import org.opendaylight.groupbasedpolicy.resolver.PolicyScope;
+import org.opendaylight.groupbasedpolicy.util.SetUtils;
+import org.opendaylight.groupbasedpolicy.util.SingletonTask;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
private final DataBroker dataBroker;
private final SwitchManager switchManager;
+ private final PolicyResolver policyResolver;
private final PolicyScope policyScope;
/**
* Keep track of currently-allocated ordinals
- * XXX should ultimately involve some sort of distributed agreement
- * or a leader to allocate them. For now we'll just use a counter and
- * this local map
*/
+ // XXX For the endpoint groups, we need a globally unique ordinal, so
+ // should ultimately involve some sort of distributed agreement
+ // or a leader to allocate them. For now we'll just use a counter and
+ // this local map. Also theoretically need to garbage collect periodically
private final ConcurrentMap<TenantId, ConcurrentMap<String, Integer>> ordinals =
new ConcurrentHashMap<>();
-
+ // XXX - need to garbage collect
+ private final ConcurrentMap<ConditionGroup, Integer> cgOrdinals =
+ new ConcurrentHashMap<>();
+
public PolicyManager(DataBroker dataBroker,
PolicyResolver policyResolver,
SwitchManager switchManager,
this.dataBroker = dataBroker;
this.switchManager = switchManager;
this.executor = executor;
+ this.policyResolver = policyResolver;
if (dataBroker != null) {
WriteTransaction t = dataBroker.newWriteOnlyTransaction();
public void setLearningMode(LearningMode learningMode) {
// No-op for now
}
-
+
+ /**
+ * Get a unique ordinal for the given condition group, suitable for
+ * use in the data plane. This is unique only for this node, and not
+ * globally.
+ * @param cg the {@link ConditionGroup}
+ * @return the unique ID
+ */
+ public int getConfGroupOrdinal(final ConditionGroup cg) {
+ if (cg == null) return 0;
+ Integer ord = cgOrdinals.get(cg);
+ if (ord == null) {
+ ord = policyOrdinal.getAndIncrement();
+ Integer old = cgOrdinals.putIfAbsent(cg, ord);
+ if (old != null) ord = old;
+ }
+ return ord.intValue();
+ }
+
/**
* Get a 32-bit context ordinal suitable for use in the OF data plane
* for the given policy item. Note that this function may block
@Override
public Void call() throws Exception {
- if (!switchManager.isSwitchReady(nodeId)) return null;
+ if (!switchManager.isSwitchReady(nodeId)) return null;
+ PolicyInfo info = policyResolver.getCurrentPolicy();
+ if (info == null) return null;
for (FlowTable table : flowPipeline) {
try {
- table.update(nodeId, dirty);
+ table.update(nodeId, info, dirty);
} catch (Exception e) {
LOG.error("Failed to write flow table {}",
table.getClass().getName(), e);
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.groupbasedpolicy.renderer.ofoverlay;
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.SubjectFeatureDefinitions;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.SubjectFeatureDefinitionsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.Type;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.ParameterBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinition;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinitionBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinitionBuilder;
-
-import com.google.common.collect.ImmutableList;
-
-/**
- * Defines the subject features that are supported by the OF overlay renderer
- */
-public class SubjectFeatures {
- public static final ActionDefinition ALLOW =
- new ActionDefinitionBuilder()
- .setId(new ActionDefinitionId("f942e8fd-e957-42b7-bd18-f73d11266d17"))
- .setName(new ActionName("allow"))
- .setDescription(new Description("Allow the specified traffic to pass"))
- .build();
-
- public static final ClassifierDefinition ETHER_TYPE =
- new ClassifierDefinitionBuilder()
- .setId(new ClassifierDefinitionId("79c6fdb2-1e1a-4832-af57-c65baf5c2335"))
- .setName(new ClassifierName("ether_type"))
- .setDescription(new Description("Match on the ether type of the traffic"))
- .setParameter(ImmutableList.of(new ParameterBuilder()
- .setName(new ParameterName("type"))
- .setDescription(new Description("The ethertype to match against"))
- .setType(Type.Int)
- .build()))
- .build();
-
- public static final ClassifierDefinition IP_PROTO =
- new ClassifierDefinitionBuilder()
- .setId(new ClassifierDefinitionId("79c6fdb2-1e1a-4832-af57-c65baf5c2335"))
- .setParent(ETHER_TYPE.getId())
- .setName(new ClassifierName("ip_proto"))
- .setDescription(new Description("Match on the IP protocol of IP traffic"))
- .setParameter(ImmutableList.of(new ParameterBuilder()
- .setName(new ParameterName("proto"))
- .setDescription(new Description("The IP protocol to match against"))
- .setType(Type.Int)
- .build()))
- .build();
-
- public static final ClassifierDefinition UDP_PORT =
- new ClassifierDefinitionBuilder()
- .setId(new ClassifierDefinitionId("4250ab32-e8b8-445a-aebb-e1bd2cdd291f"))
- .setParent(IP_PROTO.getId())
- .setName(new ClassifierName("udp_port"))
- .setDescription(new Description("Match on the port number of UDP traffic"))
- .setParameter(ImmutableList.of(new ParameterBuilder()
- .setName(new ParameterName("port"))
- .setDescription(new Description("The port number to match against"))
- .setType(Type.Int)
- .build()))
- .build();
-
- public static final ClassifierDefinition TCP_PORT =
- new ClassifierDefinitionBuilder()
- .setId(new ClassifierDefinitionId("4250ab32-e8b8-445a-aebb-e1bd2cdd291f"))
- .setParent(IP_PROTO.getId())
- .setName(new ClassifierName("tcp_port"))
- .setDescription(new Description("Match on the port number of TCP traffic"))
- .setParameter(ImmutableList.of(new ParameterBuilder()
- .setName(new ParameterName("port"))
- .setDescription(new Description("The port number to match against"))
- .setType(Type.Int)
- .build()))
- .build();
-
- public static final SubjectFeatureDefinitions OF_OVERLAY_FEATURES =
- new SubjectFeatureDefinitionsBuilder()
- .setActionDefinition(ImmutableList.of(ALLOW))
- .setClassifierDefinition(ImmutableList.of(ETHER_TYPE,
- IP_PROTO,
- UDP_PORT,
- TCP_PORT))
- .build();
-}
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
+import org.opendaylight.groupbasedpolicy.resolver.ConditionGroup;
import org.opendaylight.groupbasedpolicy.resolver.EgKey;
+import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.EndpointLocation.LocationType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Sets;
/**
* Manage the table that maps the destination address to the next hop
* @author readams
*/
public class DestinationMapper extends FlowTable {
+ protected static final Logger LOG =
+ LoggerFactory.getLogger(DestinationMapper.class);
+
public static final short TABLE_ID = 2;
/**
* This is the MAC address of the magical router in the sky
public void sync(ReadWriteTransaction t,
InstanceIdentifier<Table> tiid,
Map<String, FlowCtx> flowMap,
- NodeId nodeId, Dirty dirty)
+ NodeId nodeId, PolicyInfo policyInfo, Dirty dirty)
throws Exception {
+ dropFlow(t, tiid, flowMap, Integer.valueOf(1), null);
+
HashSet<EgKey> visitedEgs = new HashSet<>();
- for (Endpoint e : ctx.endpointManager.getEndpointsForNode(nodeId)) {
+ for (Endpoint e : ctx.epManager.getEndpointsForNode(nodeId)) {
if (e.getTenant() == null || e.getEndpointGroup() == null)
continue;
EgKey key = new EgKey(e.getTenant(), e.getEndpointGroup());
- syncEPG(t, tiid, flowMap, nodeId, key, visitedEgs);
- Set<EgKey> peers = ctx.policyResolver
- .getProvidersForConsumer(e.getTenant(),
- e.getEndpointGroup());
- syncEgKeys(t, tiid, flowMap, nodeId, peers, visitedEgs);
- peers = ctx.policyResolver
- .getConsumersForProvider(e.getTenant(),
- e.getEndpointGroup());
- syncEgKeys(t, tiid, flowMap, nodeId, peers, visitedEgs);
- }
- }
-
- private void syncEgKeys(ReadWriteTransaction t,
- InstanceIdentifier<Table> tiid,
- Map<String, FlowCtx> flowMap,
- NodeId nodeId,
- Set<EgKey> peers,
- HashSet<EgKey> visitedEgs) throws Exception {
- for (EgKey key : peers) {
- syncEPG(t, tiid, flowMap, nodeId, key, visitedEgs);
+ Set<EgKey> peers = Sets.union(Collections.singleton(key),
+ policyInfo.getPeers(key));
+ for (EgKey peer : peers) {
+ syncEPG(t, tiid, flowMap, nodeId, policyInfo, peer, visitedEgs);
+ }
}
}
private void syncEPG(ReadWriteTransaction t,
InstanceIdentifier<Table> tiid,
Map<String, FlowCtx> flowMap,
- NodeId nodeId,
+ NodeId nodeId, PolicyInfo policyInfo,
EgKey key,
HashSet<EgKey> visitedEgs) throws Exception {
if (visitedEgs.contains(key)) return;
visitedEgs.add(key);
- Collection<Endpoint> egEps = ctx.endpointManager
- .getEndpointsForGroup(key.getTenantId(), key.getEgId());
+ Collection<Endpoint> egEps = ctx.epManager
+ .getEndpointsForGroup(key);
for (Endpoint e : egEps) {
if (e.getTenant() == null || e.getEndpointGroup() == null)
continue;
OfOverlayContext ofc = e.getAugmentation(OfOverlayContext.class);
if (ofc == null || ofc.getNodeId() == null) continue;
- syncEP(t, tiid, flowMap, nodeId, e, ofc, key);
+ syncEP(t, tiid, flowMap, nodeId, policyInfo, e, ofc, key);
}
}
private void syncEP(ReadWriteTransaction t,
InstanceIdentifier<Table> tiid,
Map<String, FlowCtx> flowMap,
- NodeId nodeId,
+ NodeId nodeId, PolicyInfo policyInfo,
Endpoint e, OfOverlayContext ofc,
EgKey key)
throws Exception {
// this is a local endpoint
nextHop = ofc.getNodeConnectorId().getValue();
+ // XXX - TODO - instead of outputting, write next hop
+ // to a register and output from the policy table
Action output = FlowUtils.outputAction(ofc.getNodeConnectorId());
instructions.add(new InstructionBuilder()
order +=1;
}
}
+
+ int egId = ctx.policyManager.getContextOrdinal(e.getTenant(),
+ e.getEndpointGroup());
+ List<ConditionName> conds = ctx.epManager.getCondsForEndpoint(e);
+ ConditionGroup cg =
+ policyInfo.getEgCondGroup(new EgKey(e.getTenant(),
+ e.getEndpointGroup()),
+ conds);
+ int cgId = ctx.policyManager.getConfGroupOrdinal(cg);
+
+ // XXX TODO - add action set dEPG and dCG into registers
Instruction gotoTable = new InstructionBuilder()
.setOrder(order++)
.setInstruction(FlowUtils.gotoTableIns((short)(getTableId()+1)))
.append(nextHop)
.toString());
if (visit(flowMap, flowid.getValue())) {
+ LOG.info("{} deg:{} dcg:{}", e.getMacAddress(), egId, cgId);
// XXX TODO add match against bridge domain register
FlowBuilder flowb = base()
.setId(flowid)
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.SwitchManager;
+import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
protected final PolicyManager policyManager;
protected final SwitchManager switchManager;
- protected final EndpointManager endpointManager;
+ protected final EndpointManager epManager;
protected final PolicyResolver policyResolver;
this.rpcRegistry = rpcRegistry;
this.policyManager = policyManager;
this.switchManager = switchManager;
- this.endpointManager = endpointManager;
+ this.epManager = endpointManager;
this.policyResolver = policyResolver;
this.executor = executor;
}
* @param dirty the dirty set
* @throws Exception
*/
- public void update(NodeId nodeId, Dirty dirty) throws Exception {
+ public void update(NodeId nodeId, PolicyInfo policyInfo,
+ Dirty dirty) throws Exception {
ReadWriteTransaction t = ctx.dataBroker.newReadWriteTransaction();
InstanceIdentifier<Table> tiid =
FlowUtils.createTablePath(nodeId, getTableId());
Optional<Table> r =
t.read(LogicalDatastoreType.CONFIGURATION, tiid).get();
+ // Unfortunately, we need to construct a unique string ID for each
+ // flow which is redundant with all the information in the flow itself
+ // We'll build this map so at least we don't have to be O(n^2)
HashMap<String, FlowCtx> flowMap = new HashMap<>();
if (r.isPresent()) {
}
}
- sync(t, tiid, flowMap, nodeId, dirty);
+ sync(t, tiid, flowMap, nodeId, policyInfo, dirty);
for (FlowCtx fx : flowMap.values()) {
if (!fx.visited) {
public abstract void sync(ReadWriteTransaction t,
InstanceIdentifier<Table> tiid,
Map<String, FlowCtx> flowMap,
- NodeId nodeId, Dirty dirty) throws Exception;
+ NodeId nodeId, PolicyInfo policyInfo,
+ Dirty dirty) throws Exception;
/**
* Get the table ID being manipulated
flow);
}
+ /**
+ * Write a drop flow for the given ethertype at the given priority.
+ * If the ethertype is null, then drop all traffic
+ */
+ protected void dropFlow(ReadWriteTransaction t,
+ InstanceIdentifier<Table> tiid,
+ Map<String, FlowCtx> flowMap,
+ Integer priority, Long etherType) {
+ FlowId flowid = new FlowId(new StringBuilder()
+ .append("drop|")
+ .append(etherType)
+ .toString());
+ if (visit(flowMap, flowid.getValue())) {
+ FlowBuilder flowb = base()
+ .setId(flowid)
+ .setPriority(priority)
+ .setInstructions(FlowUtils.dropInstructions());
+ if (etherType != null)
+ flowb.setMatch(new MatchBuilder()
+ .setEthernetMatch(FlowUtils.ethernetMatch(null, null,
+ etherType))
+ .build());
+ writeFlow(t, tiid, flowb.build());
+ }
+ }
+
/**
* Context object for keeping track of flow state
*/
/**
* ARP ethertype
*/
- protected static final Long ARP = Long.valueOf(0x0806);
+ public static final Long ARP = Long.valueOf(0x0806);
/**
* IPv4 ethertype
*/
- protected static final Long IPv4 = Long.valueOf(0x0800);
+ public static final Long IPv4 = Long.valueOf(0x0800);
/**
* IPv6 ethertype
*/
- protected static final Long IPv6 = Long.valueOf(0x86DD);
+ public static final Long IPv6 = Long.valueOf(0x86DD);
/**
* Creates an Instance Identifier (path) for node with specified id
package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.concurrent.Immutable;
import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Classifier;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures;
+import org.opendaylight.groupbasedpolicy.resolver.ConditionGroup;
+import org.opendaylight.groupbasedpolicy.resolver.EgKey;
+import org.opendaylight.groupbasedpolicy.resolver.IndexedTenant;
+import org.opendaylight.groupbasedpolicy.resolver.Policy;
+import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
+import org.opendaylight.groupbasedpolicy.resolver.RuleGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup.IntraGroupPolicy;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstance;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Manage the table that enforces policy on the traffic. Traffic is denied
* @author readams
*/
public class PolicyEnforcer extends FlowTable {
+ protected static final Logger LOG =
+ LoggerFactory.getLogger(PolicyEnforcer.class);
+
public static final short TABLE_ID = 3;
public PolicyEnforcer(FlowTableCtx ctx) {
super(ctx);
}
+ @Override
+ public short getTableId() {
+ return TABLE_ID;
+ }
+
@Override
public void sync(ReadWriteTransaction t, InstanceIdentifier<Table> tiid,
- Map<String, FlowCtx> flowMap, NodeId nodeId, Dirty dirty)
+ Map<String, FlowCtx> flowMap, NodeId nodeId,
+ PolicyInfo policyInfo, Dirty dirty)
+ throws Exception {
+ dropFlow(t, tiid, flowMap, Integer.valueOf(1), null);
+
+ HashSet<CgPair> visitedPairs = new HashSet<>();
+ HashSet<EgKey> visitedEgs = new HashSet<>();
+ for (Endpoint src : ctx.epManager.getEndpointsForNode(nodeId)) {
+ if (src.getTenant() == null || src.getEndpointGroup() == null)
+ continue;
+
+ List<ConditionName> conds =
+ ctx.epManager.getCondsForEndpoint(src);
+ ConditionGroup scg =
+ policyInfo.getEgCondGroup(new EgKey(src.getTenant(),
+ src.getEndpointGroup()),
+ conds);
+ int sepgId =
+ ctx.policyManager.getContextOrdinal(src.getTenant(),
+ src.getEndpointGroup());
+ int scgId = ctx.policyManager.getConfGroupOrdinal(scg);
+
+ EgKey sepg = new EgKey(src.getTenant(), src.getEndpointGroup());
+
+ if (!visitedEgs.contains(sepg)) {
+ visitedEgs.add(sepg);
+ IndexedTenant tenant =
+ ctx.policyResolver.getTenant(sepg.getTenantId());
+ EndpointGroup group =
+ tenant.getEndpointGroup(sepg.getEgId());
+ IntraGroupPolicy igp = group.getIntraGroupPolicy();
+ if (igp == null || igp.equals(IntraGroupPolicy.Allow)) {
+ allowSameEpg(t, tiid, flowMap, nodeId, sepgId);
+ }
+ }
+
+ Set<EgKey> peers = policyInfo.getPeers(sepg);
+ for (EgKey depg : peers) {
+ int depgId =
+ ctx.policyManager.getContextOrdinal(depg.getTenantId(),
+ depg.getEgId());
+
+ for (Endpoint dst : ctx.epManager.getEndpointsForGroup(depg)) {
+
+ conds = ctx.epManager.getCondsForEndpoint(src);
+ ConditionGroup dcg =
+ policyInfo.getEgCondGroup(new EgKey(dst.getTenant(),
+ dst.getEndpointGroup()),
+ conds);
+ int dcgId = ctx.policyManager.getConfGroupOrdinal(dcg);
+
+ CgPair p = new CgPair(depgId, sepgId, dcgId, scgId);
+ if (visitedPairs.contains(p)) continue;
+ visitedPairs.add(p);
+ syncPolicy(t, tiid, flowMap, nodeId, policyInfo,
+ p, depg, sepg, dcg, scg);
+
+ p = new CgPair(sepgId, depgId, scgId, dcgId);
+ if (visitedPairs.contains(p)) continue;
+ visitedPairs.add(p);
+ syncPolicy(t, tiid, flowMap, nodeId, policyInfo,
+ p, sepg, depg, scg, dcg);
+
+ }
+ }
+ }
+ }
+
+ private void allowSameEpg(ReadWriteTransaction t,
+ InstanceIdentifier<Table> tiid,
+ Map<String, FlowCtx> flowMap, NodeId nodeId,
+ int sepgId) {
+ FlowId flowId = new FlowId(new StringBuilder()
+ .append("intraallow|")
+ .append(sepgId).toString());
+ if (visit(flowMap, flowId.getValue())) {
+ // XXX - TODO - add match against sepg, depg registers
+ // XXX - TOOD - add output action from destination register
+ FlowBuilder flow = base()
+ .setId(flowId)
+ .setPriority(65000);
+ writeFlow(t, tiid, flow.build());
+ }
+ }
+
+ private void syncPolicy(ReadWriteTransaction t,
+ InstanceIdentifier<Table> tiid,
+ Map<String, FlowCtx> flowMap, NodeId nodeId,
+ PolicyInfo policyInfo,
+ CgPair p, EgKey sepg, EgKey depg,
+ ConditionGroup scg, ConditionGroup dcg)
throws Exception {
+ // XXX - TODO raise an exception for rules between the same
+ // endpoint group that are asymmetric
+ Policy policy = policyInfo.getPolicy(sepg, depg);
+ List<RuleGroup> rgs = policy.getRules(scg, dcg);
+ int priority = 65000;
+ for (RuleGroup rg : rgs) {
+ TenantId tenantId = rg.getContractTenant().getId();
+ IndexedTenant tenant = ctx.policyResolver.getTenant(tenantId);
+ for (Rule r : rg.getRules()) {
+ syncDirection(t, tiid, flowMap, nodeId, tenant,
+ p, r, Direction.In, priority);
+ syncDirection(t, tiid, flowMap, nodeId, tenant,
+ p, r, Direction.Out, priority);
+
+ priority -= 1;
+ }
+ }
}
+
+ private void syncDirection(ReadWriteTransaction t,
+ InstanceIdentifier<Table> tiid,
+ Map<String, FlowCtx> flowMap, NodeId nodeId,
+ IndexedTenant contractTenant,
+ CgPair p, Rule r, Direction d, int priority) {
+ for (ClassifierRef cr : r.getClassifierRef()) {
+ if (cr.getDirection() != null &&
+ !cr.getDirection().equals(Direction.Bidirectional) &&
+ !cr.getDirection().equals(d))
+ continue;
+
+ StringBuilder idb = new StringBuilder();
+ // XXX - TODO - implement connection tracking (requires openflow
+ // extension and data plane support)
+
+ MatchBuilder baseMatch = new MatchBuilder();
+
+ if (d.equals(Direction.Out)) {
+ idb.append(p.sepg)
+ .append("|")
+ .append(p.scgId)
+ .append("|")
+ .append(p.depg)
+ .append("|")
+ .append(p.dcgId)
+ .append("|")
+ .append(priority);
+ // XXX - TODO - add match against sepg, depg, scg, and dcg
+ // registers
+ } else {
+ idb.append(p.depg)
+ .append("|")
+ .append(p.dcgId)
+ .append("|")
+ .append(p.sepg)
+ .append("|")
+ .append(p.scgId)
+ .append("|")
+ .append(priority);
+ // XXX - TODO - add match against sepg, depg, scg, and dcg
+ // registers
+ }
+
+
+ ClassifierInstance ci = contractTenant.getClassifier(cr.getName());
+ if (ci == null) {
+ // XXX TODO fail the match and raise an exception
+ LOG.warn("Classifier instance {} not found",
+ cr.getName().getValue());
+ return;
+ }
+ Classifier cfier = SubjectFeatures
+ .getClassifier(ci.getClassifierDefinitionId());
+ if (cfier == null) {
+ // XXX TODO fail the match and raise an exception
+ LOG.warn("Classifier definition {} not found",
+ ci.getClassifierDefinitionId().getValue());
+ return;
+ }
+
+ List<MatchBuilder> matches = Collections.singletonList(baseMatch);
+ Map<String,Object> params = new HashMap<>();
+ for (ParameterValue v : ci.getParameterValue()) {
+ if (v.getName() == null) continue;
+ if (v.getIntValue() != null) {
+ params.put(v.getName().getValue(), v.getIntValue());
+ } else if (v.getStringValue() != null) {
+ params.put(v.getName().getValue(), v.getStringValue());
+ }
+ }
+
+ matches = cfier.updateMatch(matches, params);
+ String baseId = idb.toString();
+ FlowBuilder flow = base()
+ .setPriority(Integer.valueOf(priority));
+ for (MatchBuilder match : matches) {
+ Match m = match.build();
+ FlowId flowId = new FlowId(baseId + "|" + m.toString());
+ flow.setMatch(m)
+ .setId(flowId)
+ .setPriority(Integer.valueOf(priority));
+ if (visit(flowMap, flowId.getValue())) {
+ LOG.info("{} {} {} {}", p.sepg, p.scgId, p.depg, p.dcgId);
+ writeFlow(t, tiid, flow.build());
+ }
+ }
+ }
- @Override
- public short getTableId() {
- return TABLE_ID;
}
+ @Immutable
+ private static class CgPair {
+ private final int sepg;
+ private final int depg;
+ private final int scgId;
+ private final int dcgId;
+
+ public CgPair(int sepg, int depg, int scgId, int dcgId) {
+ super();
+ this.sepg = sepg;
+ this.depg = depg;
+ this.scgId = scgId;
+ this.dcgId = dcgId;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + dcgId;
+ result = prime * result + depg;
+ result = prime * result + scgId;
+ result = prime * result + sepg;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ CgPair other = (CgPair) obj;
+ if (dcgId != other.dcgId)
+ return false;
+ if (depg != other.depg)
+ return false;
+ if (scgId != other.scgId)
+ return false;
+ if (sepg != other.sepg)
+ return false;
+ return true;
+ }
+ }
}
import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
+import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
public void sync(ReadWriteTransaction t,
InstanceIdentifier<Table> tiid,
Map<String, FlowCtx> flowMap,
- NodeId nodeId, Dirty dirty) {
+ NodeId nodeId, PolicyInfo policyInfo, Dirty dirty) {
// Allow traffic from tunnel and external ports
NodeConnectorId tunnelIf = ctx.switchManager.getTunnelPort(nodeId);
if (tunnelIf != null)
dropFlow(t, tiid, flowMap, 111, FlowUtils.IPv4);
dropFlow(t, tiid, flowMap, 112, FlowUtils.IPv6);
- for (Endpoint e : ctx.endpointManager.getEndpointsForNode(nodeId)) {
+ for (Endpoint e : ctx.epManager.getEndpointsForNode(nodeId)) {
OfOverlayContext ofc = e.getAugmentation(OfOverlayContext.class);
if (ofc != null && ofc.getNodeConnectorId() != null &&
(ofc.getLocationType() == null ||
writeFlow(t, tiid, flowb.build());
}
}
-
- private void dropFlow(ReadWriteTransaction t,
- InstanceIdentifier<Table> tiid,
- Map<String, FlowCtx> flowMap,
- Integer priority, Long etherType) {
- FlowId flowid = new FlowId(new StringBuilder()
- .append("drop|")
- .append(etherType)
- .toString());
- if (visit(flowMap, flowid.getValue())) {
- FlowBuilder flowb = base()
- .setId(flowid)
- .setPriority(priority)
- .setInstructions(FlowUtils.dropInstructions());
- if (etherType != null)
- flowb.setMatch(new MatchBuilder()
- .setEthernetMatch(FlowUtils.ethernetMatch(null, null,
- etherType))
- .build());
- writeFlow(t, tiid, flowb.build());
- }
- }
-
+
private void l2flow(ReadWriteTransaction t,
InstanceIdentifier<Table> tiid,
Map<String, FlowCtx> flowMap,
writeFlow(t, tiid, flowb.build());
}
}
-
private void l3flow(ReadWriteTransaction t,
InstanceIdentifier<Table> tiid,
package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
+import java.util.List;
import java.util.Map;
import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
+import org.opendaylight.groupbasedpolicy.resolver.ConditionGroup;
+import org.opendaylight.groupbasedpolicy.resolver.EgKey;
import org.opendaylight.groupbasedpolicy.resolver.IndexedTenant;
+import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.EndpointLocation.LocationType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Manage the table that assigns source endpoint group, bridge domain, and
* @author readams
*/
public class SourceMapper extends FlowTable {
+ protected static final Logger LOG =
+ LoggerFactory.getLogger(SourceMapper.class);
+
public static final short TABLE_ID = 1;
public SourceMapper(FlowTableCtx ctx) {
public void sync(ReadWriteTransaction t,
InstanceIdentifier<Table> tiid,
Map<String, FlowCtx> flowMap,
- NodeId nodeId, Dirty dirty) throws Exception {
+ NodeId nodeId, PolicyInfo policyInfo,
+ Dirty dirty) throws Exception {
+ dropFlow(t, tiid, flowMap, Integer.valueOf(1), null);
+
// XXX TODO Set sEPG from tunnel ports using the tunnel ID
- for (Endpoint e : ctx.endpointManager.getEndpointsForNode(nodeId)) {
+ for (Endpoint e : ctx.epManager.getEndpointsForNode(nodeId)) {
OfOverlayContext ofc = e.getAugmentation(OfOverlayContext.class);
if (ofc != null && ofc.getNodeConnectorId() != null &&
(ofc.getLocationType() == null ||
LocationType.Internal.equals(ofc.getLocationType())) &&
e.getTenant() != null && e.getEndpointGroup() != null) {
- syncEP(t, tiid, flowMap, nodeId, e, ofc);
+ syncEP(t, tiid, flowMap, policyInfo, nodeId, e, ofc);
}
}
}
private void syncEP(ReadWriteTransaction t,
InstanceIdentifier<Table> tiid,
Map<String, FlowCtx> flowMap,
+ PolicyInfo policyInfo,
NodeId nodeId, Endpoint e, OfOverlayContext ofc)
throws Exception {
// Set sEPG, flood domain, bridge domain, and layer 3 context
L2BridgeDomain bd = tenant.resolveL2BridgeDomain(eg.getNetworkDomain());
L2FloodDomain fd = tenant.resolveL2FloodDomain(eg.getNetworkDomain());
- int egId = 0, bdId = 0, fdId = 0, l3Id = 0;
+ int egId = 0, bdId = 0, fdId = 0, l3Id = 0, cgId = 0;
egId = ctx.policyManager.getContextOrdinal(e.getTenant(),
e.getEndpointGroup());
if (l3c != null)
l3Id = ctx.policyManager.getContextOrdinal(e.getTenant(),
l3c.getId());
- // TODO set source condition set ID as well
+ List<ConditionName> conds = ctx.epManager.getCondsForEndpoint(e);
+ ConditionGroup cg =
+ policyInfo.getEgCondGroup(new EgKey(e.getTenant(),
+ e.getEndpointGroup()),
+ conds);
+ cgId = ctx.policyManager.getConfGroupOrdinal(cg);
FlowId flowid = new FlowId(new StringBuilder()
.append(ofc.getNodeConnectorId())
.append(fdId)
.append("|")
.append(l3Id)
+ .append("|")
+ .append(cgId)
.toString());
if (visit(flowMap, flowid.getValue())) {
- LOG.info("{} eg:{} bd:{} fd:{} vrf:{}",
- e.getMacAddress(), egId, bdId, fdId, l3Id);
+ LOG.info("{} seg:{} bd:{} fd:{} vrf:{} scg:{}",
+ e.getMacAddress(), egId, bdId, fdId, l3Id, cgId);
FlowBuilder flowb = base()
.setPriority(Integer.valueOf(100))
.setId(flowid)
null, null))
.setInPort(ofc.getNodeConnectorId())
.build())
- // XXX TODO set sepg, bd, fd, vrf into registers
+ // XXX TODO set sepg, bd, fd, vrf, scg into registers
.setInstructions(FlowUtils.gotoTableInstructions((short)(TABLE_ID + 1)));
writeFlow(t, tiid, flowb.build());
}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
+
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
+
+/**
+ * Represent a classifier definition, and provide tools for generating flow
+ * rules based on the classifier
+ * @author readams
+ */
+public abstract class Classifier {
+ /**
+ * Get the classifier definition for this classifier
+ * @return the {@link ClassifierDefinition} for this classifier
+ */
+ public abstract ClassifierDefinitionId getId();
+
+ /**
+ * Get the classifier definition for this classifier
+ * @return the {@link ClassifierDefinition} for this classifier
+ */
+ public abstract ClassifierDefinition getClassDef();
+
+ /**
+ * Construct a set of matches that will apply to the traffic. Augment
+ * the existing list of matches or add new matches. It's important
+ * that the order of the returned list be consistent however
+ * @param matches The existing matches
+ * @param params the parameters for the classifier instance
+ * @return the updated list of matches (may be a different length)
+ */
+ public abstract List<MatchBuilder> updateMatch(List<MatchBuilder> matches,
+ Map<String, Object> params);
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
+
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.ParameterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.IsRequired;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.Type;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinitionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetTypeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Match on the ether type of the traffic
+ */
+public class EtherTypeClassifier extends Classifier {
+ public static final ClassifierDefinitionId ID =
+ new ClassifierDefinitionId("6a48ab45-a462-429d-b18c-3a575b2c8bef");
+ protected static final String TYPE = "type";
+ protected static final ClassifierDefinition DEF =
+ new ClassifierDefinitionBuilder()
+ .setId(ID)
+ .setName(new ClassifierName("ether_type"))
+ .setDescription(new Description("Match on the ether type of the traffic"))
+ .setParameter(ImmutableList.of(new ParameterBuilder()
+ .setName(new ParameterName(TYPE))
+ .setDescription(new Description("The ethertype to match against"))
+ .setIsRequired(IsRequired.Required)
+ .setType(Type.Int)
+ .build()))
+ .build();
+
+ @Override
+ public ClassifierDefinitionId getId() {
+ return ID;
+ }
+
+ @Override
+ public ClassifierDefinition getClassDef() {
+ return DEF;
+ }
+
+ @Override
+ public List<MatchBuilder> updateMatch(List<MatchBuilder> matches,
+ Map<String, Object> params) {
+ Object t = params.get(TYPE);
+ // XXX TODO generate exception and fail the match
+ if (t == null || !(t instanceof Long)) return matches;
+ Long type = (Long)t;
+ for (MatchBuilder match : matches) {
+ EthernetMatchBuilder em;
+ if (match.getEthernetMatch() != null)
+ em = new EthernetMatchBuilder(match.getEthernetMatch());
+ else
+ em = new EthernetMatchBuilder();
+ em.setEthernetType(new EthernetTypeBuilder()
+ .setType(new EtherType(type)).build());
+ match.setEthernetMatch(em.build());
+ }
+ return matches;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.ParameterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.IsRequired;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.Type;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinitionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.IpMatchBuilder;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Match on the IP protocol of IP traffic
+ */
+public class IpProtoClassifier extends EtherTypeClassifier {
+ public static final ClassifierDefinitionId ID =
+ new ClassifierDefinitionId("79c6fdb2-1e1a-4832-af57-c65baf5c2335");
+ protected static final String PROTO = "proto";
+ protected static final ClassifierDefinition DEF =
+ new ClassifierDefinitionBuilder()
+ .setId(ID)
+ .setParent(EtherTypeClassifier.ID)
+ .setName(new ClassifierName("ip_proto"))
+ .setDescription(new Description("Match on the IP protocol of IP traffic"))
+ .setParameter(ImmutableList.of(new ParameterBuilder()
+ .setName(new ParameterName(PROTO))
+ .setDescription(new Description("The IP protocol to match against"))
+ .setIsRequired(IsRequired.Required)
+ .setType(Type.Int)
+ .build()))
+ .build();
+
+ private static final Map<String, Object> ipv4 =
+ ImmutableMap.<String,Object>of(TYPE, FlowUtils.IPv4);
+ private static final Map<String, Object> ipv6 =
+ ImmutableMap.<String,Object>of(TYPE, FlowUtils.IPv6);
+
+ @Override
+ public ClassifierDefinitionId getId() {
+ return ID;
+ }
+
+ @Override
+ public ClassifierDefinition getClassDef() {
+ return DEF;
+ }
+
+ @Override
+ public List<MatchBuilder> updateMatch(List<MatchBuilder> matches,
+ Map<String, Object> params) {
+ Object t = params.get(PROTO);
+ // XXX TODO generate exception and fail the match
+ if (t == null || !(t instanceof Long)) return matches;
+ Long proto = (Long)t;
+
+ ArrayList<MatchBuilder> r = new ArrayList<>();
+ for (MatchBuilder b : matches) {
+ r.addAll(updateMatch(new MatchBuilder(b.build()), proto, ipv4));
+ r.addAll(updateMatch(new MatchBuilder(b.build()), proto, ipv6));
+ }
+ return r;
+ }
+
+ private List<MatchBuilder> updateMatch(MatchBuilder match,
+ Long proto,
+ Map<String, Object> parentParams) {
+ List<MatchBuilder> r =
+ super.updateMatch(Collections.singletonList(match),
+ parentParams);
+ for (MatchBuilder mb : r) {
+ IpMatchBuilder imb;
+ if (mb.getIpMatch() != null)
+ imb = new IpMatchBuilder(mb.getIpMatch());
+ else
+ imb = new IpMatchBuilder();
+ imb.setIpProtocol(proto.shortValue());
+ mb.setIpMatch(imb.build());
+ }
+ return r;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
+
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.IsRequired;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.Type;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.ParameterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinitionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatchBuilder;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Match against TCP or UDP, and source and/or destination ports
+ * @author readams
+ */
+public class L4Classifier extends IpProtoClassifier {
+ public static final ClassifierDefinitionId ID =
+ new ClassifierDefinitionId("4250ab32-e8b8-445a-aebb-e1bd2cdd291f");
+ private static final String SPORT = "sourceport";
+ private static final String DPORT = "destport";
+ private static final ClassifierDefinition DEF =
+ new ClassifierDefinitionBuilder()
+ .setId(new ClassifierDefinitionId("4250ab32-e8b8-445a-aebb-e1bd2cdd291f"))
+ .setParent(IpProtoClassifier.ID)
+ .setName(new ClassifierName("l4"))
+ .setDescription(new Description("Match on the port number of UDP or TCP traffic"))
+ .setParameter(ImmutableList.of(new ParameterBuilder()
+ .setName(new ParameterName(SPORT))
+ .setDescription(new Description("The source port number to match against"))
+ .setType(Type.Int)
+ .build(),
+ new ParameterBuilder()
+ .setName(new ParameterName(DPORT))
+ .setDescription(new Description("The destination port number to match against"))
+ .setType(Type.Int)
+ .build(),
+ new ParameterBuilder()
+ .setName(new ParameterName(TYPE))
+ .setDescription(new Description("TCP or UDP"))
+ .setIsRequired(IsRequired.Required)
+ .setType(Type.String)
+ .build()))
+ .build();
+
+ private static final Map<String, Object> tcp =
+ ImmutableMap.<String,Object>of(PROTO, Long.valueOf(6));
+ private static final Map<String, Object> udp =
+ ImmutableMap.<String,Object>of(PROTO, Long.valueOf(17));
+
+ @Override
+ public ClassifierDefinitionId getId() {
+ return ID;
+ }
+
+ @Override
+ public ClassifierDefinition getClassDef() {
+ return DEF;
+ }
+
+ @Override
+ public List<MatchBuilder> updateMatch(List<MatchBuilder> matches,
+ Map<String, Object> params) {
+ Object t = params.get(TYPE);
+ // XXX TODO generate exception and fail the match
+ if (t == null || !(t instanceof String)) return matches;
+ String type = (String)t;
+
+ if ("UDP".equals(type))
+ matches = super.updateMatch(matches, udp);
+ else
+ matches = super.updateMatch(matches, tcp);
+
+ Long sport = null;
+ Long dport = null;
+ t = params.get(SPORT);
+ if (t != null && (t instanceof Long))
+ sport = (Long)t;
+ t = params.get(DPORT);
+ if (t != null && (t instanceof Long))
+ dport = (Long)t;
+
+ for (MatchBuilder b : matches) {
+ if ("UDP".equals(type)) {
+ UdpMatchBuilder m = new UdpMatchBuilder();
+ if (sport != null)
+ m.setUdpSourcePort(new PortNumber(sport.intValue()));
+ if (dport != null)
+ m.setUdpDestinationPort(new PortNumber(dport.intValue()));
+ b.setLayer4Match(m.build());
+ } else {
+ TcpMatchBuilder m = new TcpMatchBuilder();
+ if (sport != null)
+ m.setTcpSourcePort(new PortNumber(sport.intValue()));
+ if (dport != null)
+ m.setTcpDestinationPort(new PortNumber(dport.intValue()));
+ b.setLayer4Match(m.build());
+ }
+ }
+ return matches;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
+
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.SubjectFeatureDefinitions;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.SubjectFeatureDefinitionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinition;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinitionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Defines the subject features that are supported by the OF overlay renderer
+ */
+public class SubjectFeatures {
+ private static final Map<ClassifierDefinitionId, Classifier> classifiers =
+ ImmutableMap.<ClassifierDefinitionId, Classifier>
+ of(EtherTypeClassifier.ID, new EtherTypeClassifier(),
+ IpProtoClassifier.ID, new IpProtoClassifier(),
+ L4Classifier.ID, new L4Classifier());
+
+ private static final List<ClassifierDefinition> classifierDefs =
+ ImmutableList.copyOf(Collections2.transform(classifiers.values(),
+ new Function<Classifier, ClassifierDefinition>() {
+ @Override
+ public ClassifierDefinition apply(Classifier input) {
+ return input.getClassDef();
+ }
+ }
+ ));
+
+ public static final ActionDefinition ALLOW =
+ new ActionDefinitionBuilder()
+ .setId(new ActionDefinitionId("f942e8fd-e957-42b7-bd18-f73d11266d17"))
+ .setName(new ActionName("allow"))
+ .setDescription(new Description("Allow the specified traffic to pass"))
+ .build();
+
+ public static final SubjectFeatureDefinitions OF_OVERLAY_FEATURES =
+ new SubjectFeatureDefinitionsBuilder()
+ .setActionDefinition(ImmutableList.of(ALLOW))
+ .setClassifierDefinition(classifierDefs)
+ .build();
+
+ /**
+ * Get the {@link Classifier} associated with the given
+ * {@link ClassifierDefinitionId}
+ * @param id the {@link ClassifierDefinitionId} to look up
+ * @return the {@link Classifier} if one exists, or <code>null</code>
+ * otherwise
+ */
+ public static Classifier getClassifier(ClassifierDefinitionId id) {
+ return classifiers.get(id);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.resolver;
+
+import java.util.Collections;
+import java.util.Set;
+
+import javax.annotation.concurrent.Immutable;
+
+/**
+ * A condition group is a unique set of conditions that are active for a
+ * particular endpoint group. Because of the potential for combinatorial
+ * explosion with condition matchers, we only keep track of the combinations
+ * that are active for a particular endpoint group.
+ * @author readams
+ */
+@Immutable
+public class ConditionGroup {
+ public static final ConditionGroup EMPTY =
+ new ConditionGroup(Collections.<ConditionSet>emptySet());
+
+ private final Set<ConditionSet> conditionSets;
+ private final int hashCode;
+
+ public ConditionGroup(Set<ConditionSet> conditionSets) {
+ super();
+ this.conditionSets = Collections.unmodifiableSet(conditionSets);
+ hashCode = computeHashCode();
+ }
+
+ /**
+ * Check whether the given condition set is in this condition group
+ * @param cs the condition set to check
+ * @return <code>true</code> if the condition set is a member of this
+ * condition group
+ */
+ public boolean contains(ConditionSet cs) {
+ return conditionSets.contains(cs);
+ }
+
+ private int computeHashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result +
+ ((conditionSets == null) ? 0 : conditionSets.hashCode());
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ return hashCode;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ConditionGroup other = (ConditionGroup) obj;
+ if (conditionSets == null) {
+ if (other.conditionSets != null)
+ return false;
+ } else if (!conditionSets.equals(other.conditionSets))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "ConditionGroup [conditionSets=" + conditionSets + "]";
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.resolver;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.concurrent.Immutable;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
+
+/**
+ * Represents a set of conditions for endpoint groups. For an endpoint
+ * to match the condition set, all the conditions in "all" must match,
+ * and none of the conditions in "none" can match. Additionally, in
+ * each set of "any" conditions, at least one condition must match.
+ * Note that if all sets are empty, then the condition set matches
+ * automatically
+ * @author readams
+ */
+@Immutable
+public class ConditionSet {
+ private final Set<ConditionName> all;
+ private final Set<ConditionName> none;
+ private final Set<? extends Set<ConditionName>> any;
+ private final int hashCode;
+
+ public static final ConditionSet EMPTY =
+ new ConditionSet(Collections.<ConditionName>emptySet(),
+ Collections.<ConditionName>emptySet(),
+ Collections.<Set<ConditionName>>emptySet());
+
+ public ConditionSet(Set<ConditionName> all,
+ Set<ConditionName> none,
+ Set<? extends Set<ConditionName>> any) {
+ super();
+ this.all = all;
+ this.none = none;
+ this.any = any;
+ this.hashCode = computeHashCode();
+ }
+
+ /**
+ * Check if the condition set matches against the given list of conditions
+ * for a particular endpoint
+ * @param conditions the list of conditions
+ * @return <code>true</code> if the condition set matches the conditions
+ */
+ public boolean matches(List<ConditionName> conditions) {
+ Set<ConditionName> matching = new HashSet<>();
+ Set<Set<ConditionName>> anyMatch = new HashSet<>();
+ for (ConditionName name : conditions) {
+ if (none.contains(name)) return false;
+ if (all.contains(name)) matching.add(name);
+ for (Set<ConditionName> anyItem : any) {
+ if (anyItem.contains(name)) anyMatch.add(anyItem);
+ }
+ }
+ if (all.size() != matching.size()) return false;
+ if (any.size() != anyMatch.size()) return false;
+ return true;
+ }
+
+ private int computeHashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((all == null) ? 0 : all.hashCode());
+ result = prime * result + ((any == null) ? 0 : any.hashCode());
+ result = prime * result + ((none == null) ? 0 : none.hashCode());
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ return hashCode;
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ConditionSet other = (ConditionSet) obj;
+ if (all == null) {
+ if (other.all != null)
+ return false;
+ } else if (!all.equals(other.all))
+ return false;
+ if (any == null) {
+ if (other.any != null)
+ return false;
+ } else if (!any.equals(other.any))
+ return false;
+ if (none == null) {
+ if (other.none != null)
+ return false;
+ } else if (!none.equals(other.none))
+ return false;
+ return true;
+ }
+ @Override
+ public String toString() {
+ return "ConditionSet [all=" + all + ", none=" + none + ", any=" +
+ any + "]";
+ }
+}
\ No newline at end of file
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.Ordering;
+
/**
* A tuple referencing an endpoint group and its enclosing tenant
* @author readams
*/
@Immutable
-public class EgKey {
+public class EgKey implements Comparable<EgKey> {
private final TenantId tenantId;
private final EndpointGroupId egId;
@Override
this.tenantId = tenantId;
this.egId = egId;
}
+
+ @Override
+ public int compareTo(EgKey o) {
+ String tid = null;
+ if (tenantId != null) tid = tenantId.getValue();
+ String otid = null;
+ if (o.tenantId != null) otid = o.tenantId.getValue();
+ String egid = null;
+ if (egId != null) tid = egId.getValue();
+ String oegid = null;
+ if (o.egId != null) oegid = o.egId.getValue();
+ return ComparisonChain.start()
+ .compare(tid, otid,
+ Ordering.natural().nullsLast())
+ .compare(egid, oegid,
+ Ordering.natural().nullsLast())
+ .result();
+ }
+
@Override
public String toString() {
return "EgKey [tenantId=" + tenantId + ", egId=" + egId + "]";
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.resolver;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+
+/**
+ * When the policy changes, recompute the set of active condition groups
+ * based on the endpoints in a particular endpoint group
+ * @author readams
+ */
+public interface EndpointProvider {
+ /**
+ * Get a collection of endpoints in a particular endpoint group
+ * @param nodeId the nodeId of the switch to get endpoints for
+ * @return a collection of {@link Endpoint} objects.
+ */
+ public Collection<Endpoint> getEndpointsForGroup(EgKey eg);
+
+ /**
+ * Get the effective list of conditions that apply to a particular
+ * endpoint. This could include additional conditions over the condition
+ * labels directly represented in the endpoint object
+ * @param endpoint the {@link Endpoint} to resolve
+ * @return the list of {@link ConditionName}
+ */
+ public List<ConditionName> getCondsForEndpoint(Endpoint endpoint);
+}
import javax.annotation.concurrent.Immutable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomain;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2FloodDomain;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.SubjectFeatureInstances;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Subnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstance;
/**
* Wrap some convenient indexes around a {@link Tenant} object
new HashMap<>();
private final Map<String, NetworkDomain> networkDomains =
new HashMap<>();
+ private final Map<ClassifierName, ClassifierInstance> classifiers =
+ new HashMap<>();
+ private final Map<ActionName, ActionInstance> actions =
+ new HashMap<>();
public IndexedTenant(Tenant tenant) {
super();
networkDomains.put(s.getId().getValue(), s);
}
}
+ if (tenant.getSubjectFeatureInstances() != null) {
+ SubjectFeatureInstances sfi = tenant.getSubjectFeatureInstances();
+ if (sfi.getClassifierInstance() != null) {
+ for (ClassifierInstance ci : sfi.getClassifierInstance()) {
+ classifiers.put(ci.getName(), ci);
+ }
+ }
+ if (sfi.getActionInstance() != null) {
+ for (ActionInstance action : sfi.getActionInstance()) {
+ actions.put(action.getName(), action);
+ }
+ }
+ }
}
/**
public Contract getContract(ContractId id) {
return contracts.get(id);
}
+
+ /**
+ * Look up the classifier instance specified
+ * @param name the {@link ClassifierName}
+ * @return the {@link ClassifierInstance} if it exists, or <code>null</code>
+ * otherwise
+ */
+ public ClassifierInstance getClassifier(ClassifierName name) {
+ return classifiers.get(name);
+ }
+
+ /**
+ * Look up the classifier instance specified
+ * @param name the {@link ActionName}
+ * @return the {@link ActionInstance} if it exists, or <code>null</code>
+ * otherwise
+ */
+ public ActionInstance getAction(ActionName name) {
+ return actions.get(name);
+ }
/**
* Get the layer 3 context for the specified network domain by walking
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.resolver;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.annotation.concurrent.Immutable;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Contract;
+
+import com.google.common.collect.ImmutableTable;
+import com.google.common.collect.Table;
+import com.google.common.collect.Table.Cell;
+
+/**
+ * Represent the policy that applies to a single pair of endpoint groups
+ * The policy is represented as a list of {@link RuleGroup} objects. A
+ * {@link RuleGroup} references ordered lists of rules from the policy,
+ * along with the associated {@link Tenant}, {@link Contract}, and
+ * {@link SubjectName}.
+ *
+ * A {@link RuleGroup} applies to a particular endpoint based on the set of
+ * conditions that are active for that endpoint. All rule groups associated
+ * with matching {@link ConditionSet}s apply.
+ * @author readams
+ */
+@Immutable
+public class Policy {
+ public static final Policy EMPTY =
+ new Policy(ImmutableTable.<ConditionSet, ConditionSet,
+ List<RuleGroup>>of());
+
+ final Table<ConditionSet, ConditionSet, List<RuleGroup>> ruleMap;
+ final boolean reversed;
+ public Policy(Table<ConditionSet, ConditionSet, List<RuleGroup>> ruleMap) {
+ super();
+ this.ruleMap = ruleMap;
+ this.reversed = false;
+ }
+ public Policy(Policy existing, boolean reversed) {
+ super();
+ this.ruleMap = existing.ruleMap;
+ this.reversed = existing.reversed != reversed;
+ }
+
+ @Override
+ public String toString() {
+ return "Policy [ruleMap=" + ruleMap + "]";
+ }
+
+ /**
+ * Get the rules that apply to a particular pair of condition groups
+ * @param fromCg the condition group that applies to the origin endpoint
+ * @param toCg the condition group that applies to the destination endpoint
+ * @return
+ */
+ public List<RuleGroup> getRules(ConditionGroup fromCg,
+ ConditionGroup toCg) {
+ ArrayList<RuleGroup> rules = new ArrayList<>();
+ for (Cell<ConditionSet, ConditionSet, List<RuleGroup>> cell : ruleMap.cellSet()) {
+ if (fromCg.contains(cell.getRowKey()) &&
+ toCg.contains(cell.getColumnKey()))
+ rules.addAll(cell.getValue());
+ }
+ Collections.sort(rules);
+ return rules;
+ }
+}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.groupbasedpolicy.resolver;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicReference;
-
-import javax.annotation.concurrent.Immutable;
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
-
-import com.google.common.collect.Table;
-import com.google.common.collect.Table.Cell;
-
-/**
- * Represent the policy relationships between endpoint groups
- * @author readams
- *
- */
-class PolicyCache {
-
- /**
- * Store a policy object for each endpoint group pair. The table
- * is stored with the key as (consumer, provider). Two endpoints could
- * appear in both roles at the same time, in which case both policies would
- * apply.
- */
- AtomicReference<Table<EgKey, EgKey, Policy>> policy =
- new AtomicReference<>();
-
- // ***************
- // PolicyCache API
- // ***************
-
- /**
- * Lookup a policy in the cache
- */
- protected List<RuleGroup> getPolicy(TenantId ep1Tenant,
- EndpointGroupId ep1Group,
- ConditionSet ep1Conds,
- TenantId ep2Tenant,
- EndpointGroupId ep2Group,
- ConditionSet ep2Conds) {
- EgKey k1 = new EgKey(ep1Tenant, ep1Group);
- EgKey k2 = new EgKey(ep2Tenant, ep2Group);
- Policy p = policy.get().get(k1, k2);
- if (p == null) return Collections.emptyList();
- List<RuleGroup> result = p.ruleMap.get(ep1Conds, ep2Conds);
- if (result == null) return Collections.emptyList();
- return result;
- }
-
- /**
- * Get the set of providers that have contracts with the consumer
- * @param tenant the tenant ID for the endpoint group
- * @param eg the endpoint group ID
- */
- protected Set<EgKey> getProvidersForConsumer(TenantId tenant,
- EndpointGroupId eg) {
- if (policy.get() == null) return Collections.emptySet();
- EgKey k = new EgKey(tenant, eg);
- return Collections.unmodifiableSet(policy.get().row(k).keySet());
- }
-
- /**
- * Get the set of providers that apply
- * @param tenant the tenant ID for the endpoint group
- * @param eg the endpoint group ID
- */
- protected Set<EgKey> getConsumersForProvider(TenantId tenant,
- EndpointGroupId eg) {
- if (policy.get() == null) return Collections.emptySet();
- EgKey k = new EgKey(tenant, eg);
- return Collections.unmodifiableSet(policy.get().column(k).keySet());
- }
-
- /**
- * Atomically update the active policy and notify policy listeners
- * of relevant changes
- * @param newPolicy the new policy to set
- * @return the set of consumers with updated policy
- */
- protected Set<EgKey> updatePolicy(Table<EgKey, EgKey, Policy> newPolicy,
- List<PolicyScope> policyListenerScopes) {
- Table<EgKey, EgKey, Policy> oldPolicy = policy.getAndSet(newPolicy);
-
- HashSet<EgKey> notifySet = new HashSet<>();
-
- for (Cell<EgKey, EgKey, Policy> cell : newPolicy.cellSet()) {
- Policy newp = cell.getValue();
- Policy oldp = null;
- if (oldPolicy != null)
- oldp = oldPolicy.get(cell.getRowKey(), cell.getColumnKey());
- if (oldp == null || !newp.equals(oldp)) {
- notifySet.add(cell.getRowKey());
- }
- }
- if (oldPolicy != null) {
- for (Cell<EgKey, EgKey, Policy> cell : oldPolicy.cellSet()) {
- if (!newPolicy.contains(cell.getRowKey(), cell.getColumnKey())) {
- notifySet.add(cell.getRowKey());
- }
- }
- }
- return notifySet;
- }
-
- // **************
- // Helper classes
- // **************
-
- @Immutable
- protected static class Policy {
- final Table<ConditionSet, ConditionSet, List<RuleGroup>> ruleMap;
- public Policy(Table<ConditionSet, ConditionSet, List<RuleGroup>> ruleMap) {
- super();
- this.ruleMap = ruleMap;
- }
- @Override
- public String toString() {
- return "Policy [ruleMap=" + ruleMap + "]";
- }
- }
-
- /**
- * Represents a set of conditions for endpoint groups. For an endpoint
- * to match the condition set, all the conditions in "all" must match,
- * and none of the conditions in "none" can match. Additionally, in
- * each set of "any" conditions, at least one condition must match.
- * Note that if all sets are empty, then the condition set matches
- * automatically
- * @author readams
- */
- @Immutable
- public static class ConditionSet {
- private final Set<ConditionName> all;
- private final Set<ConditionName> none;
- private final Set<? extends Set<ConditionName>> any;
- private final int hashCode;
-
- public static final ConditionSet EMPTY =
- new ConditionSet(Collections.<ConditionName>emptySet(),
- Collections.<ConditionName>emptySet(),
- Collections.<Set<ConditionName>>emptySet());
-
- public ConditionSet(Set<ConditionName> all,
- Set<ConditionName> none,
- Set<? extends Set<ConditionName>> any) {
- super();
- this.all = all;
- this.none = none;
- this.any = any;
- this.hashCode = computeHashCode();
- }
-
- private int computeHashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((all == null) ? 0 : all.hashCode());
- result = prime * result + ((any == null) ? 0 : any.hashCode());
- result = prime * result + ((none == null) ? 0 : none.hashCode());
- return result;
- }
-
- @Override
- public int hashCode() {
- return hashCode;
- }
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- ConditionSet other = (ConditionSet) obj;
- if (all == null) {
- if (other.all != null)
- return false;
- } else if (!all.equals(other.all))
- return false;
- if (any == null) {
- if (other.any != null)
- return false;
- } else if (!any.equals(other.any))
- return false;
- if (none == null) {
- if (other.none != null)
- return false;
- } else if (!none.equals(other.none))
- return false;
- return true;
- }
- @Override
- public String toString() {
- return "ConditionSet [all=" + all + ", none=" + none + ", any=" +
- any + "]";
- }
- }
-}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.resolver;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.concurrent.Immutable;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
+
+import com.google.common.collect.Sets;
+import com.google.common.collect.Table;
+
+/**
+ * Represent the current policy snapshot for the set of tenants that are
+ * in scope
+ * @author readams
+ */
+@Immutable
+public class PolicyInfo {
+ final Table<EgKey, EgKey, Policy> policyMap;
+ final Map<EgKey, Set<ConditionSet>> egConditions;
+
+ public PolicyInfo(Table<EgKey, EgKey, Policy> policyMap,
+ Map<EgKey, Set<ConditionSet>> egConditions) {
+ super();
+ this.policyMap = policyMap;
+ this.egConditions = egConditions;
+ }
+ public Table<EgKey, EgKey, Policy> getPolicyMap() {
+ return policyMap;
+ }
+
+ /**
+ * Get the policy that currently applies to traffic flowing out of
+ * the specified originating endpoint group into the specified destination
+ * endpoint group. Note that there will be policy only for one of the two
+ * possible directions.
+ *
+ * @param fromGroup the endpoint group for the originating endpoint
+ * @param toGroup the endpoint group for the destination endpoint
+ * @return the {@link Policy} that applies. Cannot be null
+ */
+ public Policy getPolicy(EgKey fromGroup, EgKey toGroup) {
+ Policy p = policyMap.get(fromGroup, toGroup);
+ if (p == null) return Policy.EMPTY;
+ return p;
+ }
+
+ /**
+ * Get the condition sets for a particular endpoint group
+ * @param eg the endpoint group
+ * @return the set of condition sets that could apply to an endpoint
+ * in that endpoint group
+ */
+ public Set<ConditionSet> getEgConditions(EgKey eg) {
+ return Collections.unmodifiableSet(egConditions.get(eg));
+ }
+
+ /**
+ * Get the condition group as it applies to the given list of conditions
+ * @param eg
+ * @param conditions
+ * @return
+ */
+ public ConditionGroup getEgCondGroup(EgKey eg,
+ List<ConditionName> conditions) {
+ Set<ConditionSet> egconds = egConditions.get(eg);
+ if (egconds == null) return ConditionGroup.EMPTY;
+ Set<ConditionSet> matching = null;
+ for (ConditionSet cs : egconds) {
+ if (cs.matches(conditions)) {
+ if (matching == null) matching = new HashSet<>();
+ matching.add(cs);
+ }
+ }
+ if (matching == null) return ConditionGroup.EMPTY;
+ return new ConditionGroup(matching);
+ }
+
+ /**
+ * Get the set of endpoint groups that are peers for the given endpoint
+ * group
+ * @param eg the endpoint group
+ * @return the set of endpoint groups
+ */
+ public Set<EgKey> getPeers(EgKey eg) {
+ return Sets.union(policyMap.row(eg).keySet(),
+ policyMap.column(eg).keySet());
+ }
+}
\ No newline at end of file
public interface PolicyListener {
/**
- * Indicates that the policy related to the set of consumer endpoint groups
+ * Indicates that the policy related to the set of endpoint groups
* has changed
- * @param updatedConsumers the set of consumer endpoint groups involved
+ * @param updatedConsumers the set of endpoint groups involved
* in a contract whose policy has changed
*/
- public void policyUpdated(Set<EgKey> updatedConsumers);
+ public void policyUpdated(Set<EgKey> updatedGroups);
}
package org.opendaylight.groupbasedpolicy.resolver;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+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.ConcurrentMap;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.groupbasedpolicy.resolver.PolicyCache.ConditionSet;
-import org.opendaylight.groupbasedpolicy.resolver.PolicyCache.Policy;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.ConsumerSelectionRelator;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.Matcher.MatchType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.ProviderSelectionRelator;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRefBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.condition.matchers.ConditionMatcher;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.conditions.Condition;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.target.selector.QualityMatcher;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.consumer.matchers.RequirementMatcher;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.provider.matchers.CapabilityMatcher;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.RuleBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerNamedSelector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerTargetSelector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderNamedSelector;
* list of rules that apply to a given pair of endpoints depends on the
* conditions that are active on the endpoints.
*
- * In a more formal sense: Let there be endpoint groups G_n, and for each G_n a
- * set of conditions C_n that can apply to endpoints in G_n. Further, let S be
- * the set of lists of rules defined in the policy. Our policy can be
- * represented as a function F: (G_n, 2^C_n, G_m, 2^C_m) -> S, where 2^C_n
- * represents the power set of C_n. In other words, we want to map all the
- * possible tuples of pairs of endpoints along with their active conditions
- * onto the right list of rules to apply.
- *
* <p>We need to be able to query against this policy model, enumerate the
* relevant classes of traffic and endpoints, and notify renderers when there
* are changes to policy as it applies to active sets of endpoints and
protected ConcurrentMap<TenantId, TenantContext> resolvedTenants;
- protected PolicyCache policyCache = new PolicyCache();
+ /**
+ * Store a policy object for each endpoint group pair. The table
+ * is stored with the key as (consumer, provider). Two endpoints could
+ * appear in both roles at the same time, in which case both policies would
+ * apply.
+ */
+ AtomicReference<PolicyInfo> policy = new AtomicReference<>();
public PolicyResolver(DataBroker dataProvider,
ScheduledExecutorService executor) {
// *************************
/**
- * Get the policy that currently applies to a pair of endpoints.
- * with the specified groups and conditions. The first endpoint acts as
- * the consumer and the second endpoint acts as the provider, so to get
- * all policy related to this pair of endpoints you must call this
- * function twice: once for each possible order of endpoints.
- *
- * @param ep1Tenant the tenant ID for the first endpoint
- * @param ep1Group the endpoint group for the first endpoint
- * @param ep1Conds The conditions that apply to the first endpoint
- * @param ep2Tenant the tenant ID for the second endpoint
- * @param ep2Group the endpoint group for the second endpoint
- * @param ep2Conds The conditions that apply to the second endpoint.
- * @return a list of {@link RuleGroup} that apply to the endpoints.
- * Cannot be null, but may be an empty list of rulegroups
+ * Get a snapshot of the current policy
+ * @return the {@link PolicyInfo} object representing an immutable
+ * snapshot of the policy state
*/
- public List<RuleGroup> getPolicy(TenantId ep1Tenant,
- EndpointGroupId ep1Group,
- ConditionSet ep1Conds,
- TenantId ep2Tenant,
- EndpointGroupId ep2Group,
- ConditionSet ep2Conds) {
- return policyCache.getPolicy(ep1Tenant, ep1Group, ep1Conds,
- ep2Tenant, ep2Group, ep2Conds);
+ public PolicyInfo getCurrentPolicy() {
+ return policy.get();
}
- /**
- * Get the set of providers that have contracts with the consumer
- * @param tenant the tenant ID for the endpoint group
- * @param eg the endpoint group ID
- */
- public Set<EgKey> getProvidersForConsumer(TenantId tenant,
- EndpointGroupId eg) {
- return policyCache.getProvidersForConsumer(tenant, eg);
- }
-
- /**
- * Get the set of providers that apply
- * @param tenant the tenant ID for the endpoint group
- * @param eg the endpoint group ID
- */
- public Set<EgKey> getConsumersForProvider(TenantId tenant,
- EndpointGroupId eg) {
- return policyCache.getConsumersForProvider(tenant, eg);
- }
-
+
/**
* Get the normalized tenant for the given ID
* @param tenant the tenant ID
// **************
/**
- * Notify the policy listeners about a set of updated consumers
+ * Atomically update the active policy and notify policy listeners
+ * of relevant changes
+ * @param policyMap the new policy to set
+ * @param egConditions the map of endpoint groups to relevant condition sets
+ * @return the set of groups with updated policy
*/
- private void notifyListeners(Set<EgKey> updatedConsumers) {
+ protected Set<EgKey> updatePolicy(Table<EgKey, EgKey, Policy> policyMap,
+ Map<EgKey, Set<ConditionSet>> egConditions,
+ List<PolicyScope> policyListenerScopes) {
+ PolicyInfo newPolicy = new PolicyInfo(policyMap, egConditions);
+ PolicyInfo oldPolicy = policy.getAndSet(newPolicy);
+
+ HashSet<EgKey> notifySet = new HashSet<>();
+
+ for (Cell<EgKey, EgKey, Policy> cell : newPolicy.getPolicyMap().cellSet()) {
+ Policy newp = cell.getValue();
+ Policy oldp = null;
+ if (oldPolicy != null)
+ oldp = oldPolicy.getPolicyMap().get(cell.getRowKey(),
+ cell.getColumnKey());
+ if (oldp == null || !newp.equals(oldp)) {
+ notifySet.add(cell.getRowKey());
+ notifySet.add(cell.getColumnKey());
+ }
+ }
+ if (oldPolicy != null) {
+ for (Cell<EgKey, EgKey, Policy> cell : oldPolicy.getPolicyMap().cellSet()) {
+ if (!newPolicy.getPolicyMap().contains(cell.getRowKey(),
+ cell.getColumnKey())) {
+ notifySet.add(cell.getRowKey());
+ notifySet.add(cell.getColumnKey());
+ }
+ }
+ }
+ return notifySet;
+ }
+
+ /**
+ * Notify the policy listeners about a set of updated groups
+ */
+ private void notifyListeners(Set<EgKey> updatedGroups) {
for (final PolicyScope scope : policyListenerScopes) {
Set<EgKey> filtered =
- Sets.filter(updatedConsumers, new Predicate<EgKey>() {
+ Sets.filter(updatedGroups, new Predicate<EgKey>() {
@Override
public boolean apply(EgKey input) {
return scope.contains(input.getTenantId(),
// context
registration.close();
context = oldContext;
+ } else {
+ LOG.info("Added tenant {} to policy scope", tenantId);
}
}
final IndexedTenant ot = tenantRef.get();
ReadOnlyTransaction transaction =
dataProvider.newReadOnlyTransaction();
- InstanceIdentifier<Tenant> tiid = TenantUtils.tenantIid(tenantId);
+ final InstanceIdentifier<Tenant> tiid = TenantUtils.tenantIid(tenantId);
ListenableFuture<Optional<Tenant>> unresolved;
unresolved = transaction.read(LogicalDatastoreType.CONFIGURATION, tiid);
Futures.addCallback(unresolved, new FutureCallback<Optional<Tenant>>() {
@Override
public void onSuccess(Optional<Tenant> result) {
- if (!result.isPresent()) return;
+ if (!result.isPresent()) {
+ LOG.warn("Tenant {} not found", tenantId);
+ }
Tenant t = InheritanceUtils.resolveTenant((Tenant)result.get());
IndexedTenant it = new IndexedTenant(t);
updateTenant(tenantId);
} else {
// Update the policy cache and notify listeners
- Table<EgKey, EgKey, Policy> policy = resolvePolicy(t);
- Set<EgKey> updatedConsumers =
- policyCache.updatePolicy(policy, policyListenerScopes);
-
- notifyListeners(updatedConsumers);
+ WriteTransaction wt = dataProvider.newWriteOnlyTransaction();
+ wt.put(LogicalDatastoreType.OPERATIONAL, tiid, t, true);
+ wt.submit();
+ updatePolicy();
}
}
}, executor);
}
-
+ protected void updatePolicy() {
+ try {
+ Map<EgKey, Set<ConditionSet>> egConditions = new HashMap<>();
+ Table<EgKey, EgKey, Policy> policyMap =
+ resolvePolicy(resolvedTenants.values(),
+ egConditions);
+ Set<EgKey> updatedGroups =
+ updatePolicy(policyMap,
+ egConditions,
+ policyListenerScopes);
+
+ notifyListeners(updatedGroups);
+ } catch (Exception e) {
+ LOG.error("Failed to update policy", e);
+ }
+ }
+
/**
* Resolve the policy in three phases:
* (1) select contracts that in scope based on contract selectors.
* apply for each pair of endpoint groups and the conditions that can
* apply for for each endpoint in those groups.
*/
- protected Table<EgKey, EgKey, Policy> resolvePolicy(Tenant t) {
+ protected Table<EgKey, EgKey, Policy>
+ resolvePolicy(Collection<TenantContext> tenants,
+ Map<EgKey, Set<ConditionSet>> egConditions) {
// select contracts that apply for the given tenant
Table<EgKey, EgKey, List<ContractMatch>> contractMatches =
- selectContracts(t);
+ selectContracts(tenants);
// select subjects for the matching contracts and resolve the policy
// for endpoint group pairs. This does phase (2) and (3) as one step
- return selectSubjects(contractMatches);
+ return selectSubjects(contractMatches, egConditions);
}
/**
* groups, then perform subject selection for the pair
*/
protected Table<EgKey, EgKey, List<ContractMatch>>
- selectContracts(Tenant tenant) {
+ selectContracts(Collection<TenantContext> tenants) {
+ Table<TenantId, ContractId,
+ List<ConsumerContractMatch>> consumerMatches =
+ HashBasedTable.create();
+ Table<EgKey, EgKey, List<ContractMatch>> contractMatches =
+ HashBasedTable.create();
+
+ for (TenantContext tenant : tenants) {
+ IndexedTenant t = tenant.tenant.get();
+ if (t == null) continue;
+ selectContracts(consumerMatches,
+ contractMatches,
+ t.getTenant());
+ }
+ return contractMatches;
+ }
+ protected void selectContracts(Table<TenantId,
+ ContractId,
+ List<ConsumerContractMatch>> consumerMatches,
+ Table<EgKey, EgKey,
+ List<ContractMatch>> contractMatches,
+ Tenant tenant) {
// For each endpoint group, match consumer selectors
// against contracts to get a set of matching consumer selectors
- Table<TenantId, ContractId, List<ConsumerContractMatch>> consumerMatches =
- HashBasedTable.create();
- if (tenant.getEndpointGroup() == null) return HashBasedTable.create();
+ if (tenant.getEndpointGroup() == null) return;
for (EndpointGroup group : tenant.getEndpointGroup()) {
List<ConsumerContractMatch> r =
matchConsumerContracts(tenant, group);
// Match provider selectors, and check each match for a corresponding
// consumer selector match.
- Table<EgKey, EgKey, List<ContractMatch>> contractMatches =
- HashBasedTable.create();
for (EndpointGroup group : tenant.getEndpointGroup()) {
List<ContractMatch> matches =
matchProviderContracts(tenant, group, consumerMatches);
egPairMatches.add(cm);
}
}
- return contractMatches;
}
private boolean clauseMatches(Clause clause, ContractMatch match) {
private Policy resolvePolicy(Tenant contractTenant,
Contract contract,
+ boolean reverse,
Policy merge,
- Table<ConditionSet, ConditionSet, List<Subject>> subjectMap) {
+ Table<ConditionSet, ConditionSet,
+ List<Subject>> subjectMap) {
Table<ConditionSet, ConditionSet, List<RuleGroup>> ruleMap =
HashBasedTable.create();
if (merge != null) {
for (Cell<ConditionSet, ConditionSet, List<Subject>> entry :
subjectMap.cellSet()) {
List<RuleGroup> rules = new ArrayList<>();
+ ConditionSet rowKey = entry.getRowKey();
+ ConditionSet columnKey = entry.getColumnKey();
+ if (reverse) {
+ rowKey = columnKey;
+ columnKey = entry.getRowKey();
+ }
List<RuleGroup> oldrules =
- ruleMap.get(entry.getRowKey(), entry.getColumnKey());
+ ruleMap.get(rowKey, columnKey);
if (oldrules != null) {
rules.addAll(oldrules);
}
for (Subject s : entry.getValue()) {
if (s.getRule() == null) continue;
- List<Rule> srules = Ordering
- .from(TenantUtils.RULE_COMPARATOR)
- .immutableSortedCopy(s.getRule());
+ List<Rule> srules;
+ if (reverse)
+ srules = reverseRules(s.getRule());
+ else
+ srules = Ordering
+ .from(TenantUtils.RULE_COMPARATOR)
+ .immutableSortedCopy(s.getRule());
+
RuleGroup rg = new RuleGroup(srules, s.getOrder(),
contractTenant, contract,
s.getName());
rules.add(rg);
}
Collections.sort(rules);
- ruleMap.put(entry.getRowKey(), entry.getColumnKey(),
+ ruleMap.put(rowKey, columnKey,
Collections.unmodifiableList(rules));
}
return new Policy(ruleMap);
}
+
+ private List<Rule> reverseRules(List<Rule> rules) {
+ ArrayList<Rule> nrules = new ArrayList<>();
+ for (Rule input : rules) {
+ if (input.getClassifierRef() == null ||
+ input.getClassifierRef().size() == 0) {
+ nrules.add(input);
+ continue;
+ }
+ List<ClassifierRef> classifiers = new ArrayList<>();
+ for (ClassifierRef clr : input.getClassifierRef()) {
+ Direction nd = Direction.Bidirectional;
+ if (clr.getDirection() != null) {
+ switch (clr.getDirection()) {
+ case In:
+ nd = Direction.Out;
+ break;
+ case Out:
+ nd = Direction.In;
+ break;
+ case Bidirectional:
+ default:
+ nd = Direction.Bidirectional;
+ }
+ }
+ classifiers.add(new ClassifierRefBuilder(clr)
+ .setDirection(nd).build());
+ }
+ nrules.add(new RuleBuilder(input)
+ .setClassifierRef(Collections.unmodifiableList(classifiers))
+ .build());
+ }
+ Collections.sort(nrules, TenantUtils.RULE_COMPARATOR);
+ return Collections.unmodifiableList(nrules);
+ }
+
+ /**
+ * Get the "natural" direction for the policy for the given pair of
+ * endpoint groups.
+ * @param one The first endpoint group
+ * @param two The second endpoint group
+ * @return true if the order should be reversed in the index
+ */
+ protected static boolean shouldReverse(EgKey one, EgKey two) {
+ if (one.compareTo(two) < 0) {
+ return true;
+ }
+ return false;
+ }
+
+ private void addConditionSet(EgKey eg, ConditionSet cs,
+ Map<EgKey, Set<ConditionSet>> egConditions) {
+ if (egConditions == null) return;
+ Set<ConditionSet> cset = egConditions.get(eg);
+ if (cset == null) {
+ egConditions.put(eg, cset = new HashSet<>());
+ }
+ cset.add(cs);
+ }
+
/**
* Choose the set of subjects that in scope for each possible set of
* endpoint conditions
*/
protected Table<EgKey, EgKey, Policy>
selectSubjects(Table<EgKey, EgKey,
- List<ContractMatch>> contractMatches) {
+ List<ContractMatch>> contractMatches,
+ Map<EgKey, Set<ConditionSet>> egConditions) {
// Note that it's possible to further simplify the resulting policy
// in the case of things like repeated rules, condition sets that
// cover other condition sets, etc. This would be a good thing to do
match.consumer.getId());
EgKey pkey = new EgKey(match.providerTenant.getId(),
match.provider.getId());
- Policy existing = policy.get(ckey, pkey);
- boolean alreadyMatched = false;
- if (existing != null) {
- for (List<RuleGroup> rgl : existing.ruleMap.values()) {
- for (RuleGroup rg : rgl) {
- if (rg.relatedContract == match.contract) {
- alreadyMatched = true;
- break;
- }
- }
- if (alreadyMatched) break;
- }
- if (alreadyMatched) continue;
+ EgKey one = ckey;
+ EgKey two = pkey;
+ boolean reverse = shouldReverse(ckey, pkey);
+ if (reverse) {
+ one = pkey;
+ two = ckey;
}
+ Policy existing = policy.get(one, two);
HashMap<SubjectName, Subject> subjects = new HashMap<>();
for (Subject s : subjectList) {
if (clause.getSubjectRefs() != null &&
clauseMatches(clause, match)) {
ConditionSet consCSet = buildConsConditionSet(clause);
+ addConditionSet(ckey, consCSet, egConditions);
ConditionSet provCSet = buildProvConditionSet(clause);
+ addConditionSet(pkey, provCSet, egConditions);
List<Subject> clauseSubjects =
subjectMap.get(consCSet, provCSet);
if (clauseSubjects == null) {
}
}
- policy.put(ckey, pkey,
+ policy.put(one, two,
resolvePolicy(match.contractTenant,
match.contract,
+ reverse,
existing,
subjectMap));
}
}
}
-
}
import com.google.common.collect.Ordering;
/**
- * Represent a group of rules that apply to a given pair of endpoints. Includes
- * references back to the normalized policy that resulted in the rule group.
+ * Represent a group of rules that could apply to a given pair of endpoints.
+ * Includes references back to the normalized policy that resulted in the rule
+ * group.
* @author readams
*/
@Immutable
final Integer order;
final Tenant contractTenant;
final Contract relatedContract;
- final SubjectName relatedSubject;
+ final SubjectName relatedSubject;
public RuleGroup(List<Rule> rules, Integer order,
Tenant contractTenant, Contract contract,
return ComparisonChain.start()
.compare(order, o.order,
Ordering.natural().nullsLast())
+ .compare(relatedSubject.getValue(), o.relatedSubject.getValue(),
+ Ordering.natural().nullsLast())
.result();
}
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.groupbasedpolicy.renderer.ofoverlay;
+package org.opendaylight.groupbasedpolicy.util;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
/**
- * Random utilities
+ * Utility methods related to managing sets and maps
* @author readams
*/
public class SetUtils {
-
- protected static <K1, K2> Set<K2>
+ /**
+ * Get and/or allocate as needed a nested concurrent set inside a concurrent
+ * map in a threadsafe way.
+ * @param key the key to the concurrent map
+ * @param set the concurrent map
+ * @return the nested concurrent set
+ */
+ public static <K1, K2> Set<K2>
getNestedSet(K1 key, ConcurrentMap<K1, Set<K2>> set) {
Set<K2> inner = set.get(key);
if (inner == null) {
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.groupbasedpolicy.renderer.ofoverlay;
+package org.opendaylight.groupbasedpolicy.util;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
description "Objects containing lists of classifier references";
list classifier-ref {
+ key "name";
description
"A reference to classifier instance that is used to match
traffic traveling between the endpoint groups that
form the contract.";
leaf name {
+ description "A unique name for this classifier reference";
+ type gbp-common:classifier-name;
+ mandatory true;
+ }
+
+ leaf instance-name {
description "The name of the classifier instance";
type leafref {
path "/tenants/tenant/subject-feature-instances/classifier-instance/name";
}
mandatory true;
}
- uses has-direction;
uses has-order;
}
}
uses has-requirements;
uses has-capabilities;
+ leaf intra-group-policy {
+ description
+ "Governs how traffic within the endpoint group
+ should be handled.";
+ default allow;
+ type enumeration {
+ enum allow {
+ description
+ "Traffic between two endpoints in the group
+ is always allowed";
+ }
+ enum require-contract {
+ description
+ "Traffic between two endpoints in the group
+ is allowed only when a contract exists to
+ allow it explicitly";
+ }
+ }
+ }
+
list consumer-named-selector {
description
"Consumer named selectors are named selectors
@Test
public void testNoEps() throws Exception {
ReadWriteTransaction t = dosync(null);
- verify(t, never()).put(any(LogicalDatastoreType.class),
- Matchers.<InstanceIdentifier<Flow>>any(),
- any(Flow.class));
+ verify(t, times(1)).put(any(LogicalDatastoreType.class),
+ Matchers.<InstanceIdentifier<Flow>>any(),
+ any(Flow.class));
}
private void verifyDMap(Endpoint remoteEp,
HashMap<String, FlowCtx> flowMap = new HashMap<>();
for (Flow f : ac.getAllValues()) {
flowMap.put(f.getId().getValue(), new FlowCtx(f));
- if (Objects.equals(localEp.getMacAddress(),
+ if (f.getMatch() == null) {
+ assertEquals(FlowUtils.dropInstructions(),
+ f.getInstructions());
+ count += 1;
+ } else if (Objects.equals(localEp.getMacAddress(),
f.getMatch().getEthernetMatch()
.getEthernetDestination().getAddress())) {
int icount = 0;
}
}
}
- assertEquals(4, count);
+ assertEquals(5, count);
t = dosync(flowMap);
verify(t, never()).put(any(LogicalDatastoreType.class),
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.MockEndpointManager;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.MockPolicyManager;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.MockSwitchManager;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.SubjectFeatures;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable.FlowCtx;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable.FlowTableCtx;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.L4Classifier;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures;
import org.opendaylight.groupbasedpolicy.resolver.MockPolicyResolver;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRefBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRefBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValueBuilder;
}
protected TenantBuilder baseTenant() {
+ return baseTenant(null);
+ }
+
+ protected TenantBuilder baseTenant(Direction direction) {
return new TenantBuilder()
.setId(tid)
.setEndpointGroup(ImmutableList.of(new EndpointGroupBuilder()
.setSubjectFeatureInstances(new SubjectFeatureInstancesBuilder()
.setClassifierInstance(ImmutableList.of(new ClassifierInstanceBuilder()
.setName(new ClassifierName("tcp_80"))
- .setClassifierDefinitionId(SubjectFeatures.TCP_PORT.getId())
+ .setClassifierDefinitionId(L4Classifier.ID)
.setParameterValue(ImmutableList.of(new ParameterValueBuilder()
- .setName(new ParameterName("port"))
- .setIntValue(Long.valueOf(80))
- .build()))
+ .setName(new ParameterName("destport"))
+ .setIntValue(Long.valueOf(80))
+ .build(),
+ new ParameterValueBuilder()
+ .setName(new ParameterName("type"))
+ .setStringValue("TCP")
+ .build()))
.build()))
.setActionInstance(ImmutableList.of(new ActionInstanceBuilder()
.setName(new ActionName("allow"))
.build()))
.setClassifierRef(ImmutableList.of(new ClassifierRefBuilder()
.setName(new ClassifierName("tcp_80"))
+ .setDirection(direction)
.build()))
.build()))
.build()))
ReadWriteTransaction t = mock(ReadWriteTransaction.class);
if (flowMap == null)
flowMap = Collections.emptyMap();
- table.sync(t, tiid, flowMap, nodeId, null);
+ table.sync(t, tiid, flowMap, nodeId, policyResolver.getCurrentPolicy(),
+ null);
return t;
}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
+
+import java.util.HashMap;
+import java.util.Objects;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Matchers;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable.FlowCtx;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRefBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.TenantBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.Assert.*;
+
+import static org.mockito.Matchers.*;
+
+import static org.mockito.Mockito.*;
+
+public class PolicyEnforcerTest extends FlowTableTest {
+ protected static final Logger LOG =
+ LoggerFactory.getLogger(PolicyEnforcerTest.class);
+
+ @Before
+ public void setup() throws Exception {
+ initCtx();
+ table = new PolicyEnforcer(ctx);
+ super.setup();
+ }
+
+
+ @Test
+ public void testNoEps() throws Exception {
+ ReadWriteTransaction t = dosync(null);
+ verify(t, times(1)).put(any(LogicalDatastoreType.class),
+ Matchers.<InstanceIdentifier<Flow>>any(),
+ any(Flow.class));
+ }
+
+ @Test
+ public void testSameEg() throws Exception {
+ Endpoint ep1 = localEP().build();
+ endpointManager.addEndpoint(ep1);
+ Endpoint ep2 = localEP()
+ .setMacAddress(new MacAddress("00:00:00:00:00:02"))
+ .build();
+ endpointManager.addEndpoint(ep2);
+ policyResolver.addTenant(baseTenant().build());
+
+ ReadWriteTransaction t = dosync(null);
+ ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
+ verify(t, atLeastOnce()).put(eq(LogicalDatastoreType.CONFIGURATION),
+ Matchers.<InstanceIdentifier<Flow>>any(),
+ ac.capture());
+ int count = 0;
+ HashMap<String, FlowCtx> flowMap = new HashMap<>();
+ for (Flow f : ac.getAllValues()) {
+ flowMap.put(f.getId().getValue(), new FlowCtx(f));
+ // XXX - TODO check actual match/action
+ if (f.getId().getValue().indexOf("intraallow") == 0)
+ count += 1;
+ }
+ assertEquals(1, count);
+
+ t = dosync(flowMap);
+ verify(t, never()).put(any(LogicalDatastoreType.class),
+ Matchers.<InstanceIdentifier<Flow>>any(),
+ any(Flow.class));
+ }
+
+ @Test
+ public void testDifferentEg() throws Exception {
+ doTestDifferentEg(null);
+ doTestDifferentEg(Direction.Bidirectional);
+ doTestDifferentEg(Direction.In);
+ doTestDifferentEg(Direction.Out);
+ }
+
+ public void doTestDifferentEg(Direction direction) throws Exception {
+ Endpoint ep1 = localEP().build();
+ endpointManager.addEndpoint(ep1);
+ Endpoint ep2 = localEP()
+ .setMacAddress(new MacAddress("00:00:00:00:00:02"))
+ .setEndpointGroup(eg2)
+ .build();
+ endpointManager.addEndpoint(ep2);
+ policyResolver.addTenant(baseTenant(direction).build());
+
+ ReadWriteTransaction t = dosync(null);
+ ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
+ verify(t, atLeastOnce()).put(eq(LogicalDatastoreType.CONFIGURATION),
+ Matchers.<InstanceIdentifier<Flow>>any(),
+ ac.capture());
+ int count = 0;
+ HashMap<String, FlowCtx> flowMap = new HashMap<>();
+ for (Flow f : ac.getAllValues()) {
+ flowMap.put(f.getId().getValue(), new FlowCtx(f));
+ if (f.getId().getValue().indexOf("intraallow") == 0) {
+ count += 1;
+ } else if (f.getMatch() != null &&
+ f.getMatch().getEthernetMatch() != null &&
+ Objects.equals(FlowUtils.IPv4,
+ f.getMatch().getEthernetMatch()
+ .getEthernetType().getType().getValue()) &&
+ f.getMatch().getIpMatch() != null &&
+ Objects.equals(Short.valueOf((short)6),
+ f.getMatch().getIpMatch().getIpProtocol()) &&
+ Objects.equals(Integer.valueOf(80),
+ ((TcpMatch)f.getMatch().getLayer4Match())
+ .getTcpDestinationPort().getValue())) {
+ // XXX - TODO - verify sepg/depg
+ count += 1;
+ } else if (f.getMatch() != null &&
+ f.getMatch().getEthernetMatch() != null &&
+ Objects.equals(FlowUtils.IPv6,
+ f.getMatch().getEthernetMatch()
+ .getEthernetType().getType().getValue()) &&
+ f.getMatch().getIpMatch() != null &&
+ Objects.equals(Short.valueOf((short)6),
+ f.getMatch().getIpMatch().getIpProtocol()) &&
+ Objects.equals(Integer.valueOf(80),
+ ((TcpMatch)f.getMatch().getLayer4Match())
+ .getTcpDestinationPort().getValue())) {
+ // XXX - TODO - verify sepg/depg
+ count += 1;
+ }
+ }
+ if (direction == null || direction.equals(Direction.Bidirectional))
+ assertEquals(6, count);
+ else
+ assertEquals(4, count);
+
+ t = dosync(flowMap);
+ verify(t, never()).put(any(LogicalDatastoreType.class),
+ Matchers.<InstanceIdentifier<Flow>>any(),
+ any(Flow.class));
+ }
+
+ @Test
+ public void testConditions() throws Exception {
+ // XXX TODO
+ }
+}
public void testNoPolicy() throws Exception {
endpointManager.addEndpoint(localEP().build());
ReadWriteTransaction t = dosync(null);
- verify(t, never()).put(any(LogicalDatastoreType.class),
- Matchers.<InstanceIdentifier<Flow>>any(),
- any(Flow.class));
+ verify(t, times(1)).put(any(LogicalDatastoreType.class),
+ Matchers.<InstanceIdentifier<Flow>>any(),
+ any(Flow.class));
}
@Test
ReadWriteTransaction t = dosync(null);
ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
- verify(t, times(1)).put(eq(LogicalDatastoreType.CONFIGURATION),
+ verify(t, times(2)).put(eq(LogicalDatastoreType.CONFIGURATION),
Matchers.<InstanceIdentifier<Flow>>any(),
ac.capture());
HashMap<String, FlowCtx> flowMap = new HashMap<>();
for (Flow f : ac.getAllValues()) {
flowMap.put(f.getId().getValue(), new FlowCtx(f));
- if (Objects.equals(ep.getMacAddress(),
+ if (f.getMatch() == null) {
+ assertEquals(FlowUtils.dropInstructions(),
+ f.getInstructions());
+ count += 1;
+ } else if (Objects.equals(ep.getMacAddress(),
f.getMatch().getEthernetMatch()
.getEthernetSource().getAddress())) {
// XXX TODO verify register setting in the instructions
count += 1;
}
}
- assertEquals(1, count);
+ assertEquals(2, count);
t = dosync(flowMap);
verify(t, never()).put(any(LogicalDatastoreType.class),
package org.opendaylight.groupbasedpolicy.resolver;
-import org.opendaylight.groupbasedpolicy.resolver.PolicyCache.Policy;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
-import com.google.common.collect.Table;
-
/**
* Mock version of policy resolver useful for tests
IndexedTenant it = new IndexedTenant(t);
context.tenant.set(it);
resolvedTenants.put(unresolvedTenant.getId(), context);
- Table<EgKey, EgKey, Policy> policy = resolvePolicy(t);
- policyCache.updatePolicy(policy, policyListenerScopes);
+
+ updatePolicy();
}
}
package org.opendaylight.groupbasedpolicy.resolver;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver;
-import org.opendaylight.groupbasedpolicy.resolver.PolicyCache.ConditionSet;
-import org.opendaylight.groupbasedpolicy.resolver.PolicyCache.Policy;
+import org.opendaylight.groupbasedpolicy.resolver.ConditionSet;
import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver.ContractMatch;
+import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver.TenantContext;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.CapabilityMatcherName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.CapabilityName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClauseName;
@Test
public void testContractSelection() throws Exception {
// named selectors
+ TenantContext tc = new TenantContext(null);
+ Collection<TenantContext> tCol = Collections.singleton(tc);
+
+ tc.tenant.set(new IndexedTenant(tenant1));
Table<EgKey, EgKey, List<ContractMatch>> contractMatches =
- resolver.selectContracts(tenant1);
+ resolver.selectContracts(tCol);
assertEquals(1, contractMatches.size());
List<ContractMatch> matches =
contractMatches.get(new EgKey(tenant1.getId(), eg1.getId()),
ImmutableList.of(tenant1.getId()),
matches);
- contractMatches = resolver.selectContracts(tenant2);
+
+ tc.tenant.set(new IndexedTenant(tenant2));
+ contractMatches = resolver.selectContracts(tCol);
assertEquals(2, contractMatches.size());
matches = contractMatches.get(new EgKey(tenant2.getId(), eg1.getId()),
new EgKey(tenant2.getId(), eg2.getId()));
matches);
// target selectors
- contractMatches = resolver.selectContracts(tenant3);
+ tc.tenant.set(new IndexedTenant(tenant3));
+ contractMatches = resolver.selectContracts(tCol);
assertEquals(1, contractMatches.size());
matches = contractMatches.get(new EgKey(tenant3.getId(), eg4.getId()),
new EgKey(tenant3.getId(), eg5.getId()));
matches);
// empty matches
- contractMatches = resolver.selectContracts(tenant0);
+ tc.tenant.set(new IndexedTenant(tenant0));
+ contractMatches = resolver.selectContracts(tCol);
assertEquals(0, contractMatches.size());
- contractMatches = resolver.selectContracts(tenant00);
+ tc.tenant.set(new IndexedTenant(tenant00));
+ contractMatches = resolver.selectContracts(tCol);
assertEquals(0, contractMatches.size());
}
ImmutableSet.of(cond3.getName()),
ImmutableSet.of(ImmutableSet.of(cond1.getName(),
cond2.getName())));
-
+ TenantContext tc = new TenantContext(null);
+ Collection<TenantContext> tCol = Collections.singleton(tc);
+
+ tc.tenant.set(new IndexedTenant(tenant1));
Table<EgKey, EgKey, List<ContractMatch>> contractMatches =
- resolver.selectContracts(tenant1);
+ resolver.selectContracts(tCol);
+ Map<EgKey, Set<ConditionSet>> egConditions = new HashMap<>();
Table<EgKey, EgKey, Policy> policy =
- resolver.selectSubjects(contractMatches);
+ resolver.selectSubjects(contractMatches, egConditions);
assertEquals(1, policy.size());
- Policy p = policy.get(new EgKey(tenant1.getId(), eg1.getId()),
- new EgKey(tenant1.getId(), eg2.getId()));
- List<RuleGroup> rules = p.ruleMap.get(cs, ConditionSet.EMPTY);
+ Policy p = policy.get(new EgKey(tenant1.getId(), eg2.getId()),
+ new EgKey(tenant1.getId(), eg1.getId()));
+ List<RuleGroup> rules = p.ruleMap.get(ConditionSet.EMPTY, cs);
assertNotNull(rules);
assertEquals(1, rules.size());
RuleGroup rg = rules.get(0);
assertEquals(1, rg.rules.size());
assertEquals(rule1.getName(), rg.rules.get(0).getName());
- contractMatches = resolver.selectContracts(tenant2);
- policy = resolver.selectSubjects(contractMatches);
+ tc.tenant.set(new IndexedTenant(tenant2));
+ contractMatches = resolver.selectContracts(tCol);
+ egConditions = new HashMap<>();
+ policy = resolver.selectSubjects(contractMatches, egConditions);
assertEquals(2, policy.size());
- p = policy.get(new EgKey(tenant2.getId(), eg3.getId()),
- new EgKey(tenant2.getId(), eg2.getId()));
- rules = p.ruleMap.get(cs, ConditionSet.EMPTY);
+ p = policy.get(new EgKey(tenant2.getId(), eg2.getId()),
+ new EgKey(tenant2.getId(), eg3.getId()));
+ rules = p.ruleMap.get(ConditionSet.EMPTY, cs);
assertNotNull(rules);
assertEquals(1, rules.size());
rg = rules.get(0);
assertEquals(1, rg.rules.size());
assertEquals(rule2.getName(), rg.rules.get(0).getName());
- p = policy.get(new EgKey(tenant2.getId(), eg1.getId()),
- new EgKey(tenant2.getId(), eg2.getId()));
- rules = p.ruleMap.get(cs, ConditionSet.EMPTY);
+ p = policy.get(new EgKey(tenant2.getId(), eg2.getId()),
+ new EgKey(tenant2.getId(), eg1.getId()));
+ rules = p.ruleMap.get(ConditionSet.EMPTY, cs);
assertNotNull(rules);
assertEquals(1, rules.size());
rg = rules.get(0);
assertEquals(1, rg.rules.size());
assertEquals(rule1.getName(), rg.rules.get(0).getName());
- contractMatches = resolver.selectContracts(tenant3);
- policy = resolver.selectSubjects(contractMatches);
+ tc.tenant.set(new IndexedTenant(tenant3));
+ contractMatches = resolver.selectContracts(tCol);
+ egConditions = new HashMap<>();
+ policy = resolver.selectSubjects(contractMatches, egConditions);
assertEquals(1, policy.size());
- p = policy.get(new EgKey(tenant3.getId(), eg4.getId()),
- new EgKey(tenant3.getId(), eg5.getId()));
+ p = policy.get(new EgKey(tenant3.getId(), eg5.getId()),
+ new EgKey(tenant3.getId(), eg4.getId()));
rules = p.ruleMap.get(ConditionSet.EMPTY, ConditionSet.EMPTY);
assertNotNull(rules);
assertEquals(1, rules.size());
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.groupbasedpolicy.renderer.ofoverlay;
+package org.opendaylight.groupbasedpolicy.util;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.SingletonTask;
+import org.opendaylight.groupbasedpolicy.util.SingletonTask;
public class SingletonTaskTest {