59c9635a70b7386ea7a4a9d144889a2978c7dbbf
[netvirt.git] / vpnservice / dhcpservice / dhcpservice-impl / src / main / java / org / opendaylight / netvirt / dhcpservice / DhcpServiceUtils.java
1 /*
2  * Copyright (c) 2016 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
9 package org.opendaylight.netvirt.dhcpservice;
10
11 import java.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.LinkedList;
14 import java.util.List;
15 import java.util.concurrent.ExecutionException;
16
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
21 import org.opendaylight.genius.mdsalutil.ActionInfo;
22 import org.opendaylight.genius.mdsalutil.ActionType;
23 import org.opendaylight.genius.mdsalutil.FlowEntity;
24 import org.opendaylight.genius.mdsalutil.InstructionInfo;
25 import org.opendaylight.genius.mdsalutil.InstructionType;
26 import org.opendaylight.genius.mdsalutil.MDSALUtil;
27 import org.opendaylight.genius.mdsalutil.MatchFieldType;
28 import org.opendaylight.genius.mdsalutil.MatchInfo;
29 import org.opendaylight.genius.mdsalutil.NwConstants;
30 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
31 import org.opendaylight.genius.mdsalutil.packet.IPProtocols;
32 import org.opendaylight.genius.utils.ServiceIndex;
33 import org.opendaylight.netvirt.dhcpservice.api.DHCPMConstants;
34 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesListKey;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVxlan;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.NetworkKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
62 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65
66 import com.google.common.base.Optional;
67 import com.google.common.util.concurrent.CheckedFuture;
68
69 public class DhcpServiceUtils {
70
71     private static final Logger LOG = LoggerFactory.getLogger(DhcpServiceUtils.class);
72
73     public static void setupDhcpFlowEntry(BigInteger dpId, short tableId, String vmMacAddress, int addOrRemove, IMdsalApiManager mdsalUtil, WriteTransaction tx) {
74         if (dpId == null || dpId.equals(DHCPMConstants.INVALID_DPID) || vmMacAddress == null) {
75             return;
76         }
77         List<MatchInfo> matches = getDhcpMatch(vmMacAddress);
78
79         List<InstructionInfo> instructions = new ArrayList<>();
80         List<ActionInfo> actionsInfos = new ArrayList<>();
81
82         // Punt to controller
83         actionsInfos.add(new ActionInfo(ActionType.punt_to_controller,
84                 new String[] {}));
85         instructions.add(new InstructionInfo(InstructionType.apply_actions,
86                 actionsInfos));
87         if (addOrRemove == NwConstants.DEL_FLOW) {
88             FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
89                     getDhcpFlowRef(dpId, tableId, vmMacAddress),
90                     DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
91                     DHCPMConstants.COOKIE_DHCP_BASE, matches, null);
92             LOG.trace("Removing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
93             DhcpServiceCounters.remove_dhcp_flow.inc();
94             mdsalUtil.removeFlowToTx(flowEntity, tx);
95         } else {
96             FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
97                     getDhcpFlowRef(dpId, tableId, vmMacAddress),DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
98                     DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
99             LOG.trace("Installing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
100             DhcpServiceCounters.install_dhcp_flow.inc();
101             mdsalUtil.addFlowToTx(flowEntity, tx);
102         }
103     }
104
105     private static String getDhcpFlowRef(BigInteger dpId, long tableId, String vmMacAddress) {
106         return new StringBuffer().append(DHCPMConstants.FLOWID_PREFIX)
107                 .append(dpId).append(NwConstants.FLOWID_SEPARATOR)
108                 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
109                 .append(vmMacAddress).toString();
110     }
111
112     public static void setupDhcpDropAction(BigInteger dpId, short tableId, String vmMacAddress, int addOrRemove, IMdsalApiManager mdsalUtil, WriteTransaction tx) {
113         if (dpId == null || dpId.equals(DHCPMConstants.INVALID_DPID) || vmMacAddress == null) {
114             return;
115         }
116         List<MatchInfo> matches = getDhcpMatch(vmMacAddress);
117
118         List<ActionInfo> actionsInfos = new ArrayList<>();
119         List<InstructionInfo> instructions = new ArrayList<>();
120         instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
121         // Drop Action
122         actionsInfos.add(new ActionInfo(ActionType.drop_action,
123                 new String[] {}));
124         if (addOrRemove == NwConstants.DEL_FLOW) {
125             FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
126                     getDhcpFlowRef(dpId, tableId, vmMacAddress),
127                     DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
128                     DHCPMConstants.COOKIE_DHCP_BASE, matches, null);
129             LOG.trace("Removing DHCP Drop Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
130             DhcpServiceCounters.remove_dhcp_drop_flow.inc();
131             mdsalUtil.removeFlowToTx(flowEntity, tx);
132         } else {
133             FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
134                     getDhcpFlowRef(dpId, tableId, vmMacAddress),DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
135                     DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
136             LOG.trace("Installing DHCP Drop Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
137             DhcpServiceCounters.install_dhcp_drop_flow.inc();
138             mdsalUtil.addFlowToTx(flowEntity, tx);
139         }
140     }
141
142     private static List<MatchInfo> getDhcpMatch(String vmMacAddress) {
143         List<MatchInfo> matches = new ArrayList<>();
144         matches.add(new MatchInfo(MatchFieldType.eth_type,
145                 new long[] { NwConstants.ETHTYPE_IPV4 }));
146         matches.add(new MatchInfo(MatchFieldType.ip_proto,
147                 new long[] { IPProtocols.UDP.intValue() }));
148         matches.add(new MatchInfo(MatchFieldType.udp_src,
149                 new long[] { DHCPMConstants.dhcpClientPort }));
150         matches.add(new MatchInfo(MatchFieldType.udp_dst,
151                 new long[] { DHCPMConstants.dhcpServerPort }));
152         matches.add(new MatchInfo(MatchFieldType.eth_src,
153                 new String[] { vmMacAddress }));
154         return matches;
155     }
156
157     public static List<BigInteger> getListOfDpns(DataBroker broker) {
158         List<BigInteger> dpnsList = new LinkedList<>();
159         InstanceIdentifier<Nodes> nodesInstanceIdentifier = InstanceIdentifier.builder(Nodes.class).build();
160         Optional<Nodes> nodesOptional = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, nodesInstanceIdentifier);
161         if (!nodesOptional.isPresent()) {
162             return dpnsList;
163         }
164         Nodes nodes = nodesOptional.get();
165         List<Node> nodeList = nodes.getNode();
166         for (Node node : nodeList) {
167             NodeId nodeId = node.getId();
168             if (nodeId == null) {
169                 continue;
170             }
171             BigInteger dpnId = MDSALUtil.getDpnIdFromNodeName(nodeId);
172             dpnsList.add(dpnId);
173         }
174         return dpnsList;
175     }
176
177     public static List<BigInteger> getDpnsForElan(String elanInstanceName, DataBroker broker) {
178         List<BigInteger> elanDpns = new LinkedList<>();
179         InstanceIdentifier<ElanDpnInterfacesList> elanDpnInstanceIdentifier = InstanceIdentifier.builder(ElanDpnInterfaces.class).child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName)).build();
180         Optional<ElanDpnInterfacesList> elanDpnOptional = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInstanceIdentifier);
181         if (elanDpnOptional.isPresent()) {
182             List<DpnInterfaces> dpns = elanDpnOptional.get().getDpnInterfaces();
183             for (DpnInterfaces dpnInterfaces : dpns) {
184                 elanDpns.add(dpnInterfaces.getDpId());
185             }
186         }
187         return elanDpns;
188     }
189
190     public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceFromOperationalDS(String interfaceName, DataBroker dataBroker) {
191         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey interfaceKey = new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(interfaceName);
192         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> interfaceId = InstanceIdentifier.builder(InterfacesState.class).child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class, interfaceKey).build();
193         Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> interfaceOptional = MDSALUtil.read(LogicalDatastoreType.OPERATIONAL, interfaceId, dataBroker);
194         if (!interfaceOptional.isPresent()) {
195             return null;
196         }
197         return interfaceOptional.get();
198     }
199
200
201     public static String getSegmentationId(Uuid networkId, DataBroker broker) {
202         InstanceIdentifier<Network> inst = InstanceIdentifier.create(Neutron.class).child(Networks.class).child
203                 (Network.class, new NetworkKey(networkId));
204         Optional<Network> optionalNetwork = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, inst);
205         if (!optionalNetwork.isPresent()) {
206             return null;
207         }
208         Network network = optionalNetwork.get();
209         String segmentationId = NeutronUtils.getSegmentationIdFromNeutronNetwork(network, NetworkTypeVxlan.class);
210         return segmentationId;
211     }
212
213     public static String getNodeIdFromDpnId(BigInteger dpnId) {
214         return MDSALUtil.NODE_PREFIX + MDSALUtil.SEPARATOR + dpnId.toString();
215     }
216
217     public static String getTrunkPortMacAddress(String parentRefName,
218             DataBroker broker) {
219         InstanceIdentifier<Port> portInstanceIdentifier = InstanceIdentifier.create(Neutron.class).child(Ports.class).child(Port.class);
220         Optional<Port> trunkPort = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, portInstanceIdentifier);
221         if (!trunkPort.isPresent()) {
222             LOG.warn("Trunk port {} not available for sub-port", parentRefName);
223             return null;
224         }
225         return trunkPort.get().getMacAddress().getValue();
226     }
227
228     public static String getJobKey(String interfaceName) {
229         return new StringBuilder().append(DHCPMConstants.DHCP_JOB_KEY_PREFIX).append(interfaceName).toString();
230     }
231
232     public static void submitTransaction(WriteTransaction tx) {
233         CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
234         try {
235             futures.get();
236         } catch (InterruptedException | ExecutionException e) {
237             LOG.error("Error writing to datastore tx {} error {}", tx, e.getMessage());
238         }
239     }
240
241     public static void bindDhcpService(String interfaceName, short tableId, WriteTransaction tx) {
242         int instructionKey = 0;
243         List<Instruction> instructions = new ArrayList<>();
244         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(tableId, ++instructionKey));
245         short serviceIndex = ServiceIndex.getIndex(NwConstants.DHCP_SERVICE_NAME, NwConstants.DHCP_SERVICE_INDEX);
246         BoundServices
247                 serviceInfo =
248                 getBoundServices(String.format("%s.%s", "dhcp", interfaceName),
249                         serviceIndex, DHCPMConstants.DEFAULT_FLOW_PRIORITY,
250                         DHCPMConstants.COOKIE_VM_INGRESS_TABLE, instructions);
251         tx.put(LogicalDatastoreType.CONFIGURATION,
252                 buildServiceId(interfaceName, serviceIndex), serviceInfo, true);
253     }
254
255     public static void unbindDhcpService(String interfaceName, WriteTransaction tx) {
256         short serviceIndex = ServiceIndex.getIndex(NwConstants.DHCP_SERVICE_NAME, NwConstants.DHCP_SERVICE_INDEX);
257         tx.delete(LogicalDatastoreType.CONFIGURATION,
258                 buildServiceId(interfaceName, serviceIndex));
259     }
260
261     private static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName,
262                                                              short dhcpServicePriority) {
263         return InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class, new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
264                 .child(BoundServices.class, new BoundServicesKey(dhcpServicePriority)).build();
265     }
266
267     public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
268                                           BigInteger cookie, List<Instruction> instructions) {
269         StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority).setInstruction(instructions);
270         return new BoundServicesBuilder().setKey(new BoundServicesKey(servicePriority))
271                 .setServiceName(serviceName).setServicePriority(servicePriority)
272                 .setServiceType(ServiceTypeFlowBased.class).addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
273     }
274 }