5e5970196069fd4226125a27ee251d50a9a58846
[groupbasedpolicy.git] / renderers / ofoverlay / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ofoverlay / flow / ChainActionFlows.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
10
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;
26
27 import java.math.BigInteger;
28
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;
58
59 import com.google.common.annotations.VisibleForTesting;
60
61 public class ChainActionFlows {
62
63     private static final Logger LOG = LoggerFactory.getLogger(ChainAction.class);
64
65     public ChainActionFlows() {
66
67     }
68
69     public static void createChainTunnelFlows(SfcNshHeader sfcNshHeader, NetworkElements netElements, OfWriter ofWriter,
70             OfContext ctx) {
71
72         NodeId localNodeId = netElements.getLocalNodeId();
73         NodeId destNodeId = netElements.getDstEp().getAugmentation(OfOverlayContext.class).getNodeId();
74         EndpointFwdCtxOrdinals epOrdinals = netElements.getSrcEpOrdinals();
75
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)
80             .getIpv4Address();
81         if (localNodeTunPort == null || destNodeTunPort == null) {
82             LOG.error("createChainTunnelFlows: No valid VXLAN GPE tunnel for Node {} or Node {}", localNodeId,
83                     destNodeId);
84             return;
85         }
86         ofWriter.writeFlow(localNodeId, ctx.getPolicyManager().getTABLEID_PORTSECURITY(), allowFromChainPort(
87                 sfcNshHeader, localNodeTunPort, ctx.getPolicyManager().getTABLEID_PORTSECURITY(), ctx));
88
89         ofWriter.writeFlow(localNodeId, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER(),
90                 allowFromChainTunnel(localNodeTunPort, ctx.getPolicyManager().getTABLEID_POLICY_ENFORCER()));
91
92         ofWriter.writeFlow(localNodeId, ctx.getPolicyManager().getTABLEID_EXTERNAL_MAPPER(),
93                 createExternalFlow(sfcNshHeader, localNodeTunPort, netElements,
94                         ctx.getPolicyManager(), ctx.getSwitchManager(), tunDestAddress));
95
96         ofWriter.writeFlow(destNodeId, ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER(), createChainTunnelFlow(
97                 sfcNshHeader, destNodeTunPort, epOrdinals, ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER(), ctx));
98
99         ofWriter.writeFlow(destNodeId, ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER(), createChainBroadcastFlow(
100                 sfcNshHeader, destNodeTunPort, epOrdinals, ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER(), ctx));
101     }
102
103     private static Flow createChainBroadcastFlow(SfcNshHeader sfcNshHeader, NodeConnectorId tunPort,
104             EndpointFwdCtxOrdinals epFwdCtxOrds, short tableId, OfContext ctx) {
105
106         int fdId = epFwdCtxOrds.getFdId();
107
108         MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
109
110         addNxNsiMatch(mb, sfcNshHeader.getNshNsiFromChain());
111         addNxNspMatch(mb, sfcNshHeader.getNshNspFromChain());
112         addNxTunIdMatch(mb, fdId);
113
114         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action fdReg =
115                 nxLoadRegAction(NxmNxReg5.class, BigInteger.valueOf(fdId));
116
117         Match match = mb.build();
118         FlowId flowId = FlowIdUtils.newFlowId(tableId, "chainbroadcast", match);
119
120         FlowBuilder flowb = base(tableId).setId(flowId)
121             .setPriority(150)
122             .setMatch(match)
123             .setInstructions(instructions(applyActionIns(fdReg),
124                     gotoTableIns(ctx.getPolicyManager().getTABLEID_DESTINATION_MAPPER())));
125         return flowb.build();
126     }
127
128     @VisibleForTesting
129     static Flow createExternalFlow(SfcNshHeader sfcNshHeader, NodeConnectorId tunPort, NetworkElements netElements,
130                                    PolicyManager policyManager, SwitchManager switchManager, Ipv4Address ipTunDest) {
131
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;
135
136         Integer priority = 1000;
137         int matchTunnelId = sfcNshHeader.getNshMetaC2().intValue();
138         Long l3c = (long) netElements.getSrcEpOrdinals().getL3Id();
139         loadC1 = nxLoadNshc1RegAction(sfcNshHeader.getNshMetaC1());
140
141         // Test for if SFF is on same node
142         IpAddress ipAddress = switchManager.getTunnelIP(netElements.getLocalNodeId(), TunnelTypeVxlanGpe.class);
143
144         if (ipAddress != null && ipAddress.getIpv4Address().equals(sfcNshHeader.getNshTunIpDst())) {
145             Integer newPort = returnOfPortFromNodeConnector(tunPort);
146             outputAction = FlowUtils.createActionResubmit(newPort, policyManager.getTABLEID_SFC_EGRESS());
147         } else {
148             outputAction = outputAction(tunPort);
149         }
150
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);
157
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);
165             priority = 1500;
166         }
167
168         Match match = mb.build();
169         FlowId flowId = FlowIdUtils.newFlowId(tableId, "chainexternal", match);
170         FlowBuilder flowb =
171                 base(tableId).setId(flowId).setPriority(priority).setMatch(match).setInstructions(
172                         instructions(applyActionIns(loadC1, loadC2, loadChainTunDest, loadChainTunVnid, outputAction)));
173         return flowb.build();
174     }
175
176     private static Flow createChainTunnelFlow(SfcNshHeader sfcNshHeader, NodeConnectorId tunPort,
177             EndpointFwdCtxOrdinals epFwdCtxOrds, short tableId, OfContext ctx) {
178
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();
184
185         MatchBuilder mb = new MatchBuilder().setInPort(tunPort);
186         addNxTunIdMatch(mb, tunnelId);
187         addNxNspMatch(mb, sfcNshHeader.getNshNspFromChain());
188         addNxNsiMatch(mb, sfcNshHeader.getNshNsiFromChain());
189
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));
200
201         Match match = mb.build();
202         FlowId flowId = FlowIdUtils.newFlowId(tableId, "chaintunnel", match);
203         FlowBuilder flowb =
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();
208     }
209
210     private static Flow allowFromChainPort(SfcNshHeader sfcNshHeader, NodeConnectorId port, short tableId,
211             OfContext ctx) {
212
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();
219
220         FlowId flowId = FlowIdUtils.newFlowId(tableId, "chainport", match);
221         FlowBuilder flowb =
222                 base(tableId).setId(flowId).setPriority(1200).setMatch(match).setInstructions(
223                         FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER()));
224         return flowb.build();
225     }
226
227     private static Flow allowFromChainTunnel(NodeConnectorId tunPort, short tableId) {
228
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);
233
234         FlowBuilder flow = base(tableId).setId(flowId).setMatch(match).setPriority(65000).setInstructions(
235                 instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));
236         return flow.build();
237
238     }
239
240     @VisibleForTesting
241     static Integer returnOfPortFromNodeConnector(NodeConnectorId nodeConnectorId) {
242         String[] elements = StringUtils.split(nodeConnectorId.getValue(), ":");
243         if (elements.length != 3)
244             return null;
245         return new Integer(elements[2]);
246     }
247
248     /**
249      * Get a base flow builder with some common features already set
250      */
251     private static FlowBuilder base(short tableId) {
252         return new FlowBuilder().setTableId(tableId).setBarrier(false).setHardTimeout(0).setIdleTimeout(0);
253     }
254 }