Working with OVS
[vpnservice.git] / interfacemgr / interfacemgr-impl / src / main / java / org / opendaylight / vpnservice / interfacemgr / servicebindings / flowbased / utilities / FlowBasedServicesUtils.java
1 /*
2  * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. 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 package org.opendaylight.vpnservice.interfacemgr.servicebindings.flowbased.utilities;
9
10 import com.google.common.base.Optional;
11 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
12 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
13 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
14 import org.opendaylight.vpnservice.interfacemgr.IfmConstants;
15 import org.opendaylight.vpnservice.interfacemgr.IfmUtil;
16 import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceManagerCommonUtils;
17 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
18 import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
19 import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
20 import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteMetadataCase;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.ServiceBindings;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.StypeOpenflow;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.ServicesInfo;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.ServicesInfoKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServices;
41 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 import java.math.BigInteger;
46 import java.util.ArrayList;
47 import java.util.List;
48
49 public class FlowBasedServicesUtils {
50     private static final Logger LOG = LoggerFactory.getLogger(FlowBasedServicesUtils.class);
51
52     public static ServicesInfo getServicesInfoForInterface(String interfaceName, DataBroker dataBroker) {
53         ServicesInfoKey servicesInfoKey = new ServicesInfoKey(interfaceName);
54         InstanceIdentifier.InstanceIdentifierBuilder<ServicesInfo> servicesInfoIdentifierBuilder =
55                 InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class, servicesInfoKey);
56         Optional<ServicesInfo> servicesInfoOptional = IfmUtil.read(LogicalDatastoreType.CONFIGURATION,
57                 servicesInfoIdentifierBuilder.build(), dataBroker);
58
59         if (servicesInfoOptional.isPresent()) {
60             return servicesInfoOptional.get();
61         }
62
63         return null;
64     }
65
66     public static NodeConnectorId getNodeConnectorIdFromInterface(Interface iface, DataBroker dataBroker) {
67         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState =
68                 InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(iface.getName(), dataBroker);
69         List<String> ofportIds = ifState.getLowerLayerIf();
70         return new NodeConnectorId(ofportIds.get(0));
71     }
72
73     public static List<MatchInfo> getMatchInfoForVlanPortAtIngressTable(BigInteger dpId, long portNo, long vlanId) {
74         List<MatchInfo> matches = new ArrayList<>();
75         matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {dpId, BigInteger.valueOf(portNo)}));
76         if (vlanId > 0) {
77             LOG.error("VlanId matching support is not fully available in Be.");
78             matches.add(new MatchInfo(MatchFieldType.vlan_vid, new long[]{vlanId}));
79         }
80         return matches;
81     }
82
83     public static List<MatchInfo> getMatchInfoForTunnelPortAtIngressTable(BigInteger dpId, long portNo, Interface iface) {
84         List<MatchInfo> matches = new ArrayList<MatchInfo>();
85         matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[]{dpId, BigInteger.valueOf(portNo)}));
86         /*IfTunnel tunnel = iface.getAugmentation(IfTunnel.class);
87         TunnelResources tunnelResources = tunnel.getTunnelResources();
88         if (tunnelResources.getTunnelType().isAssignableFrom(TunnelTypeGre.class)) {
89             IfGre ifgre = tunnelResources.getAugmentation(IfGre.class);
90             BigInteger grekey = ifgre.getGreKey();
91             // FIXME: Add tunnel-id match information
92
93         } else if (tunnelResources.getTunnelType().isAssignableFrom(TunnelTypeVxlan.class)) {
94             IfVxlan ifVxlan = tunnelResources.getAugmentation(IfVxlan.class);
95             BigInteger vni = ifVxlan.getVni();
96             // FIXME: Add tunnel-id match information
97         }*/
98
99         return matches;
100     }
101
102     public static List<MatchInfo> getMatchInfoForDispatcherTable(BigInteger dpId, Interface iface,
103                                                                  int interfaceTag, short servicePriority) {
104         List<MatchInfo> matches = new ArrayList<MatchInfo>();
105         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
106                 MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, servicePriority),
107                 MetaDataUtil.getMetaDataMaskForLPortDispatcher() }));
108         /*if (iface.getType().isAssignableFrom(Tunnel.class)) {
109             IfTunnel tunnel = iface.getAugmentation(IfTunnel.class);
110             TunnelResources tunnelResources = tunnel.getTunnelResources();
111             if (tunnelResources.getTunnelType().isAssignableFrom(TunnelTypeGre.class)) {
112                 IfGre ifgre = tunnelResources.getAugmentation(IfGre.class);
113                 BigInteger grekey = ifgre.getGreKey();
114                 // FIXME: Add tunnel-id match information
115
116             } else if (tunnelResources.getTunnelType().isAssignableFrom(TunnelTypeVxlan.class)) {
117                 IfVxlan ifVxlan = tunnelResources.getAugmentation(IfVxlan.class);
118                 BigInteger vni = ifVxlan.getVni();
119                 // FIXME: Add tunnel-id match information
120             }
121         }*/
122         return matches;
123     }
124
125     public static Long getLPortTag(Interface iface, DataBroker dataBroker) {
126         /*ParentRefs parentRefs = iface.getAugmentation(ParentRefs.class);
127         String portName = parentRefs.getParentInterface();
128         BigInteger dpIdFromInterface = parentRefs.getDatapathNodeIdentifier();
129         String portKey = FlowBasedServicesUtils.getInterfaceRefInfo(dpIdFromInterface.toString(), portName);
130         if (iface.getType().isAssignableFrom(L2vlan.class)) {
131             InterfacesMetaKey interfacesMetaKey = new InterfacesMetaKey(portKey);
132             InterfacesInfoKey interfacesInfoKey = new InterfacesInfoKey(iface.getName());
133             InterfacesInfo interfacesInfo = VlanInterfaceUtilities.getInterfacesInfoFromConfigDS(interfacesMetaKey,
134                     interfacesInfoKey, dataBroker);
135             return interfacesInfo.getLporttag();
136         } else if (iface.getType().isAssignableFrom(Tunnel.class)) {
137             TunnelInterfaceRefInfoKey tunnelInterfaceRefInfoKey = new TunnelInterfaceRefInfoKey(portKey);
138             TunnelInterfaceEntries tunnelInterfaceEntries =
139                     TunnelInterfaceUtilities.getTunnelInterfaceRefEntriesFromConfigDs(
140                             tunnelInterfaceRefInfoKey, iface.getName(), dataBroker);
141             return tunnelInterfaceEntries.getLportTag();
142         } */
143         return 0L;
144     }
145
146     public static void installInterfaceIngressFlow(BigInteger dpId, int vlanId,
147                                                    BoundServices boundServiceNew,
148                                                    DataBroker dataBroker, WriteTransaction t,
149                                                    List<MatchInfo> matches, int lportTag, short tableId) {
150         List<Instruction> instructions = boundServiceNew.getAugmentation(StypeOpenflow.class).getInstruction();
151
152         int serviceInstructionsSize = instructions.size();
153         List<Instruction> instructionSet = new ArrayList<Instruction>();
154         if (vlanId != 0) {
155             // incrementing instructionSize and using it as actionKey. Because it won't clash with any other instructions
156             int actionKey = ++serviceInstructionsSize;
157             instructionSet.add(MDSALUtil.buildAndGetPopVlanActionInstruction(actionKey, ++serviceInstructionsSize));
158         }
159
160         if (lportTag != 0L) {
161             BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(instructions);
162             short sIndex = boundServiceNew.getServicePriority();
163             BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag,
164                     ++sIndex, metadataValues[0]);
165             BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(
166                     MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
167                     MetaDataUtil.METADATA_MASK_LPORT_TAG, metadataValues[1]);
168             instructionSet.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask,
169                     ++serviceInstructionsSize));
170         }
171
172         if (instructions != null && !instructions.isEmpty()) {
173             for (Instruction info : instructions) {
174                 // Skip meta data write as that is handled already
175                 if (info.getInstruction() instanceof WriteMetadataCase) {
176                     continue;
177                 }
178                 instructionSet.add(info);
179             }
180         }
181
182         String serviceRef = boundServiceNew.getServiceName();
183         StypeOpenflow stypeOpenflow = boundServiceNew.getAugmentation(StypeOpenflow.class);
184         Flow ingressFlow = MDSALUtil.buildFlowNew(tableId, serviceRef,
185                 stypeOpenflow.getFlowPriority(), serviceRef, 0, 0,
186                 stypeOpenflow.getFlowCookie(), matches, instructionSet);
187         installFlow(dpId, ingressFlow, dataBroker, t);
188     }
189
190     private static void installFlow(BigInteger dpId, Flow flow, DataBroker dataBroker, WriteTransaction t) {
191         FlowKey flowKey = new FlowKey(new FlowId(flow.getId()));
192         Node nodeDpn = buildInventoryDpnNode(dpId);
193         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
194                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
195                 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class,flowKey).build();
196
197         t.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
198     }
199
200     private static Node buildInventoryDpnNode(BigInteger dpnId) {
201         NodeId nodeId = new NodeId("openflow:" + dpnId);
202         Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
203
204         return nodeDpn;
205     }
206
207     public static void installLPortDispatcherFlow(BigInteger dpId, BoundServices boundService, Interface iface,
208                                                   DataBroker dataBroker, WriteTransaction t, int interfaceTag) {
209         LOG.debug("Installing LPort Dispatcher Flows {}, {}", dpId, iface);
210         short serviceIndex = boundService.getServicePriority();
211         String serviceRef = boundService.getServiceName();
212         List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForDispatcherTable(dpId, iface,
213                 interfaceTag, serviceIndex);
214
215         // Get the metadata and mask from the service's write metadata instruction
216         StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
217         List<Instruction> serviceInstructions = stypeOpenFlow.getInstruction();
218         int instructionSize = serviceInstructions.size();
219         BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(serviceInstructions);
220         BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, ++serviceIndex, metadataValues[0]);
221         BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
222                 MetaDataUtil.METADATA_MASK_LPORT_TAG, metadataValues[1]);
223
224         // build the final instruction for LPort Dispatcher table flow entry
225         List<Instruction> instructions = new ArrayList<Instruction>();
226         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++instructionSize));
227         if (serviceInstructions != null && !serviceInstructions.isEmpty()) {
228             for (Instruction info : serviceInstructions) {
229                 // Skip meta data write as that is handled already
230                 if (info.getInstruction() instanceof WriteMetadataCase) {
231                     continue;
232                 }
233                 instructions.add(info);
234             }
235         }
236
237         // build the flow and install it
238         Flow ingressFlow = MDSALUtil.buildFlowNew(stypeOpenFlow.getDispatcherTableId(), serviceRef,
239                 boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches, instructions);
240         installFlow(dpId, ingressFlow, dataBroker, t);
241     }
242
243     public static void removeIngressFlow(Interface iface, BoundServices serviceOld, BigInteger dpId,
244                                          DataBroker dataBroker, WriteTransaction t) {
245         LOG.debug("Removing Ingress Flows");
246         String flowKeyStr = iface.getName() + serviceOld.getServicePriority() +
247                 serviceOld.getServiceName() + IfmConstants.VLAN_INTERFACE_INGRESS_TABLE;
248         FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
249         Node nodeDpn = buildInventoryDpnNode(dpId);
250         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
251                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
252                 .child(Table.class, new TableKey(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
253
254         t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
255     }
256
257     public static void removeLPortDispatcherFlow(BigInteger dpId, Interface iface, BoundServices boundServicesOld,
258                                                  DataBroker dataBroker, WriteTransaction t) {
259         LOG.debug("Removing LPort Dispatcher Flows {}, {}", dpId, iface);
260         Long interfaceTag = FlowBasedServicesUtils.getLPortTag(iface, dataBroker);
261
262         StypeOpenflow stypeOpenFlow = boundServicesOld.getAugmentation(StypeOpenflow.class);
263         String flowKeyStr = iface.getName() + boundServicesOld.getServicePriority() +
264                 boundServicesOld.getServiceName() + stypeOpenFlow.getDispatcherTableId();
265         FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
266         Node nodeDpn = buildInventoryDpnNode(dpId);
267         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
268                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
269                 .child(Table.class, new TableKey(stypeOpenFlow.getDispatcherTableId())).child(Flow.class, flowKey).build();
270
271         t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
272     }
273
274     public static String getInterfaceRefInfo(String dpId, String portName) {
275         String portRefInfo = "";
276         if (!"".equals(dpId)) {
277             portRefInfo = dpId.toString() + ":";
278         }
279         portRefInfo = portRefInfo + portName;
280         return portRefInfo;
281     }
282 }