1 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf;
4 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
6 * This program and the accompanying materials are made available under the
7 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
8 * and is available at http://www.eclipse.org/legal/epl-v10.html
11 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadNshc1RegAction;
12 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadNshc2RegAction;
13 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIPv4Action;
14 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIdAction;
15 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxSetNsiAction;
16 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxSetNspAction;
17 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.outputAction;
19 import java.math.BigInteger;
20 import java.util.List;
23 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PolicyEnforcer.NetworkElements;
24 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
25 import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
26 import org.opendaylight.sfc.provider.api.SfcProviderServiceChainAPI;
27 import org.opendaylight.sfc.provider.api.SfcProviderServicePathAPI;
28 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInput;
29 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInputBuilder;
30 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.path.first.hop.info.RenderedServicePathFirstHop;
31 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
32 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.ServiceFunctionChain;
33 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPaths;
34 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.IsRequired;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.Parameter.Type;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definition.ParameterBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinition;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinitionBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlanGpe;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
56 import com.google.common.collect.ImmutableList;
57 import com.google.common.net.InetAddresses;
60 * Chain action for the OpenFlow Overlay renderer
61 * TODO: separate the generic definition from the concrete
62 * implementation for the OpenFlow Ovelray renderer
64 public class ChainAction extends Action {
66 private static final Logger LOG = LoggerFactory.getLogger(ChainAction.class);
68 public static final ActionDefinitionId ID = new ActionDefinitionId("3d886be7-059f-4c4f-bbef-0356bea40933");
70 public static final Integer CHAIN_CONDITION_GROUP = 0xfffffe;
72 protected static final String TYPE = "type";
75 public static final String SFC_CHAIN_ACTION = "chain";
76 // the parameter used for storing the chain name
77 public static final String SFC_CHAIN_NAME = "sfc-chain-name";
79 protected static final ActionDefinition DEF = new ActionDefinitionBuilder().setId(ID)
80 .setName(new ActionName(SFC_CHAIN_ACTION))
81 .setDescription(new Description("Send the traffic through a Service Function Chain"))
83 (ImmutableList.of(new ParameterBuilder().setName(new ParameterName(SFC_CHAIN_NAME))
84 .setDescription(new Description("The named chain to match against"))
85 .setIsRequired(IsRequired.Required)
91 public ActionDefinitionId getId() {
96 public ActionDefinition getActionDef() {
101 public List<ActionBuilder> updateAction(List<ActionBuilder> actions,
102 Map<String, Object> params,
104 NetworkElements netElements) {
106 * Get the named chain
108 ServiceFunctionPath sfcPath = null;
109 String chainName = null;
110 if (params != null) {
111 LOG.debug("Searching for named chain");
112 for (String name : params.keySet()) {
113 if (name instanceof String) {
114 if (name.equals(SFC_CHAIN_NAME)) {
115 chainName = (String) params.get(name);
116 if (chainName == null) {
117 LOG.error("ChainAction: Chain name was null");
120 sfcPath = getSfcPath(chainName);
125 LOG.error("ChainAction: Parameters null for chain action");
129 if (sfcPath == null) {
130 LOG.error("ChainAction: SFC Path null for chain {}", chainName);
133 String rspName = sfcPath.getName() + "-gbp-rsp";
134 RenderedServicePathFirstHop rspFirstHop = SfcProviderRenderedPathAPI.readRenderedServicePathFirstHop(rspName);
135 if (rspFirstHop == null) {
136 LOG.info("ChainAction: Could not find RSP {} for Chain {}", rspName, chainName);
138 CreateRenderedPathInput rspInput = new CreateRenderedPathInputBuilder().setParentServiceFunctionPath(
141 .setSymmetric(Boolean.FALSE)
143 RenderedServicePath renderedServicePath = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(
145 if (renderedServicePath == null) {
146 LOG.error("Could not find or create RSP for chain {}", chainName);
149 rspFirstHop=SfcProviderRenderedPathAPI.readRenderedServicePathFirstHop(renderedServicePath.getName());
152 IpAddress sfcTunIpDst = rspFirstHop.getIp();
153 sfcTunIpDst.getIpv4Address();
154 if (sfcTunIpDst == null || sfcTunIpDst.getIpv4Address() == null || sfcTunIpDst.getIpv6Address() != null) {
155 LOG.error("Invalid IP Tunnel destination for SFC RSP First Hop {}", rspName);
158 PortNumber sfcTunUdpPort = rspFirstHop.getPort();
159 if (sfcTunUdpPort == null) {
160 LOG.error("Invalid UDP Port Number for SFC RSP {}", rspName);
163 Long sfcNsp = rspFirstHop.getPathId();
164 if (sfcNsp == null) {
165 LOG.error("Invalid NSP for SFC RSP {}", rspName);
168 Short sfcNsi = rspFirstHop.getStartingIndex();
169 if (sfcNsi == null) {
170 LOG.error("Invalid NSI for SFC RSP {}", rspName);
174 NodeConnectorId tunOpenFlowPort = SwitchManager.getTunnelPort(netElements.getNodeId(), TunnelTypeVxlanGpe.class);
177 * Setting NSH Network Context Headers for post-SFC encapsulation
178 * VXLAN header encap:
179 * - TunnelDestination IP: NSH C1
180 * - Tunnel ID (VNID) NSH C2
182 long postSfcTunnelDst = 999L;
183 IpAddress tunnelDest;
185 if (netElements.getDst().getAugmentation(OfOverlayContext.class).getNodeId().equals(netElements.getNodeId())) {
186 // Return destination is here
187 tunnelDest=SwitchManager.getTunnelIP(netElements.getNodeId(), TunnelTypeVxlanGpe.class);
189 tunnelDest=SwitchManager.getTunnelIP(netElements.getDst().getAugmentation(OfOverlayContext.class).getNodeId(), TunnelTypeVxlanGpe.class);
191 postSfcTunnelDst = (InetAddresses.coerceToInteger(InetAddresses.forString(tunnelDest.getIpv4Address().getValue()))) & 0xFFFFFFFFL;
193 // TunnelDestination after Chain
194 actions = addActionBuilder(actions, nxLoadNshc1RegAction(postSfcTunnelDst), order++);
196 actions = addActionBuilder(actions, nxLoadNshc2RegAction((long) netElements.getSrcOrds().getTunnelId()), order++);
199 * Set the tunnel destination IP
201 if (sfcTunIpDst.getIpv4Address() != null) {
202 String nextHop = sfcTunIpDst.getIpv4Address().getValue();
203 actions = addActionBuilder(actions, nxLoadTunIPv4Action(nextHop, false), order);
204 } else if (sfcTunIpDst.getIpv6Address() != null) {
205 LOG.error("IPv6 tunnel destination {} not supported", sfcTunIpDst.getIpv6Address().getValue());
208 // this shouldn't happen
209 LOG.error("Tunnel IP is invalid");
214 * Put TunID - with NSH we don't really care about this.
216 actions = addActionBuilder(actions,
217 nxLoadTunIdAction(BigInteger.valueOf(netElements.getSrcOrds().getTunnelId()), false), order);
220 * Set the NSH header fields, based on RSP
222 actions = addActionBuilder(actions,nxSetNsiAction(sfcNsi),order);
223 actions = addActionBuilder(actions,nxSetNspAction(sfcNsp),order);
225 * Set up the actions to send to the destination port
227 actions = addActionBuilder(actions,outputAction(tunOpenFlowPort), order);
232 private List<ActionBuilder> addActionBuilder(List<ActionBuilder> actions,
233 org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action action, Integer order) {
234 ActionBuilder ab = new ActionBuilder();
235 ab.setAction(action);
242 public boolean isValid(ActionInstance actionInstance) {
243 return validChain(actionInstance.getParameterValue());
246 private boolean validChain(List<ParameterValue> paramValue) {
247 ParameterValue pv = getChainNameParameter(paramValue);
251 LOG.trace("Invoking RPC for chain {}", pv.getStringValue());
252 ServiceFunctionChain chain = SfcProviderServiceChainAPI.readServiceFunctionChain(pv.getStringValue());
253 return chain != null;
256 public ServiceFunctionPath getSfcPath(String chainName) {
258 ServiceFunctionPaths paths = SfcProviderServicePathAPI.readAllServiceFunctionPaths();
259 for (ServiceFunctionPath path : paths.getServiceFunctionPath()) {
260 if (path.getServiceChainName().equals(chainName)) {
267 private ParameterValue getChainNameParameter(List<ParameterValue> paramValueList) {
268 if (paramValueList == null)
270 for (ParameterValue pv : paramValueList) {
271 if (pv.getName().getValue().equals(SFC_CHAIN_NAME)) {