2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
11 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxNsiMatch;
12 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxNspMatch;
13 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxRegMatch;
14 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxTunIdMatch;
15 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxTunIpv4DstMatch;
16 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.applyActionIns;
17 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.gotoTableIns;
18 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.instructions;
19 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadNshc1RegAction;
20 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadNshc2RegAction;
21 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadRegAction;
22 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIPv4Action;
23 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIdAction;
24 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxOutputRegAction;
25 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.outputAction;
27 import java.math.BigInteger;
29 import org.apache.commons.lang3.StringUtils;
30 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
31 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
32 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager;
33 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
34 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;
35 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PolicyEnforcer.NetworkElements;
36 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
37 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.ChainAction;
38 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sfcutils.SfcNshHeader;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg4;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlanGpe;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
59 import com.google.common.annotations.VisibleForTesting;
61 public class ChainActionFlows {
63 private static final Logger LOG = LoggerFactory.getLogger(ChainAction.class);
65 public ChainActionFlows() {
69 public static void createChainTunnelFlows(SfcNshHeader sfcNshHeader, NetworkElements netElements, OfWriter ofWriter,
72 NodeId localNodeId = netElements.getLocalNodeId();
73 NodeId destNodeId = netElements.getDstEp().getAugmentation(OfOverlayContext.class).getNodeId();
74 EndpointFwdCtxOrdinals epOrdinals = netElements.getSrcEpOrdinals();
76 NodeConnectorId localNodeTunPort = ctx.getSwitchManager().getTunnelPort(localNodeId, TunnelTypeVxlanGpe.class);
77 NodeConnectorId destNodeTunPort = ctx.getSwitchManager().getTunnelPort(destNodeId, TunnelTypeVxlanGpe.class);
78 Ipv4Address tunDestAddress = ctx.getSwitchManager()
79 .getTunnelIP(netElements.getDstNodeId(), TunnelTypeVxlanGpe.class)
81 if (localNodeTunPort == null || destNodeTunPort == null) {
82 LOG.error("createChainTunnelFlows: No valid VXLAN GPE tunnel for Node {} or Node {}", localNodeId,
86 ofWriter.writeFlow(localNodeId, ctx.getPolicyManager().getTABLEID_PORTSECURITY(), allowFromChainPort(
87 sfcNshHeader, localNodeTunPort, ctx.getPolicyManager().getTABLEID_PORTSECURITY(), ctx));
89 ofWriter.writeFlow(localNodeId, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER(),
90 allowFromChainTunnel(localNodeTunPort, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER()));
92 ofWriter.writeFlow(localNodeId, ctx.getPolicyManager().getTABLEID_EXTERNAL_MAPPER(),
93 createExternalFlow(sfcNshHeader, localNodeTunPort, netElements,
94 ctx.getPolicyManager(), ctx.getSwitchManager(), tunDestAddress));
96 ofWriter.writeFlow(destNodeId, ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER(), createChainTunnelFlow(
97 sfcNshHeader, destNodeTunPort, epOrdinals, ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER(), ctx));
99 ofWriter.writeFlow(destNodeId, ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER(), createChainBroadcastFlow(
100 sfcNshHeader, destNodeTunPort, epOrdinals, ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER(), ctx));
103 private static Flow createChainBroadcastFlow(SfcNshHeader sfcNshHeader, NodeConnectorId tunPort,
104 EndpointFwdCtxOrdinals epFwdCtxOrds, short tableId, OfContext ctx) {
106 int fdId = epFwdCtxOrds.getFdId();
108 MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
110 addNxNsiMatch(mb, sfcNshHeader.getNshNsiFromChain());
111 addNxNspMatch(mb, sfcNshHeader.getNshNspFromChain());
112 addNxTunIdMatch(mb, fdId);
114 org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action fdReg =
115 nxLoadRegAction(NxmNxReg5.class, BigInteger.valueOf(fdId));
117 Match match = mb.build();
118 FlowId flowId = FlowIdUtils.newFlowId(tableId, "chainbroadcast", match);
120 FlowBuilder flowb = base(tableId).setId(flowId)
123 .setInstructions(instructions(applyActionIns(fdReg),
124 gotoTableIns(ctx.getPolicyManager().getTABLEID_DESTINATION_MAPPER())));
125 return flowb.build();
129 static Flow createExternalFlow(SfcNshHeader sfcNshHeader, NodeConnectorId tunPort, NetworkElements netElements,
130 PolicyManager policyManager, SwitchManager switchManager, Ipv4Address ipTunDest) {
132 short tableId = policyManager.getTABLEID_EXTERNAL_MAPPER();
133 org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadC1;
134 org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action outputAction;
136 Integer priority = 1000;
137 int matchTunnelId = sfcNshHeader.getNshMetaC2().intValue();
138 Long l3c = (long) netElements.getSrcEpOrdinals().getL3Id();
139 loadC1 = nxLoadNshc1RegAction(sfcNshHeader.getNshMetaC1());
141 // Test for if SFF is on same node
142 IpAddress ipAddress = switchManager.getTunnelIP(netElements.getLocalNodeId(), TunnelTypeVxlanGpe.class);
144 if (ipAddress != null && ipAddress.getIpv4Address().equals(sfcNshHeader.getNshTunIpDst())) {
145 Integer newPort = returnOfPortFromNodeConnector(tunPort);
146 outputAction = FlowUtils.createActionResubmit(newPort, policyManager.getTABLEID_SFC_EGRESS());
148 outputAction = outputAction(tunPort);
151 org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadC2 =
152 nxLoadNshc2RegAction(sfcNshHeader.getNshMetaC2());
153 org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadChainTunVnid =
154 nxLoadTunIdAction(BigInteger.valueOf(sfcNshHeader.getNshMetaC2()), false);
155 org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadChainTunDest =
156 nxLoadTunIPv4Action(sfcNshHeader.getNshTunIpDst().getValue(), false);
158 MatchBuilder mb = new MatchBuilder();
159 addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class, l3c));
160 addNxTunIdMatch(mb, matchTunnelId);
161 addNxNspMatch(mb, sfcNshHeader.getNshNspToChain());
162 addNxNsiMatch(mb, sfcNshHeader.getNshNsiToChain());
163 if (!netElements.getDstNodeId().equals(netElements.getSrcNodeId())) {
164 addNxTunIpv4DstMatch(mb, ipTunDest);
168 Match match = mb.build();
169 FlowId flowId = FlowIdUtils.newFlowId(tableId, "chainexternal", match);
171 base(tableId).setId(flowId).setPriority(priority).setMatch(match).setInstructions(
172 instructions(applyActionIns(loadC1, loadC2, loadChainTunDest, loadChainTunVnid, outputAction)));
173 return flowb.build();
176 private static Flow createChainTunnelFlow(SfcNshHeader sfcNshHeader, NodeConnectorId tunPort,
177 EndpointFwdCtxOrdinals epFwdCtxOrds, short tableId, OfContext ctx) {
179 int egId = epFwdCtxOrds.getEpgId();
180 int bdId = epFwdCtxOrds.getBdId();
181 int fdId = epFwdCtxOrds.getFdId();
182 int l3Id = epFwdCtxOrds.getL3Id();
183 int tunnelId = epFwdCtxOrds.getTunnelId();
185 MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
186 addNxTunIdMatch(mb, tunnelId);
187 addNxNspMatch(mb, sfcNshHeader.getNshNspFromChain());
188 addNxNsiMatch(mb, sfcNshHeader.getNshNsiFromChain());
190 org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action segReg =
191 nxLoadRegAction(NxmNxReg0.class, BigInteger.valueOf(egId));
192 org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action scgReg =
193 nxLoadRegAction(NxmNxReg1.class, BigInteger.valueOf(0xffffff));
194 org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action bdReg =
195 nxLoadRegAction(NxmNxReg4.class, BigInteger.valueOf(bdId));
196 org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action fdReg =
197 nxLoadRegAction(NxmNxReg5.class, BigInteger.valueOf(fdId));
198 org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action vrfReg =
199 nxLoadRegAction(NxmNxReg6.class, BigInteger.valueOf(l3Id));
201 Match match = mb.build();
202 FlowId flowId = FlowIdUtils.newFlowId(tableId, "chaintunnel", match);
204 base(tableId).setId(flowId).setPriority(150).setMatch(match).setInstructions(
205 instructions(applyActionIns(segReg, scgReg, bdReg, fdReg, vrfReg),
206 gotoTableIns(ctx.getPolicyManager().getTABLEID_DESTINATION_MAPPER())));
207 return flowb.build();
210 private static Flow allowFromChainPort(SfcNshHeader sfcNshHeader, NodeConnectorId port, short tableId,
213 // Matching on last NSP/NSI that SFF leaves on but with C1=0
214 MatchBuilder mb = new MatchBuilder();
215 FlowUtils.addNxNshc1RegMatch(mb, 0L);
216 FlowUtils.addNxNsiMatch(mb, sfcNshHeader.getNshNsiFromChain());
217 FlowUtils.addNxNspMatch(mb, sfcNshHeader.getNshNspFromChain());
218 Match match = mb.setInPort(port).build();
220 FlowId flowId = FlowIdUtils.newFlowId(tableId, "chainport", match);
222 base(tableId).setId(flowId).setPriority(1200).setMatch(match).setInstructions(
223 FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER()));
224 return flowb.build();
227 private static Flow allowFromChainTunnel(NodeConnectorId tunPort, short tableId) {
229 MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
230 addNxRegMatch(mb, RegMatch.of(NxmNxReg1.class, 0xffffffL));
231 Match match = mb.build();
232 FlowId flowId = FlowIdUtils.newFlowId(tableId, "chainport", match);
234 FlowBuilder flow = base(tableId).setId(flowId).setMatch(match).setPriority(65000).setInstructions(
235 instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
241 static Integer returnOfPortFromNodeConnector(NodeConnectorId nodeConnectorId) {
242 String[] elements = StringUtils.split(nodeConnectorId.getValue(), ":");
243 if (elements.length != 3)
245 return new Integer(elements[2]);
249 * Get a base flow builder with some common features already set
251 private static FlowBuilder base(short tableId) {
252 return new FlowBuilder().setTableId(tableId).setBarrier(false).setHardTimeout(0).setIdleTimeout(0);