this.dataProvider = dataProvider;
this.executor = executor;
- rpcRegistration =
- rpcRegistry.addRpcImplementation(EndpointService.class, this);
+ if (rpcRegistry != null) {
+ rpcRegistration =
+ rpcRegistry.addRpcImplementation(EndpointService.class, this);
+ } else
+ rpcRegistration = null;
- // XXX - This is a hack to avoid a bug in the data broker
- // API where you have to write all the parents before you can write
- // a child
- InstanceIdentifier<Endpoints> iid =
- InstanceIdentifier.builder(Endpoints.class).build();
- WriteTransaction t = this.dataProvider.newWriteOnlyTransaction();
- t.put(LogicalDatastoreType.OPERATIONAL,
- iid, new EndpointsBuilder().build());
- ListenableFuture<RpcResult<TransactionStatus>> f = t.commit();
- Futures.addCallback(f, new FutureCallback<RpcResult<TransactionStatus>>() {
-
- @Override
- public void onSuccess(RpcResult<TransactionStatus> result) {
-
- }
+ if (dataProvider != null) {
+ // XXX - This is a hack to avoid a bug in the data broker
+ // API where you have to write all the parents before you can write
+ // a child
+ InstanceIdentifier<Endpoints> iid =
+ InstanceIdentifier.builder(Endpoints.class).build();
+ WriteTransaction t = this.dataProvider.newWriteOnlyTransaction();
+ t.put(LogicalDatastoreType.OPERATIONAL,
+ iid, new EndpointsBuilder().build());
+ ListenableFuture<RpcResult<TransactionStatus>> f = t.commit();
+ Futures.addCallback(f, new FutureCallback<RpcResult<TransactionStatus>>() {
- @Override
- public void onFailure(Throwable t) {
- LOG.error("Could not write endpoint base container", t);
- }
- });
+ @Override
+ public void onSuccess(RpcResult<TransactionStatus> result) {
+
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ LOG.error("Could not write endpoint base container", t);
+ }
+ });
+ }
// XXX TODO - age out endpoint data and remove
// endpoint group/condition mappings with no conditions
SwitchManager switchManager) {
super(dataProvider, rpcRegistry, executor);
- listenerReg =
- dataProvider.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
- endpointsIid,
- this,
- DataChangeScope.ONE);
+ if (dataProvider != null) {
+ listenerReg = dataProvider
+ .registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+ endpointsIid,
+ this,
+ DataChangeScope.ONE);
+ } else
+ listenerReg = null;
LOG.debug("Initialized OFOverlay endpoint manager");
}
/**
* Update the endpoint indexes. Set newEp to null to remove.
*/
- private void updateEndpoint(Endpoint oldEp, Endpoint newEp) {
+ protected void updateEndpoint(Endpoint oldEp, Endpoint newEp) {
// XXX TODO only keep track of endpoints that are attached
// to switches that are actually connected to us
NodeId oldLoc = getLocation(oldEp);
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable.FlowTableCtx;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PortSecurity;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.SourceEPGTable;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.SourceMapper;
import org.opendaylight.groupbasedpolicy.resolver.EgKey;
import org.opendaylight.groupbasedpolicy.resolver.PolicyListener;
import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver;
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;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.UniqueId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayConfig.LearningMode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
* event in milliseconds.
*/
private final static int FLOW_UPDATE_DELAY = 250;
+
+ /**
+ * Counter used to allocate ordinal values for forwarding contexts
+ * and VNIDs
+ */
+ private final AtomicInteger policyOrdinal = new AtomicInteger(1);
+
+ /**
+ * 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
+ */
+ private final ConcurrentMap<TenantId, ConcurrentMap<String, Integer>> ordinals =
+ new ConcurrentHashMap<>();
public PolicyManager(DataBroker dataBroker,
PolicyResolver policyResolver,
this.executor = executor;
FlowTableCtx ctx = new FlowTableCtx(dataBroker, rpcRegistry,
- policyResolver, switchManager,
+ this, policyResolver, switchManager,
endpointManager, executor);
flowPipeline = ImmutableList.of(new PortSecurity(ctx),
- new SourceEPGTable(ctx));
+ new SourceMapper(ctx));
policyScope = policyResolver.registerListener(this);
- switchManager.registerListener(this);
+ if (switchManager != null)
+ switchManager.registerListener(this);
endpointManager.registerListener(this);
dirty = new AtomicReference<>(new Dirty());
new Function<FlowTable, Table>() {
@Override
public Table apply(FlowTable input) {
- return input.getEmptyTable();
+ return new TableBuilder()
+ .setId(Short.valueOf(input.getTableId()))
+ .build();
}
})) .build());
t.put(LogicalDatastoreType.CONFIGURATION,
// No-op for now
}
+ /**
+ * 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
+ * @param tenantId the tenant ID of the element
+ * @param id the unique ID for the element
+ * @return the 32-bit ordinal value
+ */
+ public int getContextOrdinal(final TenantId tenantId,
+ final UniqueId id) throws Exception {
+ if (tenantId == null || id == null) return 0;
+ ConcurrentMap<String, Integer> m = ordinals.get(tenantId);
+ if (m == null) {
+ m = new ConcurrentHashMap<>();
+ ConcurrentMap<String, Integer> old =
+ ordinals.putIfAbsent(tenantId, m);
+ if (old != null) m = old;
+ }
+ Integer ord = m.get(id.getValue());
+ if (ord == null) {
+ ord = policyOrdinal.getAndIncrement();
+ Integer old = m.putIfAbsent(id.getValue(), ord);
+ if (old != null) ord = old;
+ }
+
+ return ord.intValue();
+// while (true) {
+// final ReadWriteTransaction t = dataBroker.newReadWriteTransaction();
+// InstanceIdentifier<DataPlaneOrdinal> iid =
+// InstanceIdentifier.builder(OfOverlayOperational.class)
+// .child(DataPlaneOrdinal.class,
+// new DataPlaneOrdinalKey(id, tenantId))
+// .build();
+// ListenableFuture<Optional<DataObject>> r =
+// t.read(LogicalDatastoreType.OPERATIONAL, iid);
+// Optional<DataObject> res = r.get();
+// if (res.isPresent()) {
+// DataPlaneOrdinal o = (DataPlaneOrdinal)res.get();
+// return o.getOrdinal().intValue();
+// }
+// final int ordinal = policyOrdinal.getAndIncrement();
+// OfOverlayOperational oo = new OfOverlayOperationalBuilder()
+// .setDataPlaneOrdinal(ImmutableList.of(new DataPlaneOrdinalBuilder()
+// .setId(id)
+// .setTenant(tenantId)
+// .setOrdinal(Long.valueOf(ordinal))
+// .build()))
+// .build();
+// t.merge(LogicalDatastoreType.OPERATIONAL,
+// InstanceIdentifier.builder(OfOverlayOperational.class)
+// .build(),
+// oo);
+// ListenableFuture<RpcResult<TransactionStatus>> commitr = t.commit();
+// try {
+// commitr.get();
+// return ordinal;
+// } catch (ExecutionException e) {
+// if (e.getCause() instanceof OptimisticLockFailedException)
+// continue;
+// throw e;
+// }
+// }
+ }
+
// **************
// Implementation
// **************
-
+
private void scheduleUpdate() {
- LOG.info("Scheduling flow update task");
- flowUpdateTask.reschedule(FLOW_UPDATE_DELAY, TimeUnit.MILLISECONDS);
+ if (switchManager != null) {
+ LOG.trace("Scheduling flow update task");
+ flowUpdateTask.reschedule(FLOW_UPDATE_DELAY, TimeUnit.MILLISECONDS);
+ }
}
/**
private class FlowUpdateTask implements Runnable {
@Override
public void run() {
- LOG.info("Beginning flow update task");
+ LOG.debug("Beginning flow update task");
Dirty d = dirty.getAndSet(new Dirty());
CompletionService<Void> ecs
LOG.error("Failed to update flow tables", e);
}
}
- LOG.info("Flow update completed");
+ LOG.debug("Flow update completed");
}
}
FlowCapableNode fcn = node.getAugmentation(FlowCapableNode.class);
if (fcn == null) return;
- LOG.info("{} update", node.getId());
+ LOG.debug("{} update", node.getId());
SwitchState state = switches.get(node.getId());
if (state == null) {
package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.EndpointManager;
+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.PolicyResolver;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService;
+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.inventory.rev130819.NodeId;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Optional;
import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
/**
* Manage the state of a flow table by reacting to any events and updating
protected final DataBroker dataBroker;
protected final RpcProviderRegistry rpcRegistry;
+ protected final PolicyManager policyManager;
protected final SwitchManager switchManager;
protected final EndpointManager endpointManager;
public FlowTableCtx(DataBroker dataBroker,
RpcProviderRegistry rpcRegistry,
+ PolicyManager policyManager,
PolicyResolver policyResolver,
SwitchManager switchManager,
EndpointManager endpointManager,
super();
this.dataBroker = dataBroker;
this.rpcRegistry = rpcRegistry;
+ this.policyManager = policyManager;
this.switchManager = switchManager;
this.endpointManager = endpointManager;
this.policyResolver = policyResolver;
}
protected final FlowTableCtx ctx;
- protected final SalFlowService flowService;
- protected final OpendaylightFlowStatisticsService statsService;
public FlowTable(FlowTableCtx ctx) {
super();
this.ctx = ctx;
- this.flowService = ctx.rpcRegistry.getRpcService(SalFlowService.class);
- this.statsService =
- ctx.rpcRegistry.getRpcService(OpendaylightFlowStatisticsService.class);
}
// *********
* @param dirty the dirty set
* @throws Exception
*/
- public abstract void update(NodeId nodeId, Dirty dirty) throws Exception;
+ public void update(NodeId nodeId, Dirty dirty) throws Exception {
+ ReadWriteTransaction t = ctx.dataBroker.newReadWriteTransaction();
+ InstanceIdentifier<Table> tiid =
+ FlowUtils.createTablePath(nodeId, getTableId());
+ Optional<DataObject> r =
+ t.read(LogicalDatastoreType.CONFIGURATION, tiid).get();
+
+ HashMap<String, FlowCtx> flowMap = new HashMap<>();
+
+ if (r.isPresent()) {
+ Table curTable = (Table)r.get();
+
+ if (curTable.getFlow() != null) {
+ for (Flow f : curTable.getFlow()) {
+ flowMap.put(f.getId().getValue(), new FlowCtx(f));
+ }
+ }
+ }
+
+ sync(t, tiid, flowMap, nodeId, dirty);
+
+ for (FlowCtx fx : flowMap.values()) {
+ if (!fx.visited) {
+ t.delete(LogicalDatastoreType.CONFIGURATION,
+ FlowUtils.createFlowPath(tiid, fx.f.getKey()));
+ }
+ }
+
+ ListenableFuture<RpcResult<TransactionStatus>> result = t.commit();
+ Futures.addCallback(result, updateCallback);
+ }
/**
- * Construct an empty flow table
- * @return the {@link Table}
+ * Sync flow state using the flow map
+ * @throws Exception
*/
- public abstract Table getEmptyTable();
+ public abstract void sync(ReadWriteTransaction t,
+ InstanceIdentifier<Table> tiid,
+ Map<String, FlowCtx> flowMap,
+ NodeId nodeId, Dirty dirty) throws Exception;
+
+ /**
+ * Get the table ID being manipulated
+ */
+ public abstract short getTableId();
// ***************
// Utility methods
// ***************
+
+ /**
+ * Get a base flow builder with some common features already set
+ */
+ protected FlowBuilder base() {
+ return new FlowBuilder()
+ .setTableId(getTableId())
+ .setBarrier(false)
+ .setHardTimeout(0)
+ .setIdleTimeout(0);
+ }
/**
* Generic callback for handling result of flow manipulation
LOG.error("Failed to add flow entry", t);
}
}
-
protected static final FlowCallback<TransactionStatus> updateCallback =
new FlowCallback<>();
+
+ /**
+ * "Visit" a flow ID by checking if it already exists and if so marking
+ * the {@link FlowCtx} visited bit.
+ * @param flowMap the map containing the existing flows for this table
+ * @param flowId the ID for the flow
+ * @return <code>true</code> if the flow needs to be added
+ */
+ protected static boolean visit(Map<String, FlowCtx> flowMap,
+ String flowId) {
+ FlowCtx c = flowMap.get(flowId);
+ if (c != null) {
+ c.visited = true;
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Write the given flow to the transaction
+ */
+ protected static void writeFlow(ReadWriteTransaction t,
+ InstanceIdentifier<Table> tiid,
+ Flow flow) {
+ LOG.trace("{} {}", flow.getId(), flow);
+ t.put(LogicalDatastoreType.CONFIGURATION,
+ FlowUtils.createFlowPath(tiid, flow.getId()),
+ flow);
+ }
+
+ /**
+ * Context object for keeping track of flow state
+ */
+ protected static class FlowCtx {
+ Flow f;
+ boolean visited = false;
+
+ public FlowCtx(Flow f) {
+ super();
+ this.f = f;
+ }
+ }
}
package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
-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.yang.types.rev100924.MacAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DropActionCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.drop.action._case.DropActionBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
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.FlowKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowTableRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.GoToTableCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteActionsCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.go.to.table._case.GoToTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.write.actions._case.WriteActionsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
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.EthernetMatch;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatch;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import com.google.common.collect.ImmutableList;
.child(Node.class, new NodeKey(nodeId))
.build();
}
-
- /**
- * Create a NodeRef from a node ID
- *
- * @param nodeId the {@link NodeId}
- * @return the {@link NodeRef}
- */
- public static final NodeRef createNodeRef(final NodeId nodeId) {
- return new NodeRef(createNodePath(nodeId));
- }
/**
* Shorten's node child path to node path.
.child(Table.class, new TableKey(tableId))
.build();
}
-
- public static final FlowTableRef createTableRef(final NodeId nodeId,
- final short tableId) {
- return new FlowTableRef(createTablePath(nodeId, tableId));
- }
-
/**
* Creates a path for particular flow, by appending flow-specific information
return table.child(Flow.class, flowKey);
}
- /**
- * Creates a path for particular flow, by appending flow-specific information
- * to table path.
- *
- * @param table
- * @param flowId
- * @return
- */
- public static InstanceIdentifier<Flow>
- createFlowPath(final InstanceIdentifier<Table> table,
- final String flowId) {
- return createFlowPath(table, new FlowKey(new FlowId(flowId)));
- }
-
/**
* Creates a path for particular flow, by appending flow-specific information
* to table path.
final FlowId flowId) {
return createFlowPath(table, new FlowKey(flowId));
}
-
- /**
- * Extract table id from table path.
- *
- * @param tablePath
- * @return
- */
- public static Short getTableId(final InstanceIdentifier<Table> tablePath) {
- return tablePath.firstKeyOf(Table.class, TableKey.class).getId();
- }
-
- /**
- * Extracts NodeConnectorKey from node connector path.
- */
- public static NodeConnectorKey
- getNodeConnectorKey(final InstanceIdentifier<?> nodeConnectorPath) {
- return nodeConnectorPath.firstKeyOf(NodeConnector.class,
- NodeConnectorKey.class);
- }
-
- /**
- * Extracts NodeKey from node path.
- */
- public static NodeKey getNodeKey(final InstanceIdentifier<?> nodePath) {
- return nodePath.firstKeyOf(Node.class, NodeKey.class);
- }
-
-
- //
- public static final InstanceIdentifier<NodeConnector>
- createNodeConnectorIdentifier(final String nodeIdValue,
- final String nodeConnectorIdValue) {
- return createNodePath(new NodeId(nodeIdValue))
- .child(NodeConnector.class,
- new NodeConnectorKey(new NodeConnectorId(nodeConnectorIdValue)));
- }
-
- /**
- * @param nodeConnectorRef
- * @return
- */
- public static InstanceIdentifier<Node>
- generateNodeInstanceIdentifier(final NodeConnectorRef nodeConnectorRef) {
- return nodeConnectorRef.getValue().firstIdentifierOf(Node.class);
- }
-
- /**
- * @param nodeConnectorRef
- * @param flowTableKey
- * @return
- */
- public static InstanceIdentifier<Table>
- generateFlowTableInstanceIdentifier(final NodeConnectorRef nodeConnectorRef,
- final TableKey flowTableKey) {
- return generateNodeInstanceIdentifier(nodeConnectorRef).builder()
- .augmentation(FlowCapableNode.class)
- .child(Table.class, flowTableKey)
- .build();
- }
-
- /**
- * @param nodeConnectorRef
- * @param flowTableKey
- * @param flowKey
- * @return
- */
- public static InstanceIdentifier<Flow>
- generateFlowInstanceIdentifier(final NodeConnectorRef nodeConnectorRef,
- final TableKey flowTableKey,
- final FlowKey flowKey) {
- return generateFlowTableInstanceIdentifier(nodeConnectorRef,
- flowTableKey)
- .child(Flow.class, flowKey);
- }
public static Instructions gotoTable(short tableId) {
return new InstructionsBuilder()
return new InstructionsBuilder()
.setInstruction(ImmutableList.of(new InstructionBuilder()
.setOrder(Integer.valueOf(0))
- .setInstruction(new ApplyActionsCaseBuilder()
- .setApplyActions(new ApplyActionsBuilder()
+ .setInstruction(new WriteActionsCaseBuilder()
+ .setWriteActions(new WriteActionsBuilder()
.setAction(ImmutableList.of(new ActionBuilder()
.setOrder(Integer.valueOf(0))
.setAction(new DropActionCaseBuilder()
+/*
+ * 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.Map;
import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
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;
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.TableBuilder;
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.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.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
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.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-
/**
* Manage the table that enforces port security
* @author readams
LoggerFactory.getLogger(PortSecurity.class);
public static final short TABLE_ID = 0;
- private static final Long ARP = Long.valueOf(0x0806);
- private static final Long IPv4 = Long.valueOf(0x0800);
- private static final Long IPv6 = Long.valueOf(0x86DD);
+ protected static final Long ARP = Long.valueOf(0x0806);
+ protected static final Long IPv4 = Long.valueOf(0x0800);
+ protected static final Long IPv6 = Long.valueOf(0x86DD);
public PortSecurity(FlowTableCtx ctx) {
super(ctx);
}
-
+
@Override
- public Table getEmptyTable() {
- return new TableBuilder()
- .setId(Short.valueOf((short)TABLE_ID))
- .build();
+ public short getTableId() {
+ return TABLE_ID;
}
-
- @Override
- public void update(NodeId nodeId, Dirty dirty) throws Exception {
- ReadWriteTransaction t = ctx.dataBroker.newReadWriteTransaction();
- InstanceIdentifier<Table> tiid =
- FlowUtils.createTablePath(nodeId, TABLE_ID);
- Optional<DataObject> r =
- t.read(LogicalDatastoreType.CONFIGURATION, tiid).get();
-
- HashMap<String, FlowCtx> flowMap = new HashMap<>();
-
- if (r.isPresent()) {
- Table curTable = (Table)r.get();
- if (curTable.getFlow() != null) {
- for (Flow f : curTable.getFlow()) {
- flowMap.put(f.getId().getValue(), new FlowCtx(f));
- }
- }
- }
-
+ @Override
+ public void sync(ReadWriteTransaction t,
+ InstanceIdentifier<Table> tiid,
+ Map<String, FlowCtx> flowMap,
+ NodeId nodeId, Dirty dirty) {
+ // Default drop all
dropFlow(t, tiid, flowMap, 1, null);
+
+ // Drop IP traffic that doesn't match a source IP rule
dropFlow(t, tiid, flowMap, 110, ARP);
dropFlow(t, tiid, flowMap, 111, IPv4);
- dropFlow(t, tiid, flowMap, 113, IPv6);
+ dropFlow(t, tiid, flowMap, 112, IPv6);
+
+ // XXX - TODO Allow traffic from tunnel ports and external ports
for (Endpoint e : ctx.endpointManager.getEndpointsForNode(nodeId)) {
OfOverlayContext ofc = e.getAugmentation(OfOverlayContext.class);
- if (ofc != null && ofc.getNodeConnectorId() != null) {
+ if (ofc != null && ofc.getNodeConnectorId() != null &&
+ (ofc.getLocationType() == null ||
+ LocationType.Internal.equals(ofc.getLocationType()))) {
+ // Allow layer 3 traffic (ARP and IP) with the correct source
+ // IP, MAC, and source port
l3flow(t, tiid, flowMap, e, ofc, 120, false);
l3flow(t, tiid, flowMap, e, ofc, 121, true);
+
+ // Allow layer 2 traffic with the correct source MAC and
+ // source port (note lower priority than drop IP rules)
l2flow(t, tiid, flowMap, e, ofc, 100);
}
}
-
- for (FlowCtx fx : flowMap.values()) {
- if (!fx.visited) {
- t.delete(LogicalDatastoreType.CONFIGURATION,
- FlowUtils.createFlowPath(tiid, fx.f.getKey()));
- }
- }
-
- ListenableFuture<RpcResult<TransactionStatus>> result = t.commit();
- Futures.addCallback(result, updateCallback);
- }
-
- private static FlowBuilder base() {
- return new FlowBuilder()
- .setTableId(TABLE_ID)
- .setBarrier(false)
- .setHardTimeout(0)
- .setIdleTimeout(0)
- .setInstructions(FlowUtils.gotoTable((short)(TABLE_ID + 1)));
}
private void dropFlow(ReadWriteTransaction t,
InstanceIdentifier<Table> tiid,
- HashMap<String, FlowCtx> flowMap,
+ Map<String, FlowCtx> flowMap,
Integer priority, Long etherType) {
FlowId flowid = new FlowId(new StringBuilder()
.append("drop|")
.append(etherType)
.toString());
if (visit(flowMap, flowid.getValue())) {
- Flow flow = base()
+ FlowBuilder flowb = base()
.setId(flowid)
.setPriority(priority)
- .setMatch(new MatchBuilder()
- .setEthernetMatch(FlowUtils.ethernetMatch(null, null,
- etherType))
- .build())
- .setInstructions(FlowUtils.dropInstructions())
- .build();
- LOG.trace("{} {}", flow.getId(), flow);
- t.put(LogicalDatastoreType.CONFIGURATION,
- FlowUtils.createFlowPath(tiid, flowid),
- flow);
+ .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,
- HashMap<String, FlowCtx> flowMap,
+ Map<String, FlowCtx> flowMap,
Endpoint e, OfOverlayContext ofc,
Integer priority) {
FlowId flowid = new FlowId(new StringBuilder()
+ .append(ofc.getNodeConnectorId())
+ .append("|")
.append(e.getMacAddress().getValue())
.toString());
if (visit(flowMap, flowid.getValue())) {
FlowBuilder flowb = base()
.setPriority(priority)
- .setId(flowid)
- .setMatch(new MatchBuilder()
- .setEthernetMatch(FlowUtils.ethernetMatch(e.getMacAddress(),
- null, null))
- .setInPort(ofc.getNodeConnectorId())
- .build());
+ .setId(flowid)
+ .setMatch(new MatchBuilder()
+ .setEthernetMatch(FlowUtils.ethernetMatch(e.getMacAddress(),
+ null, null))
+ .setInPort(ofc.getNodeConnectorId())
+ .build())
+ .setInstructions(FlowUtils.gotoTable((short)(TABLE_ID + 1)));
- Flow flow = flowb.build();
- LOG.trace("{} {}", flow.getId(), flow);
- t.put(LogicalDatastoreType.CONFIGURATION,
- FlowUtils.createFlowPath(tiid, flowid),
- flow);
+ writeFlow(t, tiid, flowb.build());
}
}
private void l3flow(ReadWriteTransaction t,
InstanceIdentifier<Table> tiid,
- HashMap<String, FlowCtx> flowMap,
+ Map<String, FlowCtx> flowMap,
Endpoint e, OfOverlayContext ofc,
Integer priority,
boolean arp) {
continue;
}
FlowId flowid = new FlowId(new StringBuilder()
+ .append(ofc.getNodeConnectorId())
+ .append("|")
.append(e.getMacAddress().getValue())
.append("|")
.append(ikey)
.setLayer3Match(m)
.setInPort(ofc.getNodeConnectorId())
.build())
+ .setInstructions(FlowUtils.gotoTable((short)(TABLE_ID + 1)))
.build();
- LOG.trace("{} {}", flow.getId(), flow);
- t.put(LogicalDatastoreType.CONFIGURATION,
- FlowUtils.createFlowPath(tiid, flowid),
- flow);
+ writeFlow(t, tiid, flow);
}
}
}
-
- private static boolean visit(HashMap<String, FlowCtx> flowMap,
- String flowId) {
- FlowCtx c = flowMap.get(flowId);
- if (c != null) {
- c.visited = true;
- return false;
- }
- return true;
- }
-
- private static class FlowCtx {
- Flow f;
- boolean visited = false;
-
- public FlowCtx(Flow f) {
- super();
- this.f = f;
- }
- }
}
+++ /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 org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
-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.TableBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-
-
-/**
- * Manage the table that assigns source endpoint group, bridge domain, and
- * router domain to registers to be used by other tables.
- * @author readams
- */
-public class SourceEPGTable extends FlowTable {
- public static final short TABLE_ID = 1;
-
- public SourceEPGTable(FlowTableCtx ctx) {
- super(ctx);
- }
-
- @Override
- public void update(NodeId nodeId, Dirty dirty) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public Table getEmptyTable() {
- return new TableBuilder()
- .setId(Short.valueOf((short)TABLE_ID))
- .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.flow;
+
+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.IndexedTenant;
+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.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.EndpointGroup;
+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.inventory.rev130819.NodeId;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Manage the table that assigns source endpoint group, bridge domain, and
+ * router domain to registers to be used by other tables.
+ * @author readams
+ */
+public class SourceMapper extends FlowTable {
+ public static final short TABLE_ID = 1;
+
+ public SourceMapper(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) throws Exception {
+ // XXX TODO Set sEPG from tunnel ports using the tunnel ID
+
+ for (Endpoint e : ctx.endpointManager.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);
+ }
+ }
+ }
+
+ private void syncEP(ReadWriteTransaction t,
+ InstanceIdentifier<Table> tiid,
+ Map<String, FlowCtx> flowMap,
+ NodeId nodeId, Endpoint e, OfOverlayContext ofc)
+ throws Exception {
+ // Set sEPG, flood domain, bridge domain, and layer 3 context
+ // for internal endpoints by directly matching each endpoint
+ IndexedTenant tenant = ctx.policyResolver.getTenant(e.getTenant());
+ if (tenant == null) return;
+
+ EndpointGroup eg = tenant.getEndpointGroup(e.getEndpointGroup());
+ L3Context l3c = tenant.resolveL3Context(eg.getNetworkDomain());
+ L2BridgeDomain bd = tenant.resolveL2BridgeDomain(eg.getNetworkDomain());
+ L2FloodDomain fd = tenant.resolveL2FloodDomain(eg.getNetworkDomain());
+
+ int egId = 0, bdId = 0, fdId = 0, l3Id = 0;
+
+ egId = ctx.policyManager.getContextOrdinal(e.getTenant(),
+ e.getEndpointGroup());
+ if (bd != null)
+ bdId = ctx.policyManager.getContextOrdinal(e.getTenant(),
+ bd.getId());
+ if (fd != null)
+ fdId = ctx.policyManager.getContextOrdinal(e.getTenant(),
+ fd.getId());
+ if (l3c != null)
+ l3Id = ctx.policyManager.getContextOrdinal(e.getTenant(),
+ l3c.getId());
+ // TODO set source condition set ID as well
+
+ FlowId flowid = new FlowId(new StringBuilder()
+ .append(ofc.getNodeConnectorId())
+ .append("|")
+ .append(e.getMacAddress().getValue())
+ .append("|")
+ .append(egId)
+ .append("|")
+ .append(bdId)
+ .append("|")
+ .append(fdId)
+ .append("|")
+ .append(l3Id)
+ .toString());
+ if (visit(flowMap, flowid.getValue())) {
+ LOG.info("{} eg:{} bd:{} fd:{} vrf:{}",
+ e.getMacAddress(), egId, bdId, fdId, l3Id);
+ FlowBuilder flowb = base()
+ .setPriority(Integer.valueOf(100))
+ .setId(flowid)
+ .setMatch(new MatchBuilder()
+ .setEthernetMatch(FlowUtils.ethernetMatch(e.getMacAddress(),
+ null, null))
+ .setInPort(ofc.getNodeConnectorId())
+ .build())
+ // XXX TODO set sepg, bd, fd, vrf into registers
+ .setInstructions(FlowUtils.gotoTable((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.resolver;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+import javax.annotation.concurrent.Immutable;
+
+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.NetworkDomain;
+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 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.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.Subnet;
+
+/**
+ * Wrap some convenient indexes around a {@link Tenant} object
+ * @author readams
+ */
+@Immutable
+public class IndexedTenant {
+ private final Tenant tenant;
+ private final int hashCode;
+
+ private final Map<EndpointGroupId, EndpointGroup> endpointGroups =
+ new HashMap<>();
+ private final Map<ContractId, Contract> contracts =
+ new HashMap<>();
+ private final Map<String, NetworkDomain> networkDomains =
+ new HashMap<>();
+
+ public IndexedTenant(Tenant tenant) {
+ super();
+ this.tenant = tenant;
+ this.hashCode = tenant.hashCode();
+
+ if (tenant.getEndpointGroup() != null) {
+ for (EndpointGroup eg : tenant.getEndpointGroup()) {
+ endpointGroups.put(eg.getId(), eg);
+ }
+ }
+ if (tenant.getContract() != null) {
+ for (Contract c : tenant.getContract()) {
+ contracts.put(c.getId(), c);
+ }
+ }
+ if (tenant.getL3Context() != null) {
+ for (L3Context c : tenant.getL3Context()) {
+ networkDomains.put(c.getId().getValue(), c);
+ }
+ }
+ if (tenant.getL2BridgeDomain() != null) {
+ for (L2BridgeDomain c : tenant.getL2BridgeDomain()) {
+ networkDomains.put(c.getId().getValue(), c);
+ }
+ }
+ if (tenant.getL2FloodDomain() != null) {
+ for (L2FloodDomain c : tenant.getL2FloodDomain()) {
+ networkDomains.put(c.getId().getValue(), c);
+ }
+ }
+ if (tenant.getSubnet() != null) {
+ for (Subnet s : tenant.getSubnet()) {
+ networkDomains.put(s.getId().getValue(), s);
+ }
+ }
+ }
+
+ /**
+ * Get the underlying tenant object
+ * @return the {@link Tenant}
+ */
+ public Tenant getTenant() {
+ return tenant;
+ }
+
+ /**
+ * Look up the network domain specified
+ * @param id the {@link NetworkDomainId}
+ * @return the {@link NetworkDomain} if it exists, or <code>null</code>
+ * otherwise
+ */
+ public NetworkDomain getNetworkDomain(NetworkDomainId id) {
+ return networkDomains.get(id.getValue());
+ }
+
+ /**
+ * Look up the endpoint group specified
+ * @param id the {@link EndpointGroupId}
+ * @return the {@link EndpointGroup} if it exists, or <code>null</code>
+ * otherwise
+ */
+ public EndpointGroup getEndpointGroup(EndpointGroupId id) {
+ return endpointGroups.get(id);
+ }
+
+ /**
+ * Look up the contract specified
+ * @param id the {@link ContractId}
+ * @return the {@link Contract} if it exists, or <code>null</code>
+ * otherwise
+ */
+ public Contract getContract(ContractId id) {
+ return contracts.get(id);
+ }
+
+ /**
+ * Get the layer 3 context for the specified network domain by walking
+ * up the hierarchy
+ * @param id the {@link NetworkDomainId} for the network domain
+ * @return the {@link L3Context} or <code>null</code> if it does not exist
+ */
+ public L3Context resolveL3Context(NetworkDomainId id) {
+ return resolveDomain(L3Context.class, id);
+ }
+
+ /**
+ * Get the layer 2 bridge domain for the specified network domain by walking
+ * up the hierarchy
+ * @param id the {@link NetworkDomainId} for the network domain
+ * @return the {@link L2BridgeDomain} or <code>null</code> if it does
+ * not exist
+ */
+ public L2BridgeDomain resolveL2BridgeDomain(NetworkDomainId id) {
+ return resolveDomain(L2BridgeDomain.class, id);
+ }
+
+ /**
+ * Get the layer 2 flood domain for the specified network domain by walking
+ * up the hierarchy
+ * @param id the {@link NetworkDomainId} for the network domain
+ * @return the {@link L2FloodDomain} or <code>null</code> if it does
+ * not exist
+ */
+ public L2FloodDomain resolveL2FloodDomain(NetworkDomainId id) {
+ return resolveDomain(L2FloodDomain.class, id);
+ }
+
+ /**
+ * If the specified network domain represents a subnet, return it.
+ * @param id the {@link NetworkDomainId}
+ * @return the {@link Subnet} if it exists, or <code>null</code> otherwise
+ */
+ public Subnet resolveSubnet(NetworkDomainId id) {
+ NetworkDomain d = networkDomains.get(id.getValue());
+ if (d == null) return null;
+ if (d instanceof Subnet) return (Subnet)d;
+ return null;
+ }
+
+ // ******
+ // Object
+ // ******
+
+ @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;
+ IndexedTenant other = (IndexedTenant) obj;
+ if (tenant == null) {
+ if (other.tenant != null)
+ return false;
+ } else if (!tenant.equals(other.tenant))
+ return false;
+ return true;
+ }
+
+ // **************
+ // Implementation
+ // **************
+
+ private <C extends NetworkDomain> C resolveDomain(Class<C> domainClass,
+ NetworkDomainId id) {
+ HashSet<NetworkDomainId> visited = new HashSet<>();
+ while (id != null) {
+ if (visited.contains(id)) return null;
+ visited.add(id);
+ NetworkDomain d = networkDomains.get(id.getValue());
+ if (d == null) return null;
+ if (domainClass.isInstance(d)) return domainClass.cast(d);
+ if (d instanceof Subnet)
+ id = ((Subnet)d).getParent();
+ if (d instanceof L2BridgeDomain)
+ id = ((L2BridgeDomain)d).getParent();
+ if (d instanceof L2FloodDomain)
+ id = ((L2FloodDomain)d).getParent();
+ }
+ return null;
+ }
+}
*/
private CopyOnWriteArrayList<PolicyScope> policyListenerScopes;
- private ConcurrentMap<TenantId, TenantContext> resolvedTenants;
+ protected ConcurrentMap<TenantId, TenantContext> resolvedTenants;
private PolicyCache policyCache = new PolicyCache();
this.executor = executor;
policyListenerScopes = new CopyOnWriteArrayList<>();
resolvedTenants = new ConcurrentHashMap<>();
-
LOG.debug("Initialized renderer common policy resolver");
}
ep2Tenant, ep2Group, ep2Conds);
}
+ /**
+ * Get the normalized tenant for the given ID
+ * @param tenant the tenant ID
+ * @return the {@link Tenant}
+ */
+ public IndexedTenant getTenant(TenantId tenant) {
+ TenantContext tc = resolvedTenants.get(tenant);
+ if (tc == null) return null;
+ return tc.tenant.get();
+ }
+
/**
* Register a listener to receive update events.
* @param listener the {@link PolicyListener} object to receive the update
}
private void updateTenant(final TenantId tenantId) {
+ if (dataProvider == null) return;
+
TenantContext context = resolvedTenants.get(tenantId);
if (context == null) {
- ListenerRegistration<DataChangeListener> registration =
- dataProvider.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
- TenantUtils.tenantIid(tenantId),
- new PolicyChangeListener(tenantId),
- DataChangeScope.SUBTREE);
+ ListenerRegistration<DataChangeListener> registration = null;
+ if (dataProvider != null) {
+ registration = dataProvider
+ .registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+ TenantUtils.tenantIid(tenantId),
+ new PolicyChangeListener(tenantId),
+ DataChangeScope.SUBTREE);
+ }
- context = new TenantContext(tenantId, registration);
+ context = new TenantContext(registration);
TenantContext oldContext =
resolvedTenants.putIfAbsent(tenantId, context);
if (oldContext != null) {
}
// Resolve the new tenant and update atomically
- final AtomicReference<Tenant> tenantRef = context.tenant;
- final Tenant ot = tenantRef.get();
+ final AtomicReference<IndexedTenant> tenantRef = context.tenant;
+ final IndexedTenant ot = tenantRef.get();
ReadOnlyTransaction transaction =
dataProvider.newReadOnlyTransaction();
InstanceIdentifier<Tenant> tiid = TenantUtils.tenantIid(tenantId);
if (!result.isPresent()) return;
Tenant t = InheritanceUtils.resolveTenant((Tenant)result.get());
- if (!tenantRef.compareAndSet(ot, t)) {
+ IndexedTenant it = new IndexedTenant(t);
+ if (!tenantRef.compareAndSet(ot, it)) {
// concurrent update of tenant policy. Retry
updateTenant(tenantId);
} else {
return matches;
}
- private static class TenantContext {
- //TenantId tenantId;
+ protected static class TenantContext {
ListenerRegistration<DataChangeListener> registration;
- AtomicReference<Tenant> tenant = new AtomicReference<Tenant>();
+ AtomicReference<IndexedTenant> tenant = new AtomicReference<>();
- public TenantContext(TenantId tenantId,
- ListenerRegistration<DataChangeListener> registration) {
+ public TenantContext(ListenerRegistration<DataChangeListener> registration) {
super();
- //this.tenantId = tenantId;
this.registration = registration;
}
}
description
"The fields that identify an endpoint by a layer 2 address";
leaf l2-context {
- type gbp-common:l2-context-id;
+ type gbp-common:l2-bridge-domain-id;
description
- "The context for the layer 2 address for this endpoint";
+ "The bridge domain for the layer 2 address for this endpoint";
}
leaf mac-address {
type yang:mac-address;
}
}
}
+ /*
+ container of-overlay-operational {
+ description
+ "Operational parameters for the OpenFlow overlay renderer";
+
+ config false;
+ list data-plane-ordinal {
+ description
+ "Map elements of the policy to the id used on the network";
+ key "tenant id";
+ leaf tenant {
+ description "The tenant for the policy element";
+ type gbp-common:tenant-id;
+ }
+ leaf id {
+ description "The ID of the item";
+ type gbp-common:unique-id;
+ }
+ leaf ordinal {
+ description "The 32-bit ordinal for the item";
+ type uint32;
+ }
+ }
+ }
+ */
grouping endpoint-location {
description
"The location for this endpoint in the overlay network";
enum internal {
description
"The endpoint is located on a port that is part of
- the overlay network. You must include the node ID
- and port number for this endpoint.";
+ the overlay network. You must include the node
+ ID and port number for this endpoint.";
}
enum external {
description "This endpoint is not inside the overlay.";
leaf node-id {
description
"The OpenFlow switch for the endpoint. Must be included
- for all internal endpoints.";
+ for all internal endpoints. The format is
+ openflow:[dpid] where the dpid is the value of the
+ switch DPID cast to a long.";
type inv:node-id;
}
leaf node-connector-id {
description
- "The node connector for the endpoint's OpenFlow port";
+ "The node connector for the endpoint's OpenFlow port. The
+ format is openflow:[dpid]:[port] where the dpid is
+ the value of the switch DPID cast to a long, and port
+ is the openflow port number of the interface where
+ the endpoint is connected.";
type inv:node-connector-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.renderer.ofoverlay;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+
+/**
+ * Class for mocking up endpoints for unit tests
+ * @author readams
+ */
+public class MockEndpointManager extends EndpointManager {
+
+ public MockEndpointManager() {
+ super(null, null, null, null);
+ }
+
+ public void addEndpoint(Endpoint ep) {
+ updateEndpoint(null, ep);
+ }
+}
--- /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.groupbasedpolicy.resolver.PolicyResolver;
+
+public class MockPolicyManager extends PolicyManager {
+
+ public MockPolicyManager(PolicyResolver policyResolver,
+ EndpointManager endpointManager) {
+ super(null, policyResolver, null, endpointManager, null, null);
+ }
+
+}
--- /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.Collections;
+import java.util.Map;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.MockEndpointManager;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.MockPolicyManager;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable.FlowCtx;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable.FlowTableCtx;
+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.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+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.tenants.TenantBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomainBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2FloodDomainBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3ContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.SubnetBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.collect.ImmutableList;
+
+import static org.mockito.Mockito.*;
+
+public class FlowTableTest {
+ FlowTableCtx ctx;
+ FlowTable table;
+ MockEndpointManager endpointManager;
+ MockPolicyResolver policyResolver;
+ MockPolicyManager policyManager;
+
+ NodeId nodeId = new NodeId("openflow:1");
+ InstanceIdentifier<Table> tiid;
+
+ L3ContextId l3c = new L3ContextId("2cf51ee4-e996-467e-a277-2d380334a91d");
+ L2BridgeDomainId bd = new L2BridgeDomainId("c95182ba-7807-43f8-98f7-6c7c720b7639");
+ L2FloodDomainId fd = new L2FloodDomainId("98e1439e-52d2-46f8-bd69-5136e6088771");
+ SubnetId sub = new SubnetId("4fcf8dfc-53b5-4aef-84d3-6b5586992fcb");
+ TenantId tid = new TenantId("1118c691-8520-47ad-80b8-4cf5e3fe3302");
+ EndpointGroupId eg = new EndpointGroupId("36dec84a-08c7-497b-80b6-a0035af72a12");
+
+ public void initCtx() {
+ endpointManager = new MockEndpointManager();
+ policyResolver = new MockPolicyResolver();
+ policyManager = new MockPolicyManager(policyResolver, endpointManager);
+ ctx = new FlowTableCtx(null,
+ null,
+ policyManager,
+ policyResolver,
+ null,
+ endpointManager,
+ null);
+ }
+
+ public void setup() throws Exception {
+ tiid = FlowUtils.createTablePath(nodeId,
+ table.getTableId());
+ }
+
+ public TenantBuilder baseTenant() {
+ return new TenantBuilder()
+ .setId(tid)
+ .setEndpointGroup(ImmutableList.of(new EndpointGroupBuilder()
+ .setId(eg)
+ .setNetworkDomain(sub)
+ .build()))
+ .setL3Context(ImmutableList.of(new L3ContextBuilder()
+ .setId(l3c)
+ .build()))
+ .setL2BridgeDomain(ImmutableList.of(new L2BridgeDomainBuilder()
+ .setId(bd)
+ .setParent(l3c)
+ .build()))
+ .setL2FloodDomain(ImmutableList.of(new L2FloodDomainBuilder()
+ .setId(fd)
+ .setParent(bd)
+ .build()))
+ .setSubnet(ImmutableList.of(new SubnetBuilder()
+ .setId(sub)
+ .setParent(fd)
+ .setIpPrefix(new IpPrefix(new Ipv4Prefix("10.0.0.1/24")))
+ .build()));
+ }
+
+ public EndpointBuilder baseEP() {
+ OfOverlayContext ofc = new OfOverlayContextBuilder()
+ .setNodeId(nodeId)
+ .setNodeConnectorId(new NodeConnectorId(nodeId.getValue() + ":1"))
+ .build();
+ return new EndpointBuilder()
+ .addAugmentation(OfOverlayContext.class, ofc)
+ .setL2Context(bd)
+ .setTenant(tid)
+ .setEndpointGroup(eg)
+ .setMacAddress(new MacAddress("00:00:00:00:00:01"));
+ }
+
+ public ReadWriteTransaction dosync(Map<String, FlowCtx> flowMap)
+ throws Exception {
+ ReadWriteTransaction t = mock(ReadWriteTransaction.class);
+ if (flowMap == null)
+ flowMap = Collections.emptyMap();
+ table.sync(t, tiid, flowMap, nodeId, 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.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+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.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
+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.endpoint.fields.L3Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3AddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6Match;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableList;
+
+import static org.junit.Assert.*;
+
+import static org.mockito.Matchers.*;
+
+import static org.mockito.Mockito.*;
+
+public class PortSecurityTest extends FlowTableTest {
+ protected static final Logger LOG =
+ LoggerFactory.getLogger(PortSecurityTest.class);
+
+ @Before
+ public void setup() throws Exception {
+ initCtx();
+ table = new PortSecurity(ctx);
+ super.setup();
+ }
+
+ @Test
+ public void testDefaultDeny() throws Exception {
+ ReadWriteTransaction t = dosync(null);
+ ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
+ verify(t, times(4)).put(eq(LogicalDatastoreType.CONFIGURATION),
+ any(InstanceIdentifier.class), ac.capture());
+ int count = 0;
+
+ HashMap<String, FlowCtx> flowMap = new HashMap<>();
+ for (Flow f : ac.getAllValues()) {
+ flowMap.put(f.getId().getValue(), new FlowCtx(f));
+ Long etherType = null;
+ if (f.getMatch() != null) {
+ etherType = f.getMatch().getEthernetMatch()
+ .getEthernetType().getType().getValue().longValue();
+ }
+ if (f.getMatch() == null ||
+ PortSecurity.ARP.equals(etherType) ||
+ PortSecurity.IPv4.equals(etherType) ||
+ PortSecurity.IPv6.equals(etherType)) {
+ count += 1;
+ assertEquals(FlowUtils.dropInstructions(),
+ f.getInstructions());
+ }
+ }
+ assertEquals(4, count);
+ t = dosync(flowMap);
+ verify(t, never()).put(any(LogicalDatastoreType.class),
+ any(InstanceIdentifier.class),
+ any(Flow.class));
+ }
+
+ @Test
+ public void testL2() throws Exception {
+ List<L3Address> l3 = Collections.emptyList();
+ Endpoint ep = baseEP()
+ .setL3Address(l3)
+ .build();
+
+ endpointManager.addEndpoint(ep);
+ ReadWriteTransaction t = dosync(null);
+
+ ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
+ verify(t, atLeastOnce()).put(eq(LogicalDatastoreType.CONFIGURATION),
+ any(InstanceIdentifier.class), 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.getMatch() != null &&
+ f.getMatch().getEthernetMatch() != null &&
+ f.getMatch().getEthernetMatch().getEthernetSource() != null &&
+ Objects.equals(ep.getMacAddress(),
+ f.getMatch().getEthernetMatch()
+ .getEthernetSource().getAddress()) &&
+ Objects.equals(ep.getAugmentation(OfOverlayContext.class).getNodeConnectorId(),
+ f.getMatch().getInPort())) {
+ count += 1;
+ assertEquals(FlowUtils.gotoTable((short)(table.getTableId()+1)),
+ f.getInstructions());
+ }
+ }
+ assertEquals(1, count);
+ t = dosync(flowMap);
+ verify(t, never()).put(any(LogicalDatastoreType.class),
+ any(InstanceIdentifier.class),
+ any(Flow.class));
+ }
+
+ @Test
+ public void testL3() throws Exception {
+ Endpoint ep = baseEP()
+ .setL3Address(ImmutableList.of(new L3AddressBuilder()
+ .setIpAddress(new IpAddress(new Ipv4Address("10.10.10.10")))
+ .build(),
+ new L3AddressBuilder()
+ .setIpAddress(new IpAddress(new Ipv6Address("2001:db8:85a3::8a2e:370:7334")))
+ .build()))
+ .build();
+
+ endpointManager.addEndpoint(ep);
+ ReadWriteTransaction t = dosync(null);
+
+ ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
+ verify(t, atLeastOnce()).put(eq(LogicalDatastoreType.CONFIGURATION),
+ any(InstanceIdentifier.class), 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.getMatch() != null &&
+ Objects.equals(ep.getAugmentation(OfOverlayContext.class).getNodeConnectorId(),
+ f.getMatch().getInPort()) &&
+ ((f.getMatch().getLayer3Match() != null &&
+ f.getMatch().getLayer3Match() instanceof Ipv4Match &&
+ Objects.equals(ep.getL3Address().get(0).getIpAddress().getIpv4Address().getValue(),
+ ((Ipv4Match)f.getMatch().getLayer3Match()).getIpv4Source().getValue())) ||
+ (f.getMatch().getLayer3Match() != null &&
+ f.getMatch().getLayer3Match() instanceof ArpMatch &&
+ Objects.equals(ep.getL3Address().get(0).getIpAddress().getIpv4Address().getValue(),
+ ((ArpMatch)f.getMatch().getLayer3Match()).getArpSourceTransportAddress().getValue())) ||
+ (f.getMatch().getLayer3Match() != null &&
+ f.getMatch().getLayer3Match() instanceof Ipv6Match &&
+ Objects.equals(ep.getL3Address().get(1).getIpAddress().getIpv6Address().getValue(),
+ ((Ipv6Match)f.getMatch().getLayer3Match()).getIpv6Source().getValue())))) {
+ count += 1;
+ assertEquals(FlowUtils.gotoTable((short)(table.getTableId()+1)),
+ f.getInstructions());
+ }
+ }
+ assertEquals(3, count);
+ t = dosync(flowMap);
+ verify(t, never()).put(any(LogicalDatastoreType.class),
+ any(InstanceIdentifier.class),
+ any(Flow.class));
+ }
+}
--- /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.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.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+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 SourceMapperTest extends FlowTableTest {
+ protected static final Logger LOG =
+ LoggerFactory.getLogger(SourceMapperTest.class);
+ @Before
+ public void setup() throws Exception {
+ initCtx();
+ table = new SourceMapper(ctx);
+ super.setup();
+ }
+
+ @Test
+ public void testNoPolicy() throws Exception {
+ endpointManager.addEndpoint(baseEP().build());
+ ReadWriteTransaction t = dosync(null);
+ verify(t, never()).put(any(LogicalDatastoreType.class),
+ any(InstanceIdentifier.class),
+ any(Flow.class));
+ }
+
+ @Test
+ public void testMap() throws Exception {
+ Endpoint ep = baseEP().build();
+ endpointManager.addEndpoint(ep);
+ policyResolver.addTenant(baseTenant().build());
+
+ ReadWriteTransaction t = dosync(null);
+ ArgumentCaptor<Flow> ac = ArgumentCaptor.forClass(Flow.class);
+ verify(t, times(1)).put(eq(LogicalDatastoreType.CONFIGURATION),
+ any(InstanceIdentifier.class), 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 (Objects.equals(ep.getMacAddress(),
+ f.getMatch().getEthernetMatch().getEthernetSource().getAddress())) {
+ // XXX TODO verify register setting in the instructions
+ LOG.info("{}", f);
+ count += 1;
+ }
+
+ }
+ assertEquals(1, count);
+
+ t = dosync(flowMap);
+ verify(t, never()).put(any(LogicalDatastoreType.class),
+ any(InstanceIdentifier.class),
+ any(Flow.class));
+ }
+
+}
--- /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 org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
+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.TenantBuilder;
+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.L2BridgeDomainBuilder;
+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.L2FloodDomainBuilder;
+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.L3ContextBuilder;
+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.SubnetBuilder;
+
+import com.google.common.collect.ImmutableList;
+
+import static org.junit.Assert.*;
+
+public class IndexedTenantTest {
+
+ @Test
+ public void testResolveND() throws Exception {
+ SubnetId sid = new SubnetId("dd25397d-d829-4c8d-8c01-31f129b8de8f");
+ L3ContextId l3id = new L3ContextId("f2311f52-890f-4095-8b85-485ec8b92b3c");
+ L2BridgeDomainId bdid= new L2BridgeDomainId("70aeb9ea-4ca1-4fb9-9780-22b04b84a0d6");
+ L2FloodDomainId fdid = new L2FloodDomainId("252fbac6-bb6e-4d16-808d-6f56d20e5cca");
+
+ L3Context l3c = new L3ContextBuilder().setId(l3id).build();
+ L2BridgeDomain bd = new L2BridgeDomainBuilder()
+ .setParent(l3id)
+ .setId(bdid).build();
+ L2FloodDomain fd = new L2FloodDomainBuilder()
+ .setParent(bdid)
+ .setId(fdid).build();
+ Subnet s = new SubnetBuilder()
+ .setParent(fdid)
+ .setId(sid).build();
+ Tenant t = new TenantBuilder()
+ .setSubnet(ImmutableList.of(s))
+ .setL2BridgeDomain(ImmutableList.of(bd))
+ .setL3Context(ImmutableList.of(l3c))
+ .setL2FloodDomain(ImmutableList.of(fd))
+ .build();
+ IndexedTenant it = new IndexedTenant(t);
+
+ assertNotNull(it.getNetworkDomain(sid));
+ assertEquals(sid, it.resolveSubnet(sid).getId());
+ assertEquals(l3id, it.resolveL3Context(sid).getId());
+ assertEquals(bdid, it.resolveL2BridgeDomain(sid).getId());
+ assertEquals(fdid, it.resolveL2FloodDomain(sid).getId());
+ }
+}
--- /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 org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
+
+
+/**
+ * Mock version of policy resolver useful for tests
+ * @author readams
+ */
+public class MockPolicyResolver extends PolicyResolver {
+
+ public MockPolicyResolver() {
+ super(null, null);
+ }
+
+ public void addTenant(Tenant unresolvedTenant) {
+ TenantContext context = new TenantContext(null);
+ Tenant t = InheritanceUtils.resolveTenant(unresolvedTenant);
+ IndexedTenant it = new IndexedTenant(t);
+ context.tenant.set(it);
+ resolvedTenants.put(unresolvedTenant.getId(), context);
+ }
+}
assertEquals(1, rg.rules.size());
assertEquals(rule2.getName(), rg.rules.get(0).getName());
}
-
- @Test
- public void testUpdates() throws Exception {
- // test subscriptions and update notifications
- }
private static class ContractMatchKey {
TenantId tenant;