Merge "add rest of sfc flows"
[netvirt.git] / openstack / net-virt-sfc / impl / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / sfc / workaround / services / SfcClassifierService.java
1 /*
2  * Copyright © 2015 Red Hat, 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.ovsdb.openstack.netvirt.sfc.workaround.services;
10
11 import com.google.common.collect.Lists;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.List;
15 import org.opendaylight.ovsdb.openstack.netvirt.providers.ConfigInterface;
16 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
17 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
18 import org.opendaylight.ovsdb.openstack.netvirt.sfc.ISfcClassifierService;
19 import org.opendaylight.ovsdb.openstack.netvirt.sfc.NshUtils;
20 import org.opendaylight.ovsdb.utils.mdsal.openflow.ActionUtils;
21 import org.opendaylight.ovsdb.utils.mdsal.openflow.FlowUtils;
22 import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
23 import org.opendaylight.ovsdb.utils.mdsal.openflow.MatchUtils;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Matches;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.AceEth;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
43 import org.osgi.framework.BundleContext;
44 import org.osgi.framework.ServiceReference;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48 public class SfcClassifierService extends AbstractServiceInstance implements ConfigInterface, ISfcClassifierService {
49     private static final Logger LOG = LoggerFactory.getLogger(SfcClassifierService.class);
50     private static final short TABLE_0 = 0;
51     private static final short UDP_SHORT = 17;
52
53     public SfcClassifierService(Service service) {
54         super(service);
55     }
56
57     public SfcClassifierService() {
58         super(Service.SFC_CLASSIFIER);
59     }
60
61     @Override
62     public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
63         super.setDependencies(bundleContext.getServiceReference(ISfcClassifierService.class.getName()), this);
64     }
65
66     @Override
67     public void setDependencies(Object impl) {}
68
69     @Override
70     public void programIngressClassifier(long dataPathId, String ruleName, Matches matches,
71                                          NshUtils nshHeader, long vxGpeOfPort, boolean write) {
72         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
73         FlowBuilder flowBuilder = new FlowBuilder();
74
75         MatchBuilder matchBuilder = buildMatch(matches);
76         flowBuilder.setMatch(matchBuilder.build());
77         flowBuilder.setMatch(MatchUtils.addNxRegMatch(
78                 matchBuilder,
79                 new MatchUtils.RegMatch(FlowUtils.REG_FIELD, FlowUtils.REG_VALUE_FROM_LOCAL)).build());
80
81         String flowId = "sfcIngressClass_" + ruleName;// + "_" + nshHeader.getNshNsp();
82         flowBuilder.setId(new FlowId(flowId));
83         FlowKey key = new FlowKey(new FlowId(flowId));
84         flowBuilder.setBarrier(true);
85         flowBuilder.setTableId(getTable());
86         flowBuilder.setKey(key);
87         flowBuilder.setFlowName(flowId);
88         flowBuilder.setHardTimeout(0);
89         flowBuilder.setIdleTimeout(0);
90
91         if (write) {
92             ActionBuilder ab = new ActionBuilder();
93             List<Action> actionList = new ArrayList<>();
94
95             ab.setAction(ActionUtils.nxMoveTunIdtoNshc2());
96             ab.setOrder(actionList.size());
97             ab.setKey(new ActionKey(actionList.size()));
98             actionList.add(ab.build());
99
100             getNshAction(nshHeader, actionList);
101
102             ab.setAction(ActionUtils.outputAction(FlowUtils.getNodeConnectorId(dataPathId, vxGpeOfPort)));
103             ab.setOrder(actionList.size());
104             ab.setKey(new ActionKey(actionList.size()));
105             actionList.add(ab.build());
106
107             ApplyActionsBuilder aab = new ApplyActionsBuilder();
108             aab.setAction(actionList);
109
110             InstructionBuilder ib = new InstructionBuilder();
111             ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
112             ib.setOrder(0);
113             ib.setKey(new InstructionKey(0));
114             List<Instruction> instructions = Lists.newArrayList();
115             instructions.add(ib.build());
116
117             InstructionsBuilder isb = new InstructionsBuilder();
118             isb.setInstruction(instructions);
119             flowBuilder.setInstructions(isb.build());
120             writeFlow(flowBuilder, nodeBuilder);
121         } else {
122             removeFlow(flowBuilder, nodeBuilder);
123         }
124     }
125
126     @Override
127     public void programSfcTable(long dataPathId, long vxGpeOfPort, short goToTableId, boolean write) {
128         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
129         FlowBuilder flowBuilder = new FlowBuilder();
130
131         MatchBuilder matchBuilder = new MatchBuilder();
132         flowBuilder.setMatch(MatchUtils.createInPortMatch(matchBuilder, dataPathId, vxGpeOfPort).build());
133
134         String flowId = "sfcTable_" + vxGpeOfPort;
135         flowBuilder.setId(new FlowId(flowId));
136         FlowKey key = new FlowKey(new FlowId(flowId));
137         flowBuilder.setBarrier(true);
138         flowBuilder.setTableId(TABLE_0);
139         flowBuilder.setKey(key);
140         flowBuilder.setFlowName(flowId);
141         flowBuilder.setHardTimeout(0);
142         flowBuilder.setIdleTimeout(0);
143         flowBuilder.setPriority(1000);
144
145         if (write) {
146             InstructionsBuilder isb = new InstructionsBuilder();
147             List<Instruction> instructions = Lists.newArrayList();
148             InstructionBuilder ib =
149                     InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), goToTableId);
150             ib.setOrder(0);
151             ib.setKey(new InstructionKey(0));
152             instructions.add(ib.build());
153
154             isb.setInstruction(instructions);
155             flowBuilder.setInstructions(isb.build());
156             writeFlow(flowBuilder, nodeBuilder);
157         } else {
158             removeFlow(flowBuilder, nodeBuilder);
159         }
160     }
161
162     @Override
163     public void programEgressClassifier1(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
164                                          int tunnelOfPort, int tunnelId, short gotoTableId, boolean write) {
165         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
166         FlowBuilder flowBuilder = new FlowBuilder();
167
168         MatchBuilder matchBuilder = new MatchBuilder();
169         flowBuilder.setMatch(MatchUtils.createInPortMatch(matchBuilder, dataPathId, vxGpeOfPort).build());
170         flowBuilder.setMatch(MatchUtils.addNxNspMatch(matchBuilder, nsp).build());
171         flowBuilder.setMatch(MatchUtils.addNxNsiMatch(matchBuilder, nsi).build());
172
173         String flowId = "sfcEgressClass1_" + vxGpeOfPort;
174         flowBuilder.setId(new FlowId(flowId));
175         FlowKey key = new FlowKey(new FlowId(flowId));
176         flowBuilder.setBarrier(true);
177         flowBuilder.setTableId(TABLE_0);
178         flowBuilder.setKey(key);
179         flowBuilder.setFlowName(flowId);
180         flowBuilder.setHardTimeout(0);
181         flowBuilder.setIdleTimeout(0);
182
183         if (write) {
184             InstructionsBuilder isb = new InstructionsBuilder();
185             List<Instruction> instructions = Lists.newArrayList();
186             List<Action> actionList = Lists.newArrayList();
187
188             ActionBuilder ab = new ActionBuilder();
189             ab.setAction(ActionUtils.nxMoveNshc2ToTunId());
190             ab.setOrder(0);
191             ab.setKey(new ActionKey(0));
192             actionList.add(ab.build());
193
194             ApplyActionsBuilder aab = new ApplyActionsBuilder();
195             aab.setAction(actionList);
196             InstructionBuilder ib = new InstructionBuilder();
197             ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
198
199             ib.setOrder(0);
200             ib.setKey(new InstructionKey(0));
201             instructions.add(ib.build());
202
203             ib = InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), getTable());
204             ib.setOrder(1);
205             ib.setKey(new InstructionKey(1));
206             instructions.add(ib.build());
207
208             isb.setInstruction(instructions);
209             flowBuilder.setInstructions(isb.build());
210             writeFlow(flowBuilder, nodeBuilder);
211         } else {
212             removeFlow(flowBuilder, nodeBuilder);
213         }
214     }
215
216     @Override
217     public void programEgressClassifier2(long dataPathId, long vxGpeOfPort, long nsp, short nsi,
218                                          int tunnelOfPort, int tunnelId, boolean write) {
219         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
220         FlowBuilder flowBuilder = new FlowBuilder();
221
222         MatchBuilder matchBuilder = new MatchBuilder();
223         flowBuilder.setMatch(MatchUtils.createInPortMatch(matchBuilder, dataPathId, vxGpeOfPort).build());
224         flowBuilder.setMatch(MatchUtils.addNxNspMatch(matchBuilder, nsp).build());
225         flowBuilder.setMatch(MatchUtils.addNxNsiMatch(matchBuilder, nsi).build());
226
227         String flowId = "sfcEgressClass2_" + vxGpeOfPort;
228         flowBuilder.setId(new FlowId(flowId));
229         FlowKey key = new FlowKey(new FlowId(flowId));
230         flowBuilder.setBarrier(true);
231         flowBuilder.setTableId(getTable());
232         flowBuilder.setKey(key);
233         flowBuilder.setFlowName(flowId);
234         flowBuilder.setHardTimeout(0);
235         flowBuilder.setIdleTimeout(0);
236
237         if (write) {
238             InstructionsBuilder isb = new InstructionsBuilder();
239             List<Instruction> instructions = Lists.newArrayList();
240             List<Action> actionList = Lists.newArrayList();
241
242             ActionBuilder ab = new ActionBuilder();
243             ab.setAction(ActionUtils.nxResubmitAction(tunnelOfPort, TABLE_0));
244             ab.setOrder(0);
245             ab.setKey(new ActionKey(0));
246             actionList.add(ab.build());
247
248             ApplyActionsBuilder aab = new ApplyActionsBuilder();
249             aab.setAction(actionList);
250             InstructionBuilder ib = new InstructionBuilder();
251             ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
252
253             ib.setOrder(0);
254             ib.setKey(new InstructionKey(0));
255             instructions.add(ib.build());
256
257             isb.setInstruction(instructions);
258             flowBuilder.setInstructions(isb.build());
259             writeFlow(flowBuilder, nodeBuilder);
260
261         } else {
262             removeFlow(flowBuilder, nodeBuilder);
263         }
264     }
265
266     @Override
267     public void program_sfEgress(long dataPathId, int dstPort, boolean write) {
268         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dataPathId);
269         FlowBuilder flowBuilder = new FlowBuilder();
270
271         MatchBuilder matchBuilder = new MatchBuilder();
272         MatchUtils.createIpProtocolMatch(matchBuilder, UDP_SHORT);
273         flowBuilder.setMatch(MatchUtils.addLayer4Match(matchBuilder, UDP_SHORT, 0, dstPort).build());
274         flowBuilder.setMatch(MatchUtils.addNxRegMatch(
275                 matchBuilder, new MatchUtils.RegMatch(FlowUtils.REG_FIELD, FlowUtils.REG_VALUE_FROM_LOCAL)).build());
276
277         String flowId = "sfEgress_" + dstPort;
278         flowBuilder.setId(new FlowId(flowId));
279         FlowKey key = new FlowKey(new FlowId(flowId));
280         flowBuilder.setBarrier(true);
281         flowBuilder.setTableId(getTable());
282         flowBuilder.setKey(key);
283         flowBuilder.setFlowName(flowId);
284         flowBuilder.setHardTimeout(0);
285         flowBuilder.setIdleTimeout(0);
286
287         if (write) {
288             InstructionBuilder ib = new InstructionBuilder();
289             InstructionsBuilder isb = new InstructionsBuilder();
290             List<Instruction> instructions = Lists.newArrayList();
291             InstructionUtils.createLocalInstructions(ib, dataPathId);
292             ib.setOrder(0);
293             ib.setKey(new InstructionKey(0));
294             instructions.add(ib.build());
295
296             isb.setInstruction(instructions);
297             flowBuilder.setInstructions(isb.build());
298             writeFlow(flowBuilder, nodeBuilder);
299         } else {
300             removeFlow(flowBuilder, nodeBuilder);
301         }
302     }
303
304     private List<Action> getNshAction(NshUtils header, List<Action> actionList) {
305         // Build the Actions to Add the NSH Header
306         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nshC1Load =
307                 ActionUtils.nxLoadNshc1RegAction(header.getNshMetaC1());
308         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nshC2Load =
309                 ActionUtils.nxLoadNshc2RegAction(header.getNshMetaC2());
310         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nspLoad =
311                 ActionUtils.nxSetNspAction(header.getNshNsp());
312         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nsiLoad =
313                 ActionUtils.nxSetNsiAction(header.getNshNsi());
314         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadChainTunVnid =
315                 ActionUtils.nxLoadTunIdAction(BigInteger.valueOf(header.getNshNsp()), false);
316         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadChainTunDest =
317                 ActionUtils.nxLoadTunIPv4Action(header.getNshTunIpDst().getValue(), false);
318
319         int count = actionList.size();
320         actionList.add(new ActionBuilder()
321                 .setKey(new ActionKey(count)).setOrder(count++).setAction(nshC1Load).build());
322         //actionList.add(new ActionBuilder()
323         // .setKey(new ActionKey(count)).setOrder(count++).setAction(nshC2Load).build());
324         actionList.add(new ActionBuilder()
325                 .setKey(new ActionKey(count)).setOrder(count++).setAction(nspLoad).build());
326         actionList.add(new ActionBuilder()
327                 .setKey(new ActionKey(count)).setOrder(count++).setAction(nsiLoad).build());
328         actionList.add(new ActionBuilder()
329                 .setKey(new ActionKey(count)).setOrder(count++).setAction(loadChainTunDest).build());
330         actionList.add(new ActionBuilder()
331                 .setKey(new ActionKey(count)).setOrder(count).setAction(loadChainTunVnid).build());
332         return actionList;
333     }
334
335     public MatchBuilder buildMatch(Matches matches) {
336         MatchBuilder matchBuilder = new MatchBuilder();
337
338         if (matches.getAceType() instanceof AceIp) {
339             AceIp aceIp = (AceIp)matches.getAceType();
340             if (aceIp.getAceIpVersion() instanceof AceIpv4) {
341                 //AceIpv4 aceIpv4 = (AceIpv4) aceIp.getAceIpVersion();
342                 //MatchUtils.createSrcL3IPv4Match(matchBuilder, aceIpv4.getSourceIpv4Network());
343                 //MatchUtils.createDstL3IPv4Match(matchBuilder, aceIpv4.getDestinationIpv4Network());
344                 MatchUtils.createIpProtocolMatch(matchBuilder, aceIp.getProtocol());
345                 MatchUtils.addLayer4Match(matchBuilder, aceIp.getProtocol().intValue(), 0,
346                         aceIp.getDestinationPortRange().getLowerPort().getValue().intValue());
347             } else {
348                 MatchUtils.createIpProtocolMatch(matchBuilder, aceIp.getProtocol());
349                 MatchUtils.addLayer4Match(matchBuilder, aceIp.getProtocol().intValue(), 0,
350                         aceIp.getDestinationPortRange().getLowerPort().getValue().intValue());
351             }
352         } else if (matches.getAceType() instanceof AceEth) {
353             AceEth aceEth = (AceEth) matches.getAceType();
354             MatchUtils.createEthSrcMatch(matchBuilder, new MacAddress(aceEth.getSourceMacAddress().getValue()));
355             MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(aceEth.getDestinationMacAddress().getValue()),
356                     new MacAddress(aceEth.getDestinationMacAddressMask().getValue()));
357         }
358
359         LOG.info("buildMatch: {}", matchBuilder.build());
360         return matchBuilder;
361     }
362 }