2 * Copyright (c) 2015 Dell, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.ovsdb.openstack.netvirt.sfc.openflow13;
11 import java.util.Iterator;
12 import java.util.List;
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.Lists;
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;
65 * Open vSwitch OpenFlow 1.3 Networking Provider for Netvirt SFC
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;
77 * {@link NetvirtSfcOF13Provider} constructor.
78 * @param dataBroker MdSal {@link DataBroker}
80 public NetvirtSfcOF13Provider(final DataBroker dataBroker) {
81 Preconditions.checkNotNull(dataBroker, "Input dataBroker cannot be NULL!");
83 //this.dataService = dataBroker;
84 dbutils = new MdsalUtils(dataBroker);
86 this.setDependencies(null);
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!");
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());
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());
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) {
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());
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());
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);
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()));
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);
148 InstructionsBuilder isb = null;
149 isb = buildActions(entry.getRuleName(), entry.getActions(), datapathId);
151 String flowId = "NETVIRT_SFC_FLOW" + "_" + entry.getRuleName();
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);
165 flowBuilder.setInstructions(isb.build());
168 writeFlow(flowBuilder, nodeBuilder);
170 removeFlow(flowBuilder, nodeBuilder);
174 private InstructionsBuilder buildActions(String ruleName, Actions actions, String datapathId) {
175 InstructionBuilder ib = new InstructionBuilder();
177 if (actions.getPacketHandling() instanceof Deny) {
178 InstructionUtils.createDropInstructions(ib);
179 } else if (actions.getPacketHandling() instanceof Permit) {
180 //Permit actPermit = (Permit) actions.getPacketHandling();
182 InstructionUtils.createDropInstructions(ib);
186 ib.setKey(new InstructionKey(0));
187 // Instructions List Stores Individual Instructions
188 List<Instruction> instructions = Lists.newArrayList();
189 instructions.add(ib.build());
191 // Call the InstructionBuilder Methods Containing Actions
192 ib = this.getMutablePipelineInstructionBuilder();
194 ib.setKey(new InstructionKey(1));
195 instructions.add(ib.build());
197 // Add InstructionBuilder to the Instruction(s)Builder List
198 InstructionsBuilder isb = new InstructionsBuilder();
199 isb.setInstruction(instructions);
203 private MatchBuilder buildMatch(String ruleName, Matches matches, String dpId) {
204 MatchBuilder matchBuilder = new MatchBuilder();
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());
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()));
224 //MatchUtils.createInPortMatch(matchBuilder, Long.getLong(dpId), Long.getLong(matches.getInputInterface()));
229 public void removeClassifierRules(Sff sff, Acl acl) {
230 // TODO Auto-generated method stub
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());
242 protected void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
243 dbutils.delete(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder));
246 private String getDpid(Node node) {
247 long dpid = southbound.getDataPathId(node);
249 LOG.warn("getDpid: DPID could not be found for node: {}", node.getNodeId().getValue());
251 return String.valueOf(dpid);
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();
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();
270 private short getTable() {
271 return Service.INGRESS_ACL.getTable();
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());
279 return InstructionUtils.createDropInstructions(new InstructionBuilder());
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);