private static final short TABLE_INDEX_PATH_MAPPER_ACL = 3;
private static final short TABLE_INDEX_NEXT_HOP = 4;
private static final short TABLE_INDEX_TRANSPORT_EGRESS = 10;
+ private static final short TABLE_INDEX_MAX_OFFSET = TABLE_INDEX_TRANSPORT_EGRESS;
private static final int FLOW_PRIORITY_TRANSPORT_INGRESS = 250;
private static final int FLOW_PRIORITY_ARP_TRANSPORT_INGRESS = 300;
// Instance variables
private short tableBase;
+ // TODO tableEgress is not implemented yet
+ // Used for app-coexistence
+ private short tableEgress;
private ExecutorService threadPoolExecutorService;
private Map<Long, List<FlowDetails>> rspNameToFlowsMap;
private Long flowRspId;
public SfcL2FlowProgrammerOFimpl() {
this.tableBase = (short) 0;
+ this.tableEgress = (short) 0;
this.rspNameToFlowsMap = new HashMap<Long, List<FlowDetails>>();
this.flowRspId = new Long(0);
this.tableBase = tableBase;
}
+ @Override
+ public short getTableEgress() {
+ return tableEgress;
+ }
+
+ @Override
+ public void setTableEgress(short tableEgress) {
+ this.tableEgress = tableEgress;
+ }
+
+ @Override
+ public short getMaxTableOffset() {
+ return TABLE_INDEX_MAX_OFFSET;
+ }
+
@Override
public void setFlowRspId(Long rspId) {
this.flowRspId = rspId;
ConfigureTableMatchAnyThread configureTableMatchAnyThread =
new ConfigureTableMatchAnyThread(
sffNodeName,
- getTableId(TABLE_INDEX_CLASSIFIER_TABLE),
- getTableId(TABLE_INDEX_INGRESS_TRANSPORT_TABLE),
+ TABLE_INDEX_CLASSIFIER_TABLE,
+ TABLE_INDEX_INGRESS_TRANSPORT_TABLE,
doDrop);
try {
threadPoolExecutorService.execute(configureTableMatchAnyThread);
//
@Override
public void configureTransportIngressTableMatchAny(final String sffNodeName, final boolean doDrop) {
- ConfigureTableMatchAnyThread configureTableMatchAnyThread = new ConfigureTableMatchAnyThread(sffNodeName,
- getTableId(TABLE_INDEX_INGRESS_TRANSPORT_TABLE), getTableId(TABLE_INDEX_PATH_MAPPER), doDrop);
+ ConfigureTableMatchAnyThread configureTableMatchAnyThread =
+ new ConfigureTableMatchAnyThread(
+ sffNodeName,
+ TABLE_INDEX_INGRESS_TRANSPORT_TABLE,
+ TABLE_INDEX_PATH_MAPPER,
+ doDrop);
try {
threadPoolExecutorService.execute(configureTableMatchAnyThread);
} catch (Exception ex) {
@Override
public void configurePathMapperTableMatchAny(final String sffNodeName, final boolean doDrop) {
- ConfigureTableMatchAnyThread configureTableMatchAnyThread = new ConfigureTableMatchAnyThread(sffNodeName,
- getTableId(TABLE_INDEX_PATH_MAPPER), getTableId(TABLE_INDEX_PATH_MAPPER_ACL), doDrop);
+ ConfigureTableMatchAnyThread configureTableMatchAnyThread =
+ new ConfigureTableMatchAnyThread(
+ sffNodeName,
+ TABLE_INDEX_PATH_MAPPER,
+ TABLE_INDEX_PATH_MAPPER_ACL,
+ doDrop);
try {
threadPoolExecutorService.execute(configureTableMatchAnyThread);
} catch (Exception ex) {
@Override
public void configurePathMapperAclTableMatchAny(final String sffNodeName, final boolean doDrop) {
- ConfigureTableMatchAnyThread configureTableMatchAnyThread = new ConfigureTableMatchAnyThread(sffNodeName,
- getTableId(TABLE_INDEX_PATH_MAPPER_ACL), getTableId(TABLE_INDEX_NEXT_HOP), doDrop);
+ ConfigureTableMatchAnyThread configureTableMatchAnyThread =
+ new ConfigureTableMatchAnyThread(
+ sffNodeName,
+ TABLE_INDEX_PATH_MAPPER_ACL,
+ TABLE_INDEX_NEXT_HOP,
+ doDrop);
try {
threadPoolExecutorService.execute(configureTableMatchAnyThread);
} catch (Exception ex) {
@Override
public void configureNextHopTableMatchAny(final String sffNodeName, final boolean doDrop) {
- ConfigureTableMatchAnyThread configureTableMatchAnyThread = new ConfigureTableMatchAnyThread(sffNodeName,
- getTableId(TABLE_INDEX_NEXT_HOP), getTableId(TABLE_INDEX_TRANSPORT_EGRESS), doDrop);
+ ConfigureTableMatchAnyThread configureTableMatchAnyThread =
+ new ConfigureTableMatchAnyThread(sffNodeName,
+ TABLE_INDEX_NEXT_HOP,
+ TABLE_INDEX_TRANSPORT_EGRESS,
+ doDrop);
try {
threadPoolExecutorService.execute(configureTableMatchAnyThread);
} catch (Exception ex) {
@Override
public void configureTransportEgressTableMatchAny(final String sffNodeName, final boolean doDrop) {
// This is the last table, cant set next table AND doDrop should be false
- ConfigureTableMatchAnyThread configureTableMatchAnyThread = new ConfigureTableMatchAnyThread(sffNodeName,
- getTableId(TABLE_INDEX_TRANSPORT_EGRESS), (short) -1, doDrop);
+ ConfigureTableMatchAnyThread configureTableMatchAnyThread =
+ new ConfigureTableMatchAnyThread(
+ sffNodeName,
+ TABLE_INDEX_TRANSPORT_EGRESS,
+ (short) -1,
+ doDrop);
try {
threadPoolExecutorService.execute(configureTableMatchAnyThread);
} catch (Exception ex) {
}
}
+ /**
+ * Configure MatchAny rules for the different tables used. When passing
+ * a tableIndex, it will be converted to the correct table internally.
+ *
+ * @author ebrjohn
+ *
+ */
private class ConfigureTableMatchAnyThread implements Runnable {
private String sffNodeName;
private boolean doDrop;
- private short tableId;
- private short nextTableId;
+ private short tableIdIndex;
+ private short nextTableIdIndex;
private Long rspId;
- public ConfigureTableMatchAnyThread(final String sffNodeName, final short tableId, final short nextTableId,
+ public ConfigureTableMatchAnyThread(final String sffNodeName, final short tableIdIndex, final short nextTableIdIndex,
final boolean doDrop) {
this.sffNodeName = sffNodeName;
- this.tableId = tableId;
- this.nextTableId = nextTableId;
+ this.tableIdIndex = tableIdIndex;
+ this.nextTableIdIndex = nextTableIdIndex;
this.doDrop = doDrop;
this.rspId = flowRspId;
}
public void run() {
try {
LOG.debug(
- "SfcProviderSffFlowWriter.ConfigureTableMatchAnyThread, sff [{}] tableId [{}] nextTableId [{}] doDrop {}",
- this.sffNodeName, this.tableId, this.nextTableId, this.doDrop);
+ "SfcProviderSffFlowWriter.ConfigureTableMatchAnyThread, sff [{}] tableIndex [{}] nextTableIndex [{}] doDrop {}",
+ this.sffNodeName, this.tableIdIndex, this.nextTableIdIndex, this.doDrop);
//
// Create the actions
} else {
//
// Action, goto Ingress table
- GoToTableBuilder gotoIngress = SfcOpenflowUtils.createActionGotoTable(this.nextTableId);
+ GoToTableBuilder gotoIngress =
+ SfcOpenflowUtils.createActionGotoTable(
+ getTableId(this.nextTableIdIndex));
InstructionBuilder ib = new InstructionBuilder();
ib.setKey(new InstructionKey(order));
//
// Create and configure the FlowBuilder
- FlowBuilder transportIngressFlow = SfcOpenflowUtils.createFlowBuilder(this.tableId,
- FLOW_PRIORITY_MATCH_ANY, "MatchAny", match, isb);
+ FlowBuilder transportIngressFlow = SfcOpenflowUtils.createFlowBuilder(
+ getTableId(this.tableIdIndex),
+ FLOW_PRIORITY_MATCH_ANY,
+ "MatchAny",
+ match,
+ isb);
writeFlowToConfig(rspId, sffNodeName, transportIngressFlow);
public void configureVxlanGpeTransportIngressFlow(final String sffNodeName) {
ConfigureTransportIngressThread configureIngressTransportThread =
new ConfigureTransportIngressThread(sffNodeName, SfcOpenflowUtils.ETHERTYPE_IPV4);
- configureIngressTransportThread.setNextTable(TABLE_INDEX_NEXT_HOP);
+ configureIngressTransportThread.setNextTableIndex(TABLE_INDEX_NEXT_HOP);
try {
threadPoolExecutorService.execute(configureIngressTransportThread);
} catch (Exception ex) {
String sffNodeName;
long etherType;
short ipProtocol;
- short nextTable;
+ short nextTableIndex;
Long rspId;
public ConfigureTransportIngressThread(final String sffNodeName, long etherType) {
this.sffNodeName = sffNodeName;
this.etherType = etherType;
this.ipProtocol = (short) -1;
- this.nextTable = TABLE_INDEX_PATH_MAPPER;
+ this.nextTableIndex = TABLE_INDEX_PATH_MAPPER;
this.rspId = flowRspId;
}
this.ipProtocol = ipProtocol;
}
- public void setNextTable(short nextTable) {
- this.nextTable = nextTable;
+ public void setNextTableIndex(short nextTableIndex) {
+ this.nextTableIndex = nextTableIndex;
}
@Override
//
// Action, goto the nextTable, defaults to Ingress table unless otherwise set
- GoToTableBuilder gotoIngress = SfcOpenflowUtils.createActionGotoTable(getTableId(this.nextTable));
+ GoToTableBuilder gotoIngress = SfcOpenflowUtils.createActionGotoTable(getTableId(this.nextTableIndex));
InstructionBuilder ib = new InstructionBuilder();
ib.setInstruction(new GoToTableCaseBuilder().setGoToTable(gotoIngress.build()).build());
//
// Create and configure the FlowBuilder
FlowBuilder transportIngressFlow =
- SfcOpenflowUtils.createFlowBuilder(TABLE_INDEX_INGRESS_TRANSPORT_TABLE,
- FLOW_PRIORITY_TRANSPORT_INGRESS, "ingress_Transport_Default_Flow", match, isb);
+ SfcOpenflowUtils.createFlowBuilder(
+ getTableId(TABLE_INDEX_INGRESS_TRANSPORT_TABLE),
+ FLOW_PRIORITY_TRANSPORT_INGRESS,
+ "ingress_Transport_Default_Flow",
+ match,
+ isb);
writeFlowToConfig(rspId, sffNodeName, transportIngressFlow);
// Create and configure the FlowBuilder
FlowBuilder transportIngressFlow =
- SfcOpenflowUtils.createFlowBuilder(TABLE_INDEX_INGRESS_TRANSPORT_TABLE,
- FLOW_PRIORITY_ARP_TRANSPORT_INGRESS, "ingress_Transport_Default_Flow", match, isb);
+ SfcOpenflowUtils.createFlowBuilder(
+ getTableId(TABLE_INDEX_INGRESS_TRANSPORT_TABLE),
+ FLOW_PRIORITY_ARP_TRANSPORT_INGRESS,
+ "ingress_Transport_Default_Flow",
+ match,
+ isb);
writeFlowToConfig(rspId, sffNodeName, transportIngressFlow);
//
// Create and configure the FlowBuilder
- FlowBuilder ingressFlow = SfcOpenflowUtils.createFlowBuilder(TABLE_INDEX_PATH_MAPPER, flowPriority,
- "nextHop", match, isb);
+ FlowBuilder ingressFlow = SfcOpenflowUtils.createFlowBuilder(
+ getTableId(TABLE_INDEX_PATH_MAPPER),
+ flowPriority,
+ "nextHop",
+ match,
+ isb);
writeFlowToConfig(rspId, sffNodeName, ingressFlow);
//
// Create and configure the FlowBuilder
- FlowBuilder ingressFlow = SfcOpenflowUtils.createFlowBuilder(TABLE_INDEX_PATH_MAPPER_ACL,
- FLOW_PRIORITY_PATH_MAPPER_ACL, "nextHop", match, isb);
+ FlowBuilder ingressFlow = SfcOpenflowUtils.createFlowBuilder(
+ getTableId(TABLE_INDEX_PATH_MAPPER_ACL),
+ FLOW_PRIORITY_PATH_MAPPER_ACL,
+ "nextHop",
+ match,
+ isb);
// Set an idle timeout on this flow
ingressFlow.setIdleTimeout(PKTIN_IDLE_TIMEOUT);
ApplyActionsBuilder aab = new ApplyActionsBuilder();
aab.setAction(actionList);
- GoToTableBuilder gotoTb = SfcOpenflowUtils.createActionGotoTable(TABLE_INDEX_TRANSPORT_EGRESS);
+ GoToTableBuilder gotoTb = SfcOpenflowUtils.createActionGotoTable(
+ getTableId(TABLE_INDEX_TRANSPORT_EGRESS));
InstructionBuilder gotoTbIb = new InstructionBuilder();
gotoTbIb.setInstruction(new GoToTableCaseBuilder().setGoToTable(gotoTb.build()).build());
//
// Create and configure the FlowBuilder
FlowBuilder nextHopFlow =
- SfcOpenflowUtils.createFlowBuilder(TABLE_INDEX_NEXT_HOP, flowPriority, "nextHop", match, isb);
+ SfcOpenflowUtils.createFlowBuilder(
+ getTableId(TABLE_INDEX_NEXT_HOP),
+ flowPriority,
+ "nextHop",
+ match,
+ isb);
writeFlowToConfig(rspId, sffNodeName, nextHopFlow);
// Put our Instruction in a list of Instructions
InstructionsBuilder isb = SfcOpenflowUtils.createInstructionsBuilder(ib);
- FlowBuilder egressTransportFlow = SfcOpenflowUtils.createFlowBuilder(TABLE_INDEX_TRANSPORT_EGRESS,
- flowPriority, TRANSPORT_EGRESS_COOKIE, "default_egress_flow", match, isb);
+ FlowBuilder egressTransportFlow = SfcOpenflowUtils.createFlowBuilder(
+ getTableId(TABLE_INDEX_TRANSPORT_EGRESS),
+ flowPriority,
+ TRANSPORT_EGRESS_COOKIE,
+ "default_egress_flow",
+ match,
+ isb);
//
// Now write the Flow Entry
//
// Create and configure the FlowBuilder
- FlowBuilder transportIngressFlow = SfcOpenflowUtils.createFlowBuilder(TABLE_INDEX_TRANSPORT_EGRESS,
- FLOW_PRIORITY_TRANSPORT_EGRESS + 10, "MatchAny", match, isb);
+ FlowBuilder transportIngressFlow = SfcOpenflowUtils.createFlowBuilder(
+ getTableId(TABLE_INDEX_TRANSPORT_EGRESS),
+ FLOW_PRIORITY_TRANSPORT_EGRESS + 10,
+ "MatchAny",
+ match,
+ isb);
writeFlowToConfig(rspId, sffNodeName, transportIngressFlow);
//
// Create and configure the FlowBuilder
FlowBuilder nextHopFlow =
- SfcOpenflowUtils.createFlowBuilder(TABLE_INDEX_NEXT_HOP, flowPriority, "nextHop", match, isb);
+ SfcOpenflowUtils.createFlowBuilder(
+ getTableId(TABLE_INDEX_NEXT_HOP),
+ flowPriority,
+ "nextHop",
+ match,
+ isb);
LOG.debug("writing group next hop flow: \n{}", nextHopFlow);
writeFlowToConfig(rspId, sffNodeName, nextHopFlow);
--- /dev/null
+/*
+ * Copyright (c) 2014, 2015 Ericsson 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.sfc.l2renderer.openflow;
+
+import java.util.Map.Entry;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.of.renderer.rev151123.SfcOfRendererConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import org.opendaylight.sfc.l2renderer.SfcL2AbstractDataListener;
+import org.opendaylight.sfc.l2renderer.SfcL2FlowProgrammerInterface;
+import org.opendaylight.sfc.l2renderer.SfcSynchronizer;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * DataListener to listen for SFC OpenFlow Renderer data store changes.
+ *
+ * @author ebrjohn
+ *
+ */
+public class SfcL2OfRendererDataListener extends SfcL2AbstractDataListener {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SfcL2OfRendererDataListener.class);
+ private SfcL2FlowProgrammerInterface sfcL2FlowProgrammer;
+ private SfcSynchronizer sfcSynchronizer;
+ private ExecutorService threadExecutor;
+
+ public SfcL2OfRendererDataListener(
+ DataBroker dataBroker,
+ SfcL2FlowProgrammerInterface sfcL2FlowProgrammer,
+ SfcSynchronizer sfcSynchronizer) {
+ setDataBroker(dataBroker);
+ setIID(InstanceIdentifier.builder(SfcOfRendererConfig.class).build());
+ registerAsDataChangeListener(LogicalDatastoreType.CONFIGURATION);
+ this.sfcL2FlowProgrammer = sfcL2FlowProgrammer;
+ this.sfcSynchronizer = sfcSynchronizer;
+ threadExecutor = Executors.newSingleThreadExecutor();
+ }
+
+ @Override
+ public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+ // SFC OF Renderer config create
+ for (Entry<InstanceIdentifier<?>, DataObject> entry : change.getCreatedData().entrySet()) {
+ if (entry.getValue() instanceof SfcOfRendererConfig) {
+ LOG.info("SfcL2OfRendererDataListener.onDataChanged create SFC OF Renderer config {}",
+ ((SfcOfRendererConfig) entry.getValue()));
+ processConfig((SfcOfRendererConfig) entry.getValue());
+ }
+ }
+
+ // SFC OF Renderer config update
+ for (Entry<InstanceIdentifier<?>, DataObject> entry : change.getUpdatedData().entrySet()) {
+ if (entry.getValue() instanceof SfcOfRendererConfig) {
+ LOG.info("SfcL2OfRendererDataListener.onDataChanged update SFC OF Renderer config {}",
+ ((SfcOfRendererConfig) entry.getValue()));
+ processConfig((SfcOfRendererConfig) entry.getValue());
+ }
+ }
+
+ // Not interested in deleted data
+ }
+
+ /**
+ * Process an OpenFlow Renderer configuration change. Only creates and
+ * updates are handled
+ * @param config the configuration details
+ */
+ private void processConfig(SfcOfRendererConfig config) {
+ if(verifyMaxTableId(config.getSfcOfTableOffset(), this.sfcL2FlowProgrammer.getMaxTableOffset()) == null) {
+ return;
+ }
+
+ if(verifyMaxTableId(config.getSfcOfAppEgressTableOffset(), (short) 0) == null) {
+ return;
+ }
+
+ UpdateOpenFlowTableOffsets updateThread =
+ new UpdateOpenFlowTableOffsets(
+ config.getSfcOfTableOffset(),
+ config.getSfcOfAppEgressTableOffset());
+
+ try {
+ threadExecutor.submit(updateThread);
+ } catch(Exception e) {
+ LOG.error("Error executing UpdateOpenFlowTableOffsets thread [{}]", e.toString());
+ }
+ }
+
+ /**
+ * Verify that the given tableOffset and optional maxTable is in range
+ *
+ * @param tableOffset the tableOffset to verify
+ * @param maxTable optionally the number of tables beyond tableOffset to be used
+ * @return a valid TableId or null if invalid
+ */
+ public TableId verifyMaxTableId(short tableOffset, short maxTable) {
+ try {
+ return new TableId((short) (tableOffset + maxTable));
+ } catch (IllegalArgumentException e) {
+ LOG.error("SfcL2OfRendererDataListener::verifyMaxTableId invalid table offset [{}] maxTable [{}]",
+ tableOffset, maxTable);
+ return null;
+ }
+ }
+
+ /**
+ * A thread to update the OpenFlow table offsets. A thread is needed, since
+ * we cant just update the table offsets while an RSP is being processed,
+ * so we need to wait until RSP processing is completed.
+ *
+ * @author ebrjohn
+ *
+ */
+ private class UpdateOpenFlowTableOffsets implements Runnable {
+
+ private short sfcOffsetTable;
+ private short sfcAppEgressTable;
+
+ public UpdateOpenFlowTableOffsets(short sfcOffsetTable, short sfcAppEgressTable) {
+ this.sfcOffsetTable = sfcOffsetTable;
+ this.sfcAppEgressTable = sfcAppEgressTable;
+ }
+
+ @Override
+ public void run() {
+ try {
+ sfcSynchronizer.lock();
+ sfcL2FlowProgrammer.setTableBase(this.sfcOffsetTable);
+ sfcL2FlowProgrammer.setTableEgress(this.sfcAppEgressTable);
+
+ LOG.info("UpdateOpenFlowTableOffsets complete tableOffset [{}] egressTable [{}]",
+ this.sfcOffsetTable, this.sfcAppEgressTable);
+ } finally {
+ sfcSynchronizer.unlock();
+ }
+ }
+ }
+}