import org.opendaylight.genius.utils.ServiceIndex;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
List<ListenableFuture<Void>> futures = new ArrayList<>();
BigInteger dpId = FlowBasedServicesUtils.getDpnIdFromInterface(ifState);
WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
+ Interface iface = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(ifState.getName(), dataBroker);
LOG.info("binding egress service for vlan port: {}", ifState.getName());
if (allServices.size() == 1) {
//calling LportDispatcherTableForService with current service index as 0 and next service index as
// some value since this is the only service bound.
- FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, boundServiceNew, ifState.getName(),
- transaction, ifState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX, (short) (boundServiceNew.getServicePriority() + 1));
+ FlowBasedServicesUtils.installEgressDispatcherFlows(dpId, boundServiceNew, ifState.getName(),
+ transaction, ifState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX, (short) (boundServiceNew.getServicePriority() + 1), iface);
if (transaction != null) {
futures.add(transaction.submit());
}
//In this case the match criteria of existing service should be changed.
BoundServices lower = FlowBasedServicesUtils.getHighAndLowPriorityService(allServices, low)[0];
short lowerServiceIndex = (short) ((lower != null) ? lower.getServicePriority() : low.getServicePriority() + 1);
- FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, low, ifState.getName(), transaction, ifState.getIfIndex(), low.getServicePriority(), lowerServiceIndex);
+ FlowBasedServicesUtils.installEgressDispatcherFlows(dpId, low, ifState.getName(), transaction, ifState.getIfIndex(),
+ low.getServicePriority(), lowerServiceIndex, iface);
} else {
currentServiceIndex = boundServiceNew.getServicePriority();
}
if (high != null) {
currentServiceIndex = boundServiceNew.getServicePriority();
if (high.equals(highest)) {
- FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, high, ifState.getName(), transaction, ifState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX, currentServiceIndex);
+ FlowBasedServicesUtils.installEgressDispatcherFlows(dpId, high, ifState.getName(), transaction, ifState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX, currentServiceIndex, iface);
} else {
- FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, high, ifState.getName(), transaction, ifState.getIfIndex(), high.getServicePriority(), currentServiceIndex);
+ FlowBasedServicesUtils.installEgressDispatcherFlows(dpId, high, ifState.getName(), transaction, ifState.getIfIndex(), high.getServicePriority(), currentServiceIndex, iface);
}
}
- FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, boundServiceNew, ifState.getName(), transaction, ifState.getIfIndex(), currentServiceIndex, nextServiceIndex);
+ FlowBasedServicesUtils.installEgressDispatcherFlows(dpId, boundServiceNew, ifState.getName(), transaction, ifState.getIfIndex(), currentServiceIndex, nextServiceIndex, iface);
futures.add(transaction.submit());
return futures;
}
import org.opendaylight.genius.mdsalutil.NwConstants;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
List<ListenableFuture<Void>> futures = new ArrayList<>();
WriteTransaction t = dataBroker.newWriteOnlyTransaction();
+ Interface iface = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(ifaceState.getName(), dataBroker);
BigInteger dpId = FlowBasedServicesUtils.getDpnIdFromInterface(ifaceState);
if (boundServices.isEmpty()) {
// Remove default entry from Lport Dispatcher Table.
- FlowBasedServicesUtils.removeEgressDispatcherFlow(dpId, ifaceState.getName(), boundServiceOld, t, NwConstants.DEFAULT_SERVICE_INDEX);
+ FlowBasedServicesUtils.removeEgressDispatcherFlows(dpId, ifaceState.getName(), boundServiceOld, t, NwConstants.DEFAULT_SERVICE_INDEX);
if (t != null) {
futures.add(t.submit());
}
BoundServices high = highLow[1];
// This means the one removed was the highest priority service
if (high == null) {
- FlowBasedServicesUtils.removeEgressDispatcherFlow(dpId, ifaceState.getName(), boundServiceOld, t, NwConstants.DEFAULT_SERVICE_INDEX);
+ FlowBasedServicesUtils.removeEgressDispatcherFlows(dpId, ifaceState.getName(), boundServiceOld, t, NwConstants.DEFAULT_SERVICE_INDEX);
if (low != null) {
//delete the lower services flow entry.
- FlowBasedServicesUtils.removeEgressDispatcherFlow(dpId, ifaceState.getName(), low, t, low.getServicePriority());
+ FlowBasedServicesUtils.removeEgressDispatcherFlows(dpId, ifaceState.getName(), low, t, low.getServicePriority());
BoundServices lower = FlowBasedServicesUtils.getHighAndLowPriorityService(boundServices, low)[0];
short lowerServiceIndex = (short) ((lower!=null) ? lower.getServicePriority() : low.getServicePriority() + 1);
- FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, low, ifaceState.getName(), t, ifaceState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX, lowerServiceIndex);
+ FlowBasedServicesUtils.installEgressDispatcherFlows(dpId, low, ifaceState.getName(), t, ifaceState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX, lowerServiceIndex, iface);
}
} else {
- FlowBasedServicesUtils.removeEgressDispatcherFlow(dpId, ifaceState.getName(), boundServiceOld, t, boundServiceOld.getServicePriority());
+ FlowBasedServicesUtils.removeEgressDispatcherFlows(dpId, ifaceState.getName(), boundServiceOld, t, boundServiceOld.getServicePriority());
short lowerServiceIndex = (short) ((low!=null) ? low.getServicePriority() : boundServiceOld.getServicePriority() + 1);
BoundServices highest = FlowBasedServicesUtils.getHighestPriorityService(boundServices);
if (high.equals(highest)) {
- FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, high, ifaceState.getName(),t, ifaceState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX, lowerServiceIndex);
+ FlowBasedServicesUtils.installEgressDispatcherFlows(dpId, high, ifaceState.getName(),t, ifaceState.getIfIndex(), NwConstants.DEFAULT_SERVICE_INDEX, lowerServiceIndex, iface);
} else {
- FlowBasedServicesUtils.installEgressDispatcherFlow(dpId, high, ifaceState.getName(),t, ifaceState.getIfIndex(), high.getServicePriority(), lowerServiceIndex);
+ FlowBasedServicesUtils.installEgressDispatcherFlows(dpId, high, ifaceState.getName(),t, ifaceState.getIfIndex(), high.getServicePriority(), lowerServiceIndex, iface);
}
}
futures.add(t.submit());
import org.opendaylight.genius.mdsalutil.MatchFieldType;
import org.opendaylight.genius.mdsalutil.MatchInfo;
import org.opendaylight.genius.mdsalutil.MatchInfoBase;
+import org.opendaylight.genius.mdsalutil.ActionInfo;
+import org.opendaylight.genius.mdsalutil.ActionType;
+import org.opendaylight.genius.mdsalutil.InstructionInfo;
+import org.opendaylight.genius.mdsalutil.InstructionType;
import org.opendaylight.genius.mdsalutil.MDSALUtil;
import org.opendaylight.genius.mdsalutil.MetaDataUtil;
import org.opendaylight.genius.mdsalutil.NwConstants;
import org.opendaylight.genius.mdsalutil.NxMatchFieldType;
import org.opendaylight.genius.utils.ServiceIndex;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
return matches;
}
- public static List<NxMatchInfo> getMatchInfoForEgressDispatcherTable(int interfaceTag, short serviceIndex) {
- List<NxMatchInfo> matches = new ArrayList<>();
+ public static List<MatchInfoBase> getMatchInfoForEgressDispatcherTable(int interfaceTag, short serviceIndex) {
+ List<MatchInfoBase> matches = new ArrayList<>();
matches.add(new NxMatchInfo(NxMatchFieldType.nxm_reg_6, new long[] {
MetaDataUtil.getReg6ValueForLPortDispatcher(interfaceTag, serviceIndex)}));
return matches;
WriteTransaction t, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
LOG.debug("Installing LPort Dispatcher Flow {}, {}", dpId, interfaceName);
String serviceRef = boundService.getServiceName();
- List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForDispatcherTable(dpId,
- interfaceTag, currentServiceIndex);
+ List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForDispatcherTable(dpId, interfaceTag, currentServiceIndex);
// Get the metadata and mask from the service's write metadata instruction
StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
installFlow(dpId, ingressFlow, t);
}
- public static void installEgressDispatcherFlow(BigInteger dpId, BoundServices boundService, String interfaceName,
- WriteTransaction t, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
+ public static void installEgressDispatcherFlows(BigInteger dpId, BoundServices boundService, String interfaceName,
+ WriteTransaction t, int interfaceTag, short currentServiceIndex,
+ short nextServiceIndex, Interface iface) {
LOG.debug("Installing Egress Dispatcher Flows {}, {}", dpId, interfaceName);
+ installEgressDispatcherFlow(dpId, boundService, interfaceName, t, interfaceTag, currentServiceIndex, nextServiceIndex);
+
+ // Install Split Horizon drop flow only for the default egress service - this flow drops traffic targeted to external interfaces if they arrived
+ // from an external interface (marked with the SH bit)
+ if (boundService.getServicePriority() == ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME, NwConstants.DEFAULT_EGRESS_SERVICE_INDEX)) {
+ installEgressDispatcherSplitHorizonFlow(dpId, boundService, interfaceName, t, interfaceTag, currentServiceIndex, iface);
+ }
+ }
+
+ private static void installEgressDispatcherFlow(BigInteger dpId, BoundServices boundService, String interfaceName,
+ WriteTransaction t, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
String serviceRef = boundService.getServiceName();
- List<? extends MatchInfoBase> matches;
- matches = FlowBasedServicesUtils.getMatchInfoForEgressDispatcherTable(interfaceTag, currentServiceIndex);
+ List<? extends MatchInfoBase> matches = FlowBasedServicesUtils.getMatchInfoForEgressDispatcherTable(interfaceTag, currentServiceIndex);
// Get the metadata and mask from the service's write metadata instruction
StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
// build the flow and install it
String flowRef = getFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, interfaceName, boundService, currentServiceIndex);
- Flow ingressFlow = MDSALUtil.buildFlowNew(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, flowRef,
+ Flow egressFlow = MDSALUtil.buildFlowNew(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, flowRef,
boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches, instructions);
- installFlow(dpId, ingressFlow, t);
+ installFlow(dpId, egressFlow, t);
}
+ public static void installEgressDispatcherSplitHorizonFlow(BigInteger dpId, BoundServices boundService, String interfaceName,
+ WriteTransaction t, int interfaceTag, short currentServiceIndex, Interface iface) {
+ // only install split horizon drop flows for external interfaces
+ if (!isExternal(iface)) {
+ return;
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Installing split horizon drop flow for external interface {} on dpId {}", interfaceName, dpId);
+ }
+
+ BigInteger shFlagSet = BigInteger.ONE; // BigInteger.ONE is used for checking the Split-Horizon flag
+ StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
+ List<MatchInfoBase> shMatches = FlowBasedServicesUtils.getMatchInfoForEgressDispatcherTable(interfaceTag, currentServiceIndex);
+ shMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] { shFlagSet, MetaDataUtil.METADATA_MASK_SH_FLAG }));
+ List<InstructionInfo> shInstructions = new ArrayList<>();
+ List<ActionInfo> actionsInfos = new ArrayList<>();
+ actionsInfos.add(new ActionInfo(ActionType.drop_action, new String[] {}));
+ shInstructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
+
+ String flowRef = getSplitHorizonFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, interfaceName, currentServiceIndex, shFlagSet);
+ String serviceRef = boundService.getServiceName();
+ int splitHorizonFlowPriority = boundService.getServicePriority() + 1; // this must be higher priority than the egress flow
+ Flow egressSplitHorizonFlow = MDSALUtil.buildFlow(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, flowRef,
+ splitHorizonFlowPriority, serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), shMatches, shInstructions);
+
+ installFlow(dpId, egressSplitHorizonFlow, t);
+ }
public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
BigInteger cookie, List<Instruction> instructions) {
t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
}
- public static void removeEgressDispatcherFlow(BigInteger dpId, String iface, BoundServices boundServicesOld, WriteTransaction t, short currentServiceIndex) {
+ public static void removeEgressDispatcherFlows(BigInteger dpId, String iface, BoundServices boundServicesOld, WriteTransaction t, short currentServiceIndex) {
LOG.debug("Removing Egress Dispatcher Flows {}, {}", dpId, iface);
+ removeEgressDispatcherFlow(dpId, iface, t, currentServiceIndex, boundServicesOld);
+ removeEgressSplitHorizonDispatcherFlow(dpId, iface, t, currentServiceIndex);
+ }
+
+ private static void removeEgressDispatcherFlow(BigInteger dpId, String iface, WriteTransaction t,
+ short currentServiceIndex, BoundServices boundServicesOld) {
// build the flow and install it
String flowRef = getFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, iface, boundServicesOld, currentServiceIndex);
FlowKey flowKey = new FlowKey(new FlowId(flowRef));
t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
}
+ public static void removeEgressSplitHorizonDispatcherFlow(BigInteger dpId, String iface, WriteTransaction t, short currentServiceIndex) {
+ BigInteger shFlagSet = BigInteger.ONE; // BigInteger.ONE is used for checking the Split-Horizon flag
+ String shFlowRef = getSplitHorizonFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, iface, currentServiceIndex, shFlagSet);
+ FlowKey shFlowKey = new FlowKey(new FlowId(shFlowRef));
+ Node nodeDpn = buildInventoryDpnNode(dpId);
+ InstanceIdentifier<Flow> shFlowInstanceId = InstanceIdentifier.builder(Nodes.class)
+ .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
+ .child(Table.class, new TableKey(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE)).child(Flow.class, shFlowKey).build();
+
+ t.delete(LogicalDatastoreType.CONFIGURATION, shFlowInstanceId);
+ }
+
private static String getFlowRef(BigInteger dpnId, short tableId, String iface, BoundServices service, short currentServiceIndex) {
return new StringBuffer().append(dpnId).append(tableId).append(NwConstants.FLOWID_SEPARATOR)
.append(iface).append(NwConstants.FLOWID_SEPARATOR).append(currentServiceIndex).toString();
}
+ private static String getSplitHorizonFlowRef(BigInteger dpnId, short tableId, String iface, short currentServiceIndex, BigInteger shFlag) {
+ return new StringBuffer().append(dpnId).append(tableId).append(NwConstants.FLOWID_SEPARATOR)
+ .append(iface).append(NwConstants.FLOWID_SEPARATOR).append(shFlag.toString()).toString();
+ }
/**
* This util method returns an array of ServiceInfo in which index 0 will
* have the immediate lower priority service and index 1 will have the