package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
-/*
- * 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
- */
-
import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.ChainActionFlows.createChainTunnelFlows;
import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxSetNsiAction;
import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxSetNspAction;
import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.sf.actions.ChainActionDefinition;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.FlowMap;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PolicyEnforcer.NetworkElements;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PolicyEnforcer.PolicyPair;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sfcutils.SfcIidFactory;
import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
import org.opendaylight.sfc.provider.api.SfcProviderServiceChainAPI;
import org.opendaylight.sfc.provider.api.SfcProviderServicePathAPI;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RspName;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SfcName;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInput;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInputBuilder;
import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.path.first.hop.info.RenderedServicePathFirstHop;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.IsRequired;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.Type;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.ParameterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinition;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinitionBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.supported.action.definition.SupportedParameterValues;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.supported.action.definition.SupportedParameterValuesBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlanGpe;
import org.slf4j.Logger;
/**
* Chain action for the OpenFlow Overlay renderer
* TODO: separate the generic definition from the concrete
- * implementation for the OpenFlow Ovelray renderer
+ * implementation for the OpenFlow Overlay renderer
*/
public class ChainAction extends Action {
private static final Logger LOG = LoggerFactory.getLogger(ChainAction.class);
- public static final ActionDefinitionId ID = new ActionDefinitionId("3d886be7-059f-4c4f-bbef-0356bea40933");
-
- public static final Integer CHAIN_CONDITION_GROUP = 0xfffffe;
-
- protected static final String TYPE = "type";
-
- // the chain action
- public static final String SFC_CHAIN_ACTION = "chain";
- // the parameter used for storing the chain name
- public static final String SFC_CHAIN_NAME = "sfc-chain-name";
-
- protected static final ActionDefinition DEF = new ActionDefinitionBuilder().setId(ID)
- .setName(new ActionName(SFC_CHAIN_ACTION))
- .setDescription(new Description("Send the traffic through a Service Function Chain"))
- .setParameter(
- (ImmutableList.of(new ParameterBuilder().setName(new ParameterName(SFC_CHAIN_NAME))
- .setDescription(new Description("The named chain to match against"))
- .setIsRequired(IsRequired.Required)
- .setType(Type.String)
- .build())))
- .build();
-
@Override
public ActionDefinitionId getId() {
- return ID;
+ return ChainActionDefinition.ID;
}
@Override
public ActionDefinition getActionDef() {
- return DEF;
+ return ChainActionDefinition.DEFINITION;
}
@Override
public List<ActionBuilder> updateAction(List<ActionBuilder> actions, Map<String, Object> params, Integer order,
- NetworkElements netElements, PolicyPair policyPair, FlowMap flowMap, OfContext ctx) {
+ NetworkElements netElements, PolicyPair policyPair, OfWriter ofWriter, OfContext ctx, Direction direction) {
/*
* Get the named chain
*/
- ServiceFunctionPath sfcPath = null;
String chainName = null;
if (params != null) {
- LOG.debug("ChainAction: Searching for named chain");
+ LOG.debug("updateAction: Searching for named chain");
for (String name : params.keySet()) {
if (name instanceof String) {
- if (name.equals(SFC_CHAIN_NAME)) {
+ if (name.equals(ChainActionDefinition.SFC_CHAIN_NAME)) {
chainName = (String) params.get(name);
if (chainName == null) {
- LOG.error("ChainAction: Chain name was null");
+ LOG.error("updateAction: Chain name was null");
return null;
}
- sfcPath = getSfcPath(chainName);
}
}
}
} else {
- LOG.error("ChainAction: Parameters null for chain action");
+ LOG.error("updateAction: Parameters null for chain action");
+ return null;
+ }
+
+ if (chainName == null) {
+ LOG.error("updateAction: Chain name was null");
return null;
}
/*
- * If path is symmetrical
- * if src == consumer, chainName
- * else src == provider, chainName-Reverse.
+ * If path is symmetrical then there are two RSPs.
+ * if srcEp is in consumer EPG use "rspName"
+ * else srcEp is in provider EPG, "rspName-Reverse".
*/
- if (sfcPath == null) {
- LOG.error("ChainAction: SFC Path null for chain {}", chainName);
+ ServiceFunctionPath sfcPath = getSfcPath(new SfcName(chainName));
+ if (sfcPath == null || sfcPath.getName() == null) {
+ LOG.error("updateAction: SFC Path was invalid. Either null or name was null.", sfcPath);
return null;
}
-
// Find existing RSP based on following naming convention, else create it.
- String rspName = sfcPath.getName() + "-gbp-rsp";
+ RspName rspName = new RspName(sfcPath.getName() + "-gbp-rsp");
ReadOnlyTransaction rTx = ctx.getDataBroker().newReadOnlyTransaction();
- RenderedServicePath renderedServicePath = getRspByName(rspName, rTx);
- if (renderedServicePath == null) {
- LOG.info("ChainAction: Could not find RSP {} for Chain {}", rspName, chainName);
-
- CreateRenderedPathInput rspInput = new CreateRenderedPathInputBuilder().setParentServiceFunctionPath(
- sfcPath.getName())
- .setName(rspName)
- .setSymmetric(Boolean.FALSE)
- .build();
- renderedServicePath = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(sfcPath, rspInput);
- if (renderedServicePath == null) {
- LOG.error("ChainAction: Could not find or create RSP for chain {}", chainName);
+ RenderedServicePath renderedServicePath;
+ RenderedServicePath rsp = getRspByName(rspName, rTx);
+ if (rsp == null) {
+ renderedServicePath = createRsp(sfcPath, rspName);
+ if (renderedServicePath != null) {
+ LOG.info("updateAction: Could not find RSP {} for Chain {}, created.", rspName, chainName);
+ } else {
+ LOG.error("updateAction: Could not create RSP {} for Chain {}", rspName, chainName);
return null;
}
+ } else {
+ renderedServicePath = rsp;
}
- RenderedServicePathFirstHop rspFirstHop = SfcProviderRenderedPathAPI.readRenderedServicePathFirstHop(rspName);
+ try {
+ if (sfcPath.isSymmetric() && direction.equals(Direction.Out)){
+ rspName = new RspName(rspName.getValue() + "-Reverse");
+ rsp = getRspByName(rspName, rTx);
+ if (rsp == null) {
+ LOG.info("updateAction: Could not find Reverse RSP {} for Chain {}", rspName, chainName);
+ renderedServicePath = createSymmetricRsp(renderedServicePath);
+ if (renderedServicePath == null) {
+ LOG.error("updateAction: Could not create RSP {} for Chain {}", rspName, chainName);
+ return null;
+ }
+ } else {
+ renderedServicePath = rsp;
+ }
+ }
+ } catch (Exception e) {
+ LOG.error("updateAction: Attemping to determine if srcEp {} was consumer.", netElements.getSrcEp().getKey(), e);
+ return null;
+ }
+ RenderedServicePathFirstHop rspFirstHop = SfcProviderRenderedPathAPI.readRenderedServicePathFirstHop(rspName);
if (!isValidRspFirstHop(rspFirstHop)) {
// Errors logged in method.
return null;
}
- NodeId tunnelDestNodeId;
- if (netElements.getDstNodeId().equals(netElements.getLocalNodeId())) {
- // Return destination is here
- tunnelDestNodeId = netElements.getLocalNodeId();
- } else {
- tunnelDestNodeId = netElements.getDstNodeId();
- }
+ NodeId tunnelDestNodeId=netElements.getDstNodeId();
- IpAddress tunnelDest = ctx.getSwitchManager().getTunnelIP(tunnelDestNodeId, TunnelTypeVxlanGpe.class);
+ Long returnVnid = (long) netElements.getSrcEpOrds().getTunnelId();
+ IpAddress tunnelDest = ctx.getSwitchManager().getTunnelIP(tunnelDestNodeId, TunnelTypeVxlanGpe.class);
if (tunnelDest == null || tunnelDest.getIpv4Address() == null) {
- LOG.error("ChainAction: Invalid tunnelDest for NodeId: {}", tunnelDestNodeId);
+ LOG.error("updateAction: Invalid tunnelDest for NodeId: {}", tunnelDestNodeId);
return null;
}
-
RenderedServicePathHop firstRspHop = renderedServicePath.getRenderedServicePathHop().get(0);
RenderedServicePathHop lastRspHop = Iterables.getLast(renderedServicePath.getRenderedServicePathHop());
-
SfcNshHeader sfcNshHeader = new SfcNshHeaderBuilder().setNshTunIpDst(rspFirstHop.getIp().getIpv4Address())
.setNshTunUdpPort(rspFirstHop.getPort())
.setNshNsiToChain(firstRspHop.getServiceIndex())
.setNshNsiFromChain((short) (lastRspHop.getServiceIndex().intValue() - 1))
.setNshNspFromChain(renderedServicePath.getPathId())
.setNshMetaC1(SfcNshHeader.convertIpAddressToLong(tunnelDest.getIpv4Address()))
- .setNshMetaC2((long) netElements.getSrcEpOrds().getTunnelId())
+ .setNshMetaC2(returnVnid)
.build();
- // Cannot set all actions here. Some actions are destination specific, and we don't know a destination is to be
- // chained until we reach this point. Need to write match/action in External Table for chained packets.
+ // Cannot set all actions here. Some actions are destination specific, and we don't know
+ // a destination is to be
+ // chained until we reach this point. Need to write match/action in External Table for
+ // chained packets.
actions = addActionBuilder(actions, nxSetNsiAction(sfcNshHeader.getNshNsiToChain()), order);
actions = addActionBuilder(actions, nxSetNspAction(sfcNshHeader.getNshNspToChain()), order);
+ createChainTunnelFlows(sfcNshHeader, netElements, ofWriter, ctx);
+ return actions;
+ }
- createChainTunnelFlows(sfcNshHeader, netElements, flowMap, ctx);
+ private RenderedServicePath createRsp(ServiceFunctionPath sfcPath, RspName rspName) {
+ CreateRenderedPathInput rspInput = new CreateRenderedPathInputBuilder().setParentServiceFunctionPath(
+ sfcPath.getName().getValue())
+ .setName(rspName.getValue())
+ .setSymmetric(sfcPath.isSymmetric())
+ .build();
+ return SfcProviderRenderedPathAPI.createRenderedServicePathAndState(sfcPath, rspInput);
+ }
- return actions;
+ private RenderedServicePath createSymmetricRsp(RenderedServicePath rsp) {
+ if (rsp == null) {
+ return null;
+ }
+ return SfcProviderRenderedPathAPI.createSymmetricRenderedServicePathAndState(rsp);
}
private boolean isValidRspFirstHop(RenderedServicePathFirstHop rspFirstHop) {
return valid;
}
- private RenderedServicePath getRspByName(String rspName, ReadOnlyTransaction rTx) {
+ private RenderedServicePath getRspByName(RspName rspName, ReadOnlyTransaction rTx) {
Optional<RenderedServicePath> optRsp = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
SfcIidFactory.rspIid(rspName), rTx);
if (optRsp.isPresent()) {
if (pv == null) {
return false;
}
- LOG.trace("Invoking RPC for chain {}", pv.getStringValue());
- ServiceFunctionChain chain = SfcProviderServiceChainAPI.readServiceFunctionChain(pv.getStringValue());
+ SfcName sfcName = new SfcName(pv.getStringValue());
+ LOG.trace("isValidGbpChain: Invoking RPC for chain {}", pv.getStringValue());
+ ServiceFunctionChain chain = SfcProviderServiceChainAPI.readServiceFunctionChain(sfcName);
return (chain != null);
}
- public ServiceFunctionPath getSfcPath(String chainName) {
-
+ public ServiceFunctionPath getSfcPath(SfcName chainName) {
ServiceFunctionPaths paths = SfcProviderServicePathAPI.readAllServiceFunctionPaths();
for (ServiceFunctionPath path : paths.getServiceFunctionPath()) {
if (path.getServiceChainName().equals(chainName)) {
if (paramValueList == null)
return null;
for (ParameterValue pv : paramValueList) {
- if (pv.getName().getValue().equals(SFC_CHAIN_NAME)) {
+ if (pv.getName().getValue().equals(ChainActionDefinition.SFC_CHAIN_NAME)) {
return pv;
}
}
return actions;
}
+ @Override
+ public List<SupportedParameterValues> getSupportedParameterValues() {
+ // supported parameter does not contain parameter type - it means all strings are supported
+ return ImmutableList.<SupportedParameterValues>of(new SupportedParameterValuesBuilder()
+ .setParameterName(new ParameterName(ChainActionDefinition.SFC_CHAIN_NAME)).build());
+ }
+
}