Fix netvirtsfc flows
[ovsdb.git] / openstack / net-virt-sfc / impl / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / sfc / openflow13 / NetvirtSfcOF13Provider.java
1 /*
2  * Copyright (c) 2015 Dell, 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.openflow13;
10
11 import com.google.common.util.concurrent.CheckedFuture;
12 import java.math.BigInteger;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.StringTokenizer;
16
17 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
18 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
21
22 import com.google.common.base.Preconditions;
23 import com.google.common.collect.Lists;
24 import com.google.common.net.InetAddresses;
25
26 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
29 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
30 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
31 import org.opendaylight.ovsdb.utils.mdsal.openflow.ActionUtils;
32 import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
33 import org.opendaylight.ovsdb.utils.mdsal.openflow.MatchUtils;
34 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
35 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
36 import org.opendaylight.sfc.provider.api.SfcProviderRenderedPathAPI;
37 import org.opendaylight.sfc.provider.api.SfcProviderServiceForwarderAPI;
38 import org.opendaylight.sfc.provider.api.SfcProviderServicePathAPI;
39 import org.opendaylight.sfc.sfc_ovs.provider.SfcOvsUtil;
40 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.RspName;
41 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.common.rev151017.SffName;
42 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInput;
43 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInputBuilder;
44 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.RenderedServicePaths;
45 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.path.first.hop.info.RenderedServicePathFirstHop;
46 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
47 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePathKey;
48 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHop;
49 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
50 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPaths;
51 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.Ace;
54 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;
55 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;
56 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;
57 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;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
60 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.dst.choice.grouping.dst.choice.DstNxRegCaseBuilder;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.acl.rev150105.RedirectToSfc;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.bridges.Bridge;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
89 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
90 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
91 import org.osgi.framework.ServiceReference;
92 import org.slf4j.Logger;
93 import org.slf4j.LoggerFactory;
94
95
96 /**
97  * Open vSwitch OpenFlow 1.3 Networking Provider for Netvirt SFC
98  * @author Arun Yerra
99  */
100 public class NetvirtSfcOF13Provider implements INetvirtSfcOF13Provider{
101     private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcOF13Provider.class);
102     private static final int DEFAULT_FLOW_PRIORITY = 32768;
103     private static final short TABLE_0_CLASSIFIER = 0;
104     //private static final short TABLE_1_L2FORWARD = 30;
105     //private static final short TABLE_2_L3FORWARD = 40;
106     private static final short TABLE_3_INGR_ACL = 50;
107     private static final String OPENFLOW = "openflow:";
108
109     public static final long REG_VALUE_FROM_LOCAL = 0x1L;
110     public static final long REG_VALUE_FROM_REMOTE = 0x2L;
111     public static final Class<? extends NxmNxReg> REG_FIELD = NxmNxReg0.class;
112     private volatile NodeCacheManager nodeCacheManager;
113     private volatile Southbound southbound;
114     private MdsalUtils mdsalUtils;
115     private DataBroker dataBroker;
116
117     // TBD:: Remove these constants after integrating with openstack.
118     //private static final String NETWORK_TYPE_VXLAN = "vxlan";
119     private static final String NETWORK_SEGMENT_ID = "10";
120     private static final String LOCAL_TP_ID = "vethl-h35_2";
121     private static final String INTERFACE_TYPE_VXLAN_GPE = "vxlangpe";
122     private static final String GPE_IFACE_ID = "sw1-vxlangpe-0";
123
124     /**
125      * {@link NetvirtSfcOF13Provider} constructor.
126      * @param dataBroker MdSal {@link DataBroker}
127      */
128     public NetvirtSfcOF13Provider(final DataBroker dataBroker) {
129         Preconditions.checkNotNull(dataBroker, "Input dataBroker cannot be NULL!");
130         this.dataBroker = dataBroker;
131         mdsalUtils = new MdsalUtils(dataBroker);
132         this.setDependencies(null);
133     }
134
135     @Override
136     public void addClassifierRules(Sff sff, Acl acl) {
137         Preconditions.checkNotNull(sff, "Input service function forwarder cannot be NULL!");
138         Preconditions.checkNotNull(acl, "Input accesslist cannot be NULL!");
139
140         // Validate if any service function forwarder exists by the name, using SFC provider APIs.
141         ServiceFunctionForwarder serviceForwarder =
142                 SfcProviderServiceForwarderAPI.readServiceFunctionForwarder(new SffName(sff.getName()));
143         if (serviceForwarder == null) {
144             LOG.debug("Service Function Forwarder = {} not yet configured. Skip processing !!", sff.getName());
145             return;
146         }
147
148         // If a service function forwarder exists, then get the corresponding OVS Bridge details and Openflow NodeId.
149         // If OVS Bridge augmentation is configured, the following API returns NULL.
150         String datapathId = null;
151         Node node = null;
152         // TODO: Replace with OVSDB methods and not use the SFC API
153         datapathId = SfcOvsUtil.getOpenFlowNodeIdForSff(serviceForwarder);
154         if (datapathId == null) {
155             LOG.debug("Service Function Forwarder = {} is not augmented with "
156                     + "OVS Bridge Information. Skip processing!!", sff.getName());
157         }
158         // If openflow Node Id is NULL, get all the bridge nodes using southbound apis and fetch
159         // SFF with matching name. From this bridge name, get the openflow data path ID.
160
161         node = getBridgeNode(serviceForwarder.getName().toString());
162         if (node == null) {
163             LOG.warn("Node doesn't exist for corresponding SFF={}", sff.getName());
164             return;
165         }
166
167         datapathId = getDpid(node);
168         LOG.debug("Processing the Classifier rules on Node={}", datapathId);
169         if (datapathId != null) {
170             // Program the OF flow on the corresponding open flow node.
171             Iterator<Ace> itr = acl.getAccessListEntries().getAce().iterator();
172             while (itr.hasNext()) {
173                 Ace entry = itr.next();
174                 processAclEntry(entry, node, true);
175             }
176         } else {
177             LOG.warn("Skipping ACL processing on Node={} as DatapathID is NULL!!", sff.getName());
178         }
179     }
180
181     @Override
182     public void addClassifierRules(Bridge bridge, Acl acl) {
183         Preconditions.checkNotNull(bridge, "Input bridge cannot be NULL!");
184         Preconditions.checkNotNull(acl, "Input accesslist cannot be NULL!");
185
186         Node bridgeNode = getBridgeNode(bridge.getName());
187         if (bridgeNode == null) {
188             LOG.debug("bridge {} not yet configured. Skip processing !!", bridge.getName());
189             return;
190         }
191
192         // Program the OF flow on the corresponding open flow node.
193         for (Ace ace : acl.getAccessListEntries().getAce()) {
194             processAclEntry(ace, bridgeNode, true);
195         }
196     }
197
198     private void processAclEntry(Ace entry, Node srcNode, boolean write) {
199         RedirectToSfc sfcRedirect = entry.getActions().getAugmentation(RedirectToSfc.class);
200         LOG.debug("Processing ACL entry = {} on Node = {} sfcRedirect = {}", entry.getRuleName(),
201                 srcNode.getNodeId(), sfcRedirect);
202         if (sfcRedirect != null) {
203             // Given SFP find the corresponding RSP.
204             String sfcName = sfcRedirect.getRedirectSfc();
205             LOG.debug("Processing Redirect to SFC = {}", sfcRedirect.getRedirectSfc());
206             ServiceFunctionPath sfp = getSfp(sfcName);
207             if (sfp == null || sfp.getName() == null) {
208                 LOG.warn("There is no configured SFP with sfcName = {}; so skip installing the ACL entry!!", sfcName);
209                 return;
210             }
211
212             LOG.debug("Processing Redirect to SFC = {}, SFP = {}", sfcRedirect.getRedirectSfc(), sfp);
213             // If RSP doesn't exist, create an RSP.
214             String sfpName = sfp.getName().getValue();
215             RenderedServicePath rsp = getRspforSfp(sfpName);
216             String rspName = sfp.getName().getValue() + "_rsp";
217             if (rsp == null) {
218                 LOG.info("No configured RSP corresponding to SFP = {}, Creating new RSP = {}!!", sfpName, rspName);
219                 // Create RSP.
220                 CreateRenderedPathInput rspInput = new CreateRenderedPathInputBuilder()
221                         .setParentServiceFunctionPath(sfpName)
222                         .setName(rspName)
223                         .setSymmetric(sfp.isSymmetric())
224                         .build();
225                 rsp = SfcProviderRenderedPathAPI.createRenderedServicePathAndState(sfp, rspInput);
226                 if (rsp == null) {
227                     LOG.warn("failed to add RSP");
228                     return;
229                 }
230
231                 // If SFP is symmetric, create RSP in the reverse direction.
232                 if (sfp.isSymmetric()) {
233                     LOG.info("SFP = {} is symmetric, installing RSP in the reverse direction!!", sfpName);
234                     String rspNameRev = rspName + "-Reverse";
235                     RenderedServicePath rspReverse = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
236                                                                  this.getRspId(rspNameRev));
237                     if (rspReverse == null) {
238                         rspReverse = SfcProviderRenderedPathAPI.createSymmetricRenderedServicePathAndState(rsp);
239                     }
240                 }
241             }
242             LOG.info("rsp: {}", rsp);
243
244             // Find the first Hop within a RSP.
245             List<RenderedServicePathHop> pathHopList = rsp.getRenderedServicePathHop();
246             if (pathHopList.isEmpty()) {
247                 LOG.info("Service Path = {} has empty hops!!", sfpName);
248                 return;
249             }
250
251             RenderedServicePathFirstHop firstRspHop = SfcProviderRenderedPathAPI
252                     .readRenderedServicePathFirstHop(new RspName(rspName));
253             //String firstSff = firstHop.getServiceFunctionForwarderLocator();
254
255             LOG.debug("First Hop IPAddress = {}, Port = {}", firstRspHop.getIp().getIpv4Address().getValue(),
256                     firstRspHop.getPort().getValue().intValue());
257             OvsdbTerminationPointAugmentation tunnelPort = southbound
258                     .getTerminationPointOfBridge(srcNode, GPE_IFACE_ID);
259             if (tunnelPort != null) {
260                 long tunnelOfPort = southbound.getOFPort(tunnelPort);
261                 LOG.debug("Tunnel Port = {}, OF Port Number = {}", tunnelPort.getName(), tunnelOfPort);
262                 if (tunnelOfPort == 0) {
263                     LOG.error("programTunnelRules: Could not Identify Tunnel port {} -> OF ({}) on {}",
264                             tunnelPort.getName(), tunnelOfPort, srcNode);
265                     return;
266                 }
267             }
268
269             Matches match = entry.getMatches();
270
271             NshUtils header = new NshUtils();
272             // C1 is the normal overlay dest ip
273             header.setNshMetaC1(convertToLongIp(getDestIp(match)));
274             header.setNshMetaC2(Long.parseLong(NETWORK_SEGMENT_ID));
275             header.setNshNsp(rsp.getPathId());
276
277             RenderedServicePathHop firstHop = pathHopList.get(0);
278             header.setNshNsi(firstHop.getServiceIndex());
279             header.setNshTunIpDst(firstRspHop.getIp().getIpv4Address());
280             header.setNshTunUdpPort(firstRspHop.getPort());
281
282             LOG.debug("The Nsh Header = {}", header);
283             OvsdbTerminationPointAugmentation localPort = getTerminationPoint(srcNode, LOCAL_TP_ID);
284
285            /* String attachedMac = southbound.getInterfaceExternalIdsValue(localPort, Constants.EXTERNAL_ID_VM_MAC);
286             if (attachedMac == null) {
287                 LOG.warn("No AttachedMac seen in {}", localPort);
288                 // return;
289             }
290             */
291             LOG.debug("LocalPort ID={}, IP Address = {}", localPort.getName(), getSourceIp(match));
292             handleLocalInPort(southbound.getDataPathId(srcNode), TABLE_0_CLASSIFIER, TABLE_3_INGR_ACL,
293                     NETWORK_SEGMENT_ID, localPort.getOfport(), getSourceIp(match), true);
294
295             // L2 Dst MAC forwarding flows.
296             // L2 Flood Flows.
297             // Set the Tunnel Destination IP, Dest MAC based on the destination IP address.
298             // Replace SMAC & decrement TTL.
299             // handleL3Flows(southbound.getDataPathId(srcNode), TABLE_1_ISOLATE_TENANT,
300             // TABLE_2_INGRESS_ACL, destIp, l3SegmentId, destMac);
301             // Set NSP & NSI values based on the Classifier Match actions.
302             OvsdbTerminationPointAugmentation outPort = getTerminationPoint(srcNode, INTERFACE_TYPE_VXLAN_GPE);
303             // TODO: commented out for test
304             //handleSfcClassiferFlows(entry.getRuleName(), srcNode, match,
305             //              TABLE_3_INGR_ACL, header, outPort.getOfport(), true);
306             // Set NSHC1, NSHC2, Tunnel DestIP, port toward SFF1, output to Tunnel Port.
307
308         }
309     }
310
311     private OvsdbTerminationPointAugmentation getTerminationPoint(Node srcNode, String localTpId) {
312         List<OvsdbTerminationPointAugmentation> ports = southbound.extractTerminationPointAugmentations(srcNode);
313         if (ports != null && !ports.isEmpty()) {
314             for (OvsdbTerminationPointAugmentation port : ports) {
315                 // TBD :: For Demo, use the Tunnel ID as 10. Once openstack is integrated,
316                 // tunnel ID is created through Network Creation.
317                 if (port.getName().contains(localTpId)) {
318                     return port;
319                 }
320             }
321         }
322         return null;
323     }
324
325     private String getTunnelName(String networkTypeVxlan, Ipv4Address ipv4Address) {
326         return networkTypeVxlan + "-" + ipv4Address.getValue();
327     }
328
329     /*
330      * (TABLE:50) EGRESS VM TRAFFIC TOWARDS TEP with NSH header
331      * MATCH: Match fields passed through ACL entry
332      * INSTRUCTION: SET TUNNELID AND GOTO TABLE TUNNEL TABLE (N)
333      * TABLE=0,IN_PORT=2,DL_SRC=00:00:00:00:00:01 \
334      * ACTIONS=SET_FIELD:5->TUN_ID,GOTO_TABLE=1"
335      */
336     private void handleSfcClassiferFlows(String ruleName, Node node, Matches match,
337                  short table3IngrAcl, NshUtils header, long ofPort, boolean write) {
338         // Build the Actions to Add the NSH Header
339         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nshC1Load =
340                         NshUtils.nxLoadNshc1RegAction(header.getNshMetaC1());
341         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nshC2Load =
342                         NshUtils.nxLoadNshc2RegAction(header.getNshMetaC2());
343         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nspLoad =
344                         NshUtils.nxSetNspAction(header.getNshNsp());
345         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action nsiLoad =
346                         NshUtils.nxSetNsiAction(header.getNshNsi());
347         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadChainTunVnid =
348                         NshUtils.nxLoadTunIdAction(BigInteger.valueOf(header.getNshMetaC2()), false);
349         org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action loadChainTunDest =
350                         NshUtils.nxLoadTunIPv4Action(header.getNshTunIpDst().getValue(), false);
351
352         int count = 0;
353         List<Action> actionList = Lists.newArrayList();
354         actionList.add(new ActionBuilder().setOrder(Integer.valueOf(count++)).setAction(nshC1Load).build());
355         actionList.add(new ActionBuilder().setOrder(Integer.valueOf(count++)).setAction(nshC2Load).build());
356         actionList.add(new ActionBuilder().setOrder(Integer.valueOf(count++)).setAction(nspLoad).build());
357         actionList.add(new ActionBuilder().setOrder(Integer.valueOf(count++)).setAction(nsiLoad).build());
358         actionList.add(new ActionBuilder().setOrder(Integer.valueOf(count++)).setAction(loadChainTunDest).build());
359         actionList.add(new ActionBuilder().setOrder(Integer.valueOf(count++)).setAction(loadChainTunVnid).build());
360
361         ApplyActionsBuilder aab = new ApplyActionsBuilder();
362         aab.setAction(actionList);
363
364         InstructionBuilder ib = new InstructionBuilder();
365         ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
366         ib.setOrder(0);
367         ib.setKey(new InstructionKey(0));
368
369         List<Instruction> instructions = Lists.newArrayList();
370         instructions.add(ib.build());
371
372      // Set the Output Port/Iface
373         InstructionUtils.createOutputPortInstructions(ib, southbound.getDataPathId(node), ofPort);
374         ib.setOrder(1);
375         ib.setKey(new InstructionKey(1));
376         instructions.add(ib.build());
377
378      // Add InstructionBuilder to the Instruction(s)Builder List
379         InstructionsBuilder isb = new InstructionsBuilder();
380         isb.setInstruction(instructions);
381
382         String flowId = "NETVIRT_SFC_FLOW" + "_" + ruleName + "_" + header.getNshNsp();
383         FlowBuilder flowBuilder = new FlowBuilder();
384         flowBuilder.setId(new FlowId(flowId));
385         FlowKey key = new FlowKey(new FlowId(flowId));
386
387         MatchBuilder mb = buildMatch(match);
388         flowBuilder.setMatch(mb.build());
389         flowBuilder.setPriority(DEFAULT_FLOW_PRIORITY);
390         flowBuilder.setBarrier(true);
391         flowBuilder.setTableId(table3IngrAcl);
392         flowBuilder.setKey(key);
393         flowBuilder.setFlowName(flowId);
394         flowBuilder.setHardTimeout(0);
395         flowBuilder.setIdleTimeout(0);
396
397         flowBuilder.setInstructions(isb.build());
398
399         if (write) {
400             writeFlow(flowBuilder, createNodeBuilder(node.getNodeId().getValue()));
401         } else {
402             removeFlow(flowBuilder, createNodeBuilder(node.getNodeId().getValue()));
403         }
404     }
405
406     /*
407      * (TABLE:0) EGRESS VM TRAFFIC TOWARDS TEP
408      * MATCH: DESTINATION ETHERNET ADDR AND OPENFLOW INPORT
409      * INSTRUCTION: SET TUNNELID AND GOTO TABLE TUNNEL TABLE (N)
410      * TABLE=0,IN_PORT=2,DL_SRC=00:00:00:00:00:01 \
411      * ACTIONS=SET_FIELD:5->TUN_ID,GOTO_TABLE=1"
412      */
413     private void handleLocalInPort(long dpidLong, short writeTable, short goToTableId,
414             String segmentationId, Long inPort, String sourceIp,
415             boolean write) {
416         programDropSrcIface(dpidLong, inPort, true);
417         programLocalInPort(dpidLong, segmentationId, inPort, sourceIp, goToTableId, write);
418     }
419
420     private String getDestIp(Matches match) {
421         if (match.getAceType() instanceof AceIp) {
422             AceIp aceIp = (AceIp)match.getAceType();
423             if (aceIp.getAceIpVersion() instanceof AceIpv4) {
424                 AceIpv4 aceIpv4 = (AceIpv4) aceIp.getAceIpVersion();
425                 if (aceIpv4.getDestinationIpv4Network() != null) {
426                     String ipAddrPrefix = aceIpv4.getDestinationIpv4Network().getValue();
427                     String ipAddr = new StringTokenizer(ipAddrPrefix, "/").nextToken();
428                     return ipAddr;
429                 }
430             }
431         }
432         return null;
433     }
434
435     private String getSourceIp(Matches match) {
436         if (match.getAceType() instanceof AceIp) {
437             AceIp aceIp = (AceIp)match.getAceType();
438             if (aceIp.getAceIpVersion() instanceof AceIpv4) {
439                 AceIpv4 aceIpv4 = (AceIpv4) aceIp.getAceIpVersion();
440                 if (aceIpv4.getSourceIpv4Network() != null) {
441                     String ipAddrPrefix = aceIpv4.getSourceIpv4Network().getValue();
442                     //String ipAddr = new StringTokenizer(ipAddrPrefix, "/").nextToken();
443                     return ipAddrPrefix;
444                 }
445             }
446         }
447         return null;
448     }
449
450     private long convertToLongIp(String ipaddr) {
451         LOG.debug("Converting String={} to Long", ipaddr);
452         return InetAddresses.coerceToInteger(InetAddresses.forString(ipaddr)) & 0xFFFFFFFFL;
453     }
454
455     private void programLocalInPort(Long dpidLong, String segmentationId, Long inPort,
456                                     String ipAddr, short goToTableId, boolean write) {
457         String nodeName = OPENFLOW + dpidLong;
458
459         MatchBuilder matchBuilder = new MatchBuilder();
460         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
461         FlowBuilder flowBuilder = new FlowBuilder();
462
463         // Create the OF Match using MatchBuilder
464         //flowBuilder.setMatch(MatchUtils.createEthSrcMatch(matchBuilder, new MacAddress(attachedMac)).build());
465         // TODO Broken In_Port Match
466         flowBuilder.setMatch(MatchUtils.createInPortMatch(matchBuilder, dpidLong, inPort).build());
467         //flowBuilder.setMatch(MatchUtils.createSrcL3IPv4Match(matchBuilder, new Ipv4Prefix(ipAddr)).build());
468         String flowId = "LocalSfc_" + segmentationId + "_" + inPort;// + "_" + ipAddr.split("/",2)[0];
469         // Add Flow Attributes
470         flowBuilder.setId(new FlowId(flowId));
471         FlowKey key = new FlowKey(new FlowId(flowId));
472         flowBuilder.setStrict(true);
473         flowBuilder.setBarrier(false);
474         flowBuilder.setTableId((short)0);//getTable());
475         flowBuilder.setKey(key);
476         flowBuilder.setFlowName(flowId);
477         flowBuilder.setPriority(8192);
478         flowBuilder.setHardTimeout(0);
479         flowBuilder.setIdleTimeout(0);
480
481         if (write) {
482             // Instantiate the Builders for the OF Actions and Instructions
483             InstructionBuilder ib = new InstructionBuilder();
484             InstructionsBuilder isb = new InstructionsBuilder();
485
486             // Instructions List Stores Individual Instructions
487             List<Instruction> instructions = Lists.newArrayList();
488
489             // TODO Broken SetTunID
490             //InstructionUtils.createSetTunnelIdInstructions(ib, new BigInteger(segmentationId));
491             //ApplyActionsCase aac = (ApplyActionsCase) ib.getInstruction();
492             //List<Action> actionList = aac.getApplyActions().getAction();
493
494             //ActionBuilder ab = new ActionBuilder();
495             //ab.setAction(ActionUtils.nxLoadRegAction(new DstNxRegCaseBuilder().setNxReg(REG_FIELD).build(),
496             //        BigInteger.valueOf(REG_VALUE_FROM_LOCAL)));
497             //ab.setOrder(1);
498             //ab.setKey(new ActionKey(1));
499
500             //actionList.add(ab.build());
501
502             //ib.setOrder(0);
503             //ib.setKey(new InstructionKey(0));
504             //instructions.add(ib.build());
505
506             // Next service GOTO Instructions Need to be appended to the List
507             ib = InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), goToTableId);
508             ib.setOrder(0);//1);
509             ib.setKey(new InstructionKey(0));//1));
510             instructions.add(ib.build());
511
512             // Add InstructionBuilder to the Instruction(s)Builder List
513             isb.setInstruction(instructions);
514
515             // Add InstructionsBuilder to FlowBuilder
516             flowBuilder.setInstructions(isb.build());
517
518             writeFlow(flowBuilder, nodeBuilder);
519         } else {
520             removeFlow(flowBuilder, nodeBuilder);
521         }
522     }
523
524     public void programDropSrcIface(Long dpidLong, Long inPort, boolean write) {
525
526         String nodeName = OPENFLOW + dpidLong;
527
528         MatchBuilder matchBuilder = new MatchBuilder();
529         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
530         FlowBuilder flowBuilder = new FlowBuilder();
531
532         // Create the OF Match using MatchBuilder
533         flowBuilder.setMatch(MatchUtils.createInPortMatch(matchBuilder, dpidLong, inPort).build());
534
535         if (write) {
536             // Instantiate the Builders for the OF Actions and Instructions
537             InstructionBuilder ib = new InstructionBuilder();
538             InstructionsBuilder isb = new InstructionsBuilder();
539
540             // Instructions List Stores Individual Instructions
541             List<Instruction> instructions = Lists.newArrayList();
542
543             // Call the InstructionBuilder Methods Containing Actions
544             InstructionUtils.createDropInstructions(ib);
545             ib.setOrder(0);
546             ib.setKey(new InstructionKey(0));
547             instructions.add(ib.build());
548
549             // Add InstructionBuilder to the Instruction(s)Builder List
550             isb.setInstruction(instructions);
551
552             // Add InstructionsBuilder to FlowBuilder
553             flowBuilder.setInstructions(isb.build());
554         }
555
556         String flowId = "DropFilter_"+inPort;
557         // Add Flow Attributes
558         flowBuilder.setId(new FlowId(flowId));
559         FlowKey key = new FlowKey(new FlowId(flowId));
560         flowBuilder.setStrict(true);
561         flowBuilder.setBarrier(false);
562         flowBuilder.setTableId((short)50);//getTable());
563         flowBuilder.setKey(key);
564         flowBuilder.setFlowName(flowId);
565         flowBuilder.setPriority(8192);
566         flowBuilder.setHardTimeout(0);
567         flowBuilder.setIdleTimeout(0);
568         if (write) {
569             writeFlow(flowBuilder, nodeBuilder);
570         } else {
571             removeFlow(flowBuilder, nodeBuilder);
572         }
573     }
574
575     private Node getBridgeNode(String bridgeName) {
576         //SffOvsBridgeAugmentation sffBridge = sff.getAugmentation(SffOvsBridgeAugmentation.class);
577         //String brName = sffBridge.getOvsBridge().getBridgeName();
578
579         final List<Node> nodes = nodeCacheManager.getBridgeNodes();
580         if (nodes.isEmpty()) {
581             LOG.debug("Noop with Classifier Creation on SFF={}. No Bridges configured YET!!", bridgeName);
582         } else {
583             for (Node node : nodes) {
584                 OvsdbBridgeAugmentation bridgeAugmentation = southbound.extractBridgeAugmentation(node);
585                 if (bridgeAugmentation != null) {
586                     if (bridgeAugmentation.getBridgeName().getValue().equalsIgnoreCase(bridgeName)) {
587                         LOG.info("Found matching OVSDB Bridge Name {}", node.getNodeId().getValue());
588                         return node;
589                     }
590                 }
591             }
592         }
593         return null;
594     }
595
596 /*
597     private InstructionsBuilder buildActions(String ruleName, Actions actions, String datapathId) {
598         InstructionBuilder ib = new InstructionBuilder();
599
600         if (actions.getPacketHandling() instanceof Deny) {
601             InstructionUtils.createDropInstructions(ib);
602         } else if (actions.getPacketHandling() instanceof Permit) {
603             //Permit actPermit = (Permit) actions.getPacketHandling();
604         } else {
605             InstructionUtils.createDropInstructions(ib);
606         }
607
608         ib.setOrder(0);
609         ib.setKey(new InstructionKey(0));
610         // Instructions List Stores Individual Instructions
611         List<Instruction> instructions = Lists.newArrayList();
612         instructions.add(ib.build());
613
614         // Call the InstructionBuilder Methods Containing Actions
615         ib = this.getMutablePipelineInstructionBuilder();
616         ib.setOrder(1);
617         ib.setKey(new InstructionKey(1));
618         instructions.add(ib.build());
619
620         // Add InstructionBuilder to the Instruction(s)Builder List
621         InstructionsBuilder isb = new InstructionsBuilder();
622         isb.setInstruction(instructions);
623         return isb;
624     }*/
625
626     private ServiceFunctionPath getSfp(String redirectSfc) {
627         ServiceFunctionPaths sfps = SfcProviderServicePathAPI.readAllServiceFunctionPaths();
628         if (sfps != null) {
629             for (ServiceFunctionPath sfp: sfps.getServiceFunctionPath()) {
630                 if (sfp.getServiceChainName().getValue().equalsIgnoreCase(redirectSfc)) {
631                     return sfp;
632                 }
633             }
634         }
635         return null;
636     }
637
638     private RenderedServicePath getRspforSfp(String sfpName) {
639         RenderedServicePaths rsps = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, this.getRspsId());
640         if (rsps == null) {
641             LOG.debug("RSP has not been configured yet for SFP = {}", sfpName);
642             return null;
643         }
644         for (RenderedServicePath rsp : rsps.getRenderedServicePath()) {
645             if (rsp.getParentServiceFunctionPath() !=  null) {
646                 if (rsp.getParentServiceFunctionPath().getValue().equalsIgnoreCase(sfpName)) {
647                     return rsp;
648                 }
649             }
650         }
651         return null;
652     }
653
654     private MatchBuilder buildMatch(Matches matches) {
655         MatchBuilder matchBuilder = new MatchBuilder();
656
657         if (matches.getAceType() instanceof AceIp) {
658             AceIp aceIp = (AceIp)matches.getAceType();
659             if (aceIp.getAceIpVersion() instanceof AceIpv4) {
660                 AceIpv4 aceIpv4 = (AceIpv4) aceIp.getAceIpVersion();
661                 MatchUtils.createSrcL3IPv4Match(matchBuilder, aceIpv4.getSourceIpv4Network());
662                 //MatchUtils.createDstL3IPv4Match(matchBuilder, aceIpv4.getDestinationIpv4Network());
663                 //MatchUtils.createIpProtocolMatch(matchBuilder, aceIp.getProtocol());
664                 MatchUtils.addLayer4Match(matchBuilder, aceIp.getProtocol().intValue(),
665                         0,
666                         aceIp.getDestinationPortRange().getLowerPort().getValue().intValue());
667             }
668         } else if (matches.getAceType() instanceof AceEth) {
669             AceEth aceEth = (AceEth) matches.getAceType();
670             MatchUtils.createEthSrcMatch(matchBuilder, new MacAddress(aceEth.getSourceMacAddress().getValue()));
671             MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(aceEth.getDestinationMacAddress().getValue()),
672                     new MacAddress(aceEth.getDestinationMacAddressMask().getValue()));
673         }
674
675         //MatchUtils.createInPortMatch(matchBuilder, Long.getLong(dpId), Long.getLong(matches.getInputInterface()));
676         return matchBuilder;
677     }
678
679     @Override
680     public void removeClassifierRules(Sff sff, Acl acl) {
681         // TODO Auto-generated method stub
682     }
683
684     /*
685     protected void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
686         LOG.debug("writeFlow: flowBuilder: {}, nodeBuilder: {}",
687                 flowBuilder.build(), nodeBuilder.build());
688         mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, createNodePath(nodeBuilder), nodeBuilder.build());
689         mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder), flowBuilder.build());
690     }
691 */
692     protected void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
693         LOG.debug("writeFlow: flowBuilder: {}, nodeBuilder: {}",
694                 flowBuilder.build(), nodeBuilder.build());
695         WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
696         modification.put(LogicalDatastoreType.CONFIGURATION, createNodePath(nodeBuilder),
697                 nodeBuilder.build(), true /*createMissingParents*/);
698         modification.put(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder),
699                 flowBuilder.build(), true /*createMissingParents*/);
700
701         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
702         try {
703             commitFuture.get();  // TODO: Make it async (See bug 1362)
704             LOG.debug("Transaction success for write of Flow {}", flowBuilder.getFlowName());
705         } catch (Exception e) {
706             LOG.error(e.getMessage(), e);
707             modification.cancel();
708         }
709     }
710
711     protected void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
712         mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder));
713     }
714
715     private String getDpid(Node node) {
716         long dpid = southbound.getDataPathId(node);
717         if (dpid == 0) {
718             LOG.warn("getDpid: DPID could not be found for node: {}", node.getNodeId().getValue());
719         }
720         return String.valueOf(dpid);
721     }
722
723     private static InstanceIdentifier<Flow> createFlowPath(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
724         return InstanceIdentifier.builder(Nodes.class)
725                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
726                         nodeBuilder.getKey())
727                 .augmentation(FlowCapableNode.class)
728                 .child(Table.class, new TableKey(flowBuilder.getTableId()))
729                 .child(Flow.class, flowBuilder.getKey()).build();
730     }
731
732     private static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node>
733         createNodePath(NodeBuilder nodeBuilder) {
734         return InstanceIdentifier.builder(Nodes.class)
735                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
736                         nodeBuilder.getKey()).build();
737     }
738
739     private NodeBuilder createNodeBuilder(String nodeId) {
740         NodeBuilder builder = new NodeBuilder();
741         builder.setId(new NodeId(nodeId));
742         builder.setKey(new NodeKey(builder.getId()));
743         return builder;
744     }
745
746     private InstanceIdentifier<RenderedServicePaths> getRspsId() {
747         return InstanceIdentifier.builder(RenderedServicePaths.class).build();
748     }
749
750     private InstanceIdentifier<RenderedServicePath> getRspId(String rspName) {
751         return InstanceIdentifier.builder(RenderedServicePaths.class)
752                 .child(RenderedServicePath.class, new RenderedServicePathKey(new RspName(rspName))).build();
753     }
754
755     private short getTable() {
756         return Service.INGRESS_ACL.getTable();
757     }
758
759     private void setDependencies(ServiceReference serviceReference) {
760         nodeCacheManager = (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
761         southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
762     }
763 }