Use latest sfc-model
[netvirt.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 java.util.Iterator;
12 import java.util.List;
13
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.Lists;
16
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
20 import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
21 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
22 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.PipelineOrchestrator;
23 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
24 import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
25 import org.opendaylight.ovsdb.utils.mdsal.openflow.MatchUtils;
26 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
27 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
28 import org.opendaylight.sfc.provider.api.SfcProviderServiceForwarderAPI;
29 import org.opendaylight.sfc.sfc_ovs.provider.SfcOvsUtil;
30 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.Acl;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.Ace;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.Actions;
34 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;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.actions.packet.handling.Deny;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev150317.access.lists.acl.access.list.entries.ace.actions.packet.handling.Permit;
37 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;
38 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;
39 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;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.sfc.classifier.rev150105.classifiers.classifier.sffs.Sff;
58 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
59 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
60 import org.osgi.framework.ServiceReference;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 /**
65  * Open vSwitch OpenFlow 1.3 Networking Provider for Netvirt SFC
66  * @author Arun Yerra
67  */
68 public class NetvirtSfcOF13Provider implements INetvirtSfcOF13Provider{
69     private static final Logger LOG = LoggerFactory.getLogger(NetvirtSfcOF13Provider.class);
70     private static final int DEFAULT_FLOW_PRIORITY = 32768;
71     private volatile NodeCacheManager nodeCacheManager;
72     private volatile Southbound southbound;
73     private MdsalUtils dbutils;
74     private PipelineOrchestrator orchestrator;
75
76     /**
77      * {@link NetvirtSfcOF13Provider} constructor.
78      * @param dataBroker MdSal {@link DataBroker}
79      */
80     public NetvirtSfcOF13Provider(final DataBroker dataBroker) {
81         Preconditions.checkNotNull(dataBroker, "Input dataBroker cannot be NULL!");
82
83         //this.dataService = dataBroker;
84         dbutils = new MdsalUtils(dataBroker);
85
86         this.setDependencies(null);
87     }
88
89     @Override
90     public void addClassifierRules(Sff sff, Acl acl) {
91         Preconditions.checkNotNull(sff, "Input service function forwarder cannot be NULL!");
92         Preconditions.checkNotNull(acl, "Input accesslist cannot be NULL!");
93
94         // Validate if any service function forwarder exists by the name, using SFC provider APIs.
95         ServiceFunctionForwarder serviceForwarder =
96                 SfcProviderServiceForwarderAPI.readServiceFunctionForwarder(sff.getName());
97         if (serviceForwarder == null) {
98             LOG.debug("Service Function Forwarder = {} not yet configured. Skip processing !!", sff.getName());
99             return;
100         }
101
102         // If a service function forwarder exists, then get the corresponding OVS Bridge details and Openflow NodeId.
103         // If OVS Bridge augmentation is configured, the following API returns NULL.
104         String datapathId = SfcOvsUtil.getOpenFlowNodeIdForSff(serviceForwarder);
105         if (datapathId == null) {
106             LOG.debug("Service Function Forwarder = {} is not augemented with "
107                     + "OVS Bridge Information. Skip processing!!", sff.getName());
108         }
109         // If openflow Node Id is NULL, get all the bridge nodes using southbound apis and fetch
110         // SFF with matching name. From this bridge name, get the openflow data path ID.
111         if (datapathId == null) {
112             Node node = null;
113             final List<Node> nodes = nodeCacheManager.getBridgeNodes();
114             if (nodes.isEmpty()) {
115                 LOG.debug("Noop with Classifier Creation on SFF={}. No Bridges configured YET!!", sff.getName());
116             } else {
117                 for (Node dstNode : nodes) {
118                     LOG.debug("Processing Node={}, sff={}", dstNode.getNodeId().getValue(), sff.getName());
119                     if (dstNode.getNodeId().getValue().equalsIgnoreCase(sff.getName())) {
120                         LOG.debug("Found matching OVSDB Bridge Name!!= {}", dstNode.getNodeId().getValue());
121                         node = dstNode;
122                         break;
123                     }
124                 }
125             }
126         }
127
128         LOG.debug("Processing the Classifier rules on Node={}", datapathId);
129         if (datapathId != null) {
130             // Program the OF flow on the corresponding open flow node.
131             Iterator<Ace> itr = acl.getAccessListEntries().getAce().iterator();
132             while (itr.hasNext()) {
133                 Ace entry = itr.next();
134                 programOFRules(entry, datapathId, true);
135             }
136         }
137     }
138
139     private void programOFRules(Ace entry, String datapathId, boolean write) {
140         NodeBuilder nodeBuilder = new NodeBuilder();
141         nodeBuilder.setId(new NodeId(Constants.OPENFLOW_NODE_PREFIX + datapathId));
142         nodeBuilder.setKey(new NodeKey(nodeBuilder.getId()));
143
144         //Create the match using match builder, by parsing the Accesslist Entry Match.
145         MatchBuilder matchBuilder = null;
146         matchBuilder = buildMatch(entry.getRuleName(), entry.getMatches(), datapathId);
147
148         InstructionsBuilder isb = null;
149         isb = buildActions(entry.getRuleName(), entry.getActions(), datapathId);
150
151         String flowId = "NETVIRT_SFC_FLOW" + "_" + entry.getRuleName();
152
153         FlowBuilder flowBuilder = new FlowBuilder();
154         flowBuilder.setId(new FlowId(flowId));
155         FlowKey key = new FlowKey(new FlowId(flowId));
156         flowBuilder.setMatch(matchBuilder.build());
157         flowBuilder.setPriority(DEFAULT_FLOW_PRIORITY);
158         flowBuilder.setBarrier(true);
159         flowBuilder.setTableId(this.getTable());
160         flowBuilder.setKey(key);
161         flowBuilder.setFlowName(flowId);
162         flowBuilder.setHardTimeout(0);
163         flowBuilder.setIdleTimeout(0);
164
165         flowBuilder.setInstructions(isb.build());
166
167         if (write) {
168             writeFlow(flowBuilder, nodeBuilder);
169         } else {
170             removeFlow(flowBuilder, nodeBuilder);
171         }
172     }
173
174     private InstructionsBuilder buildActions(String ruleName, Actions actions, String datapathId) {
175         InstructionBuilder ib = new InstructionBuilder();
176
177         if (actions.getPacketHandling() instanceof Deny) {
178             InstructionUtils.createDropInstructions(ib);
179         } else if (actions.getPacketHandling() instanceof Permit) {
180             //Permit actPermit = (Permit) actions.getPacketHandling();
181         } else {
182             InstructionUtils.createDropInstructions(ib);
183         }
184
185         ib.setOrder(0);
186         ib.setKey(new InstructionKey(0));
187         // Instructions List Stores Individual Instructions
188         List<Instruction> instructions = Lists.newArrayList();
189         instructions.add(ib.build());
190
191         // Call the InstructionBuilder Methods Containing Actions
192         ib = this.getMutablePipelineInstructionBuilder();
193         ib.setOrder(1);
194         ib.setKey(new InstructionKey(1));
195         instructions.add(ib.build());
196
197         // Add InstructionBuilder to the Instruction(s)Builder List
198         InstructionsBuilder isb = new InstructionsBuilder();
199         isb.setInstruction(instructions);
200         return isb;
201     }
202
203     private MatchBuilder buildMatch(String ruleName, Matches matches, String dpId) {
204         MatchBuilder matchBuilder = new MatchBuilder();
205
206         if (matches.getAceType() instanceof AceIp) {
207             AceIp aceIp = (AceIp)matches.getAceType();
208             if (aceIp.getAceIpVersion() instanceof AceIpv4) {
209                 AceIpv4 aceIpv4 = (AceIpv4) aceIp.getAceIpVersion();
210                 MatchUtils.createSrcL3IPv4Match(matchBuilder, aceIpv4.getSourceIpv4Network());
211                 MatchUtils.createDstL3IPv4Match(matchBuilder, aceIpv4.getDestinationIpv4Network());
212                 MatchUtils.createIpProtocolMatch(matchBuilder, aceIp.getProtocol());
213                 MatchUtils.addLayer4Match(matchBuilder, aceIp.getProtocol().intValue(),
214                         aceIp.getSourcePortRange().getLowerPort().getValue().intValue(),
215                         aceIp.getDestinationPortRange().getLowerPort().getValue().intValue());
216             }
217         } else if (matches.getAceType() instanceof AceEth) {
218             AceEth aceEth = (AceEth) matches.getAceType();
219             MatchUtils.createEthSrcMatch(matchBuilder, new MacAddress(aceEth.getSourceMacAddress().getValue()));
220             MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(aceEth.getDestinationMacAddress().getValue()),
221                     new MacAddress(aceEth.getDestinationMacAddressMask().getValue()));
222         }
223
224         //MatchUtils.createInPortMatch(matchBuilder, Long.getLong(dpId), Long.getLong(matches.getInputInterface()));
225         return matchBuilder;
226     }
227
228     @Override
229     public void removeClassifierRules(Sff sff, Acl acl) {
230         // TODO Auto-generated method stub
231
232     }
233
234
235     protected void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
236         LOG.debug("writeFlow: flowBuilder: {}, nodeBuilder: {}",
237                 flowBuilder.build(), nodeBuilder.build());
238         dbutils.merge(LogicalDatastoreType.CONFIGURATION, createNodePath(nodeBuilder), nodeBuilder.build());
239         dbutils.put(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder), flowBuilder.build());
240     }
241
242     protected void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
243         dbutils.delete(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder));
244     }
245
246     private String getDpid(Node node) {
247         long dpid = southbound.getDataPathId(node);
248         if (dpid == 0) {
249             LOG.warn("getDpid: DPID could not be found for node: {}", node.getNodeId().getValue());
250         }
251         return String.valueOf(dpid);
252     }
253
254     private static InstanceIdentifier<Flow> createFlowPath(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
255         return InstanceIdentifier.builder(Nodes.class)
256                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
257                         nodeBuilder.getKey())
258                 .augmentation(FlowCapableNode.class)
259                 .child(Table.class, new TableKey(flowBuilder.getTableId()))
260                 .child(Flow.class, flowBuilder.getKey()).build();
261     }
262
263     private static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node>
264         createNodePath(NodeBuilder nodeBuilder) {
265         return InstanceIdentifier.builder(Nodes.class)
266                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
267                         nodeBuilder.getKey()).build();
268     }
269
270     private short getTable() {
271         return Service.INGRESS_ACL.getTable();
272     }
273
274     private final InstructionBuilder getMutablePipelineInstructionBuilder() {
275         Service nextService = orchestrator.getNextServiceInPipeline(Service.INGRESS_ACL);
276         if (nextService != null) {
277             return InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), nextService.getTable());
278         } else {
279             return InstructionUtils.createDropInstructions(new InstructionBuilder());
280         }
281     }
282
283     private void setDependencies(ServiceReference serviceReference) {
284         nodeCacheManager = (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
285         southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
286         orchestrator = (PipelineOrchestrator) ServiceHelper.getGlobalInstance(PipelineOrchestrator.class, this);
287     }
288 }