Fix build faliures due to OFPlugin checktyle fixes
[netvirt.git] / 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 com.google.common.base.Optional;
12 import com.google.common.util.concurrent.FutureCallback;
13 import java.math.BigInteger;
14 import java.net.InetAddress;
15 import java.net.UnknownHostException;
16 import java.util.ArrayList;
17 import java.util.Arrays;
18 import java.util.Collections;
19 import java.util.LinkedList;
20 import java.util.List;
21 import java.util.Objects;
22 import java.util.function.BiConsumer;
23 import java.util.function.Consumer;
24 import java.util.stream.Collectors;
25 import java.util.stream.IntStream;
26 import java.util.stream.LongStream;
27 import javax.annotation.Nonnull;
28 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
29 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
30 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
31 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
32 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
33 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
34 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
35 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
36 import org.opendaylight.genius.mdsalutil.ActionInfo;
37 import org.opendaylight.genius.mdsalutil.FlowEntity;
38 import org.opendaylight.genius.mdsalutil.InstructionInfo;
39 import org.opendaylight.genius.mdsalutil.MDSALDataStoreUtils;
40 import org.opendaylight.genius.mdsalutil.MDSALUtil;
41 import org.opendaylight.genius.mdsalutil.MatchInfo;
42 import org.opendaylight.genius.mdsalutil.NWUtil;
43 import org.opendaylight.genius.mdsalutil.NwConstants;
44 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
45 import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
46 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
47 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
48 import org.opendaylight.genius.mdsalutil.matches.MatchArpOp;
49 import org.opendaylight.genius.mdsalutil.matches.MatchArpTpa;
50 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetSource;
51 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
52 import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
53 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
54 import org.opendaylight.genius.mdsalutil.matches.MatchUdpDestinationPort;
55 import org.opendaylight.genius.mdsalutil.matches.MatchUdpSourcePort;
56 import org.opendaylight.genius.utils.ServiceIndex;
57 import org.opendaylight.netvirt.dhcpservice.api.DhcpMConstants;
58 import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
59 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
60 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
61 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
62 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
63 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesListKey;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkMaps;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMap;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMapKey;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionBase;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionV4;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVxlan;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.NetworkKey;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetKey;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.InterfaceNameMacAddresses;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.SubnetDhcpPortData;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddress;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddressBuilder;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710._interface.name.mac.addresses.InterfaceNameMacAddressKey;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.subnet.dhcp.port.data.SubnetToDhcpPort;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.subnet.dhcp.port.data.SubnetToDhcpPortBuilder;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.api.rev150710.subnet.dhcp.port.data.SubnetToDhcpPortKey;
106 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
107 import org.slf4j.Logger;
108 import org.slf4j.LoggerFactory;
109
110 public final class DhcpServiceUtils {
111
112     private static final Logger LOG = LoggerFactory.getLogger(DhcpServiceUtils.class);
113     private static final FutureCallback<Void> DEFAULT_CALLBACK = new FutureCallback<Void>() {
114         @Override
115         public void onSuccess(Void result) {
116             LOG.debug("Success in Datastore write operation");
117         }
118
119         @Override
120         public void onFailure(Throwable error) {
121             LOG.error("Error in Datastore write operation", error);
122         }
123     };
124
125     private DhcpServiceUtils() { }
126
127     public static void setupDhcpFlowEntry(BigInteger dpId, short tableId, String vmMacAddress, int addOrRemove,
128                                           IMdsalApiManager mdsalUtil, WriteTransaction tx) {
129         if (dpId == null || dpId.equals(DhcpMConstants.INVALID_DPID) || vmMacAddress == null) {
130             return;
131         }
132         List<MatchInfo> matches = getDhcpMatch(vmMacAddress);
133         List<InstructionInfo> instructions = new ArrayList<>();
134         List<ActionInfo> actionsInfos = new ArrayList<>();
135
136         // Punt to controller
137         actionsInfos.add(new ActionPuntToController());
138         instructions.add(new InstructionApplyActions(actionsInfos));
139         if (addOrRemove == NwConstants.DEL_FLOW) {
140             FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
141                     getDhcpFlowRef(dpId, tableId, vmMacAddress),
142                     DhcpMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
143                     DhcpMConstants.COOKIE_DHCP_BASE, matches, null);
144             LOG.trace("Removing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
145             DhcpServiceCounters.remove_dhcp_flow.inc();
146             mdsalUtil.removeFlowToTx(flowEntity, tx);
147         } else {
148             FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
149                     getDhcpFlowRef(dpId, tableId, vmMacAddress), DhcpMConstants.DEFAULT_DHCP_FLOW_PRIORITY,
150                     "DHCP", 0, 0, DhcpMConstants.COOKIE_DHCP_BASE, matches, instructions);
151             LOG.trace("Installing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
152             DhcpServiceCounters.install_dhcp_flow.inc();
153             mdsalUtil.addFlowToTx(flowEntity, tx);
154         }
155     }
156
157     private static String getDhcpFlowRef(BigInteger dpId, long tableId, String vmMacAddress) {
158         return new StringBuffer().append(DhcpMConstants.FLOWID_PREFIX)
159                 .append(dpId).append(NwConstants.FLOWID_SEPARATOR)
160                 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
161                 .append(vmMacAddress).toString();
162     }
163
164     private static String getDhcpArpFlowRef(BigInteger dpId, long tableId, long lportTag, String ipAddress) {
165         return new StringBuffer().append(DhcpMConstants.FLOWID_PREFIX)
166                 .append(dpId).append(NwConstants.FLOWID_SEPARATOR)
167                 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
168                 .append(lportTag).append(NwConstants.FLOWID_SEPARATOR)
169                 .append(ipAddress).toString();
170     }
171
172     public static void setupDhcpDropAction(BigInteger dpId, short tableId, String vmMacAddress, int addOrRemove,
173                                            IMdsalApiManager mdsalUtil, WriteTransaction tx) {
174         if (dpId == null || dpId.equals(DhcpMConstants.INVALID_DPID) || vmMacAddress == null) {
175             return;
176         }
177         List<MatchInfo> matches = getDhcpMatch(vmMacAddress);
178
179         List<ActionInfo> actionsInfos = new ArrayList<>();
180         List<InstructionInfo> instructions = new ArrayList<>();
181         instructions.add(new InstructionApplyActions(actionsInfos));
182         // Drop Action
183         actionsInfos.add(new ActionDrop());
184         if (addOrRemove == NwConstants.DEL_FLOW) {
185             FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
186                     getDhcpFlowRef(dpId, tableId, vmMacAddress),
187                     DhcpMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
188                     DhcpMConstants.COOKIE_DHCP_BASE, matches, null);
189             LOG.trace("Removing DHCP Drop Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
190             DhcpServiceCounters.remove_dhcp_drop_flow.inc();
191             mdsalUtil.removeFlowToTx(flowEntity, tx);
192         } else {
193             FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
194                     getDhcpFlowRef(dpId, tableId, vmMacAddress), DhcpMConstants.DEFAULT_DHCP_FLOW_PRIORITY,
195                     "DHCP", 0, 0, DhcpMConstants.COOKIE_DHCP_BASE, matches, instructions);
196             LOG.trace("Installing DHCP Drop Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
197             DhcpServiceCounters.install_dhcp_drop_flow.inc();
198             mdsalUtil.addFlowToTx(flowEntity, tx);
199         }
200     }
201
202     @SuppressWarnings("checkstyle:IllegalCatch")
203     public static void setupDhcpArpRequest(BigInteger dpId, short tableId, BigInteger vni, String dhcpIpAddress,
204                                            int lportTag, Long elanTag, boolean add, IMdsalApiManager mdsalUtil) {
205         List<MatchInfo> matches = getDhcpArpMatch(vni, dhcpIpAddress);
206         if (add) {
207             Flow flow = MDSALUtil.buildFlowNew(tableId, getDhcpArpFlowRef(dpId, tableId, lportTag, dhcpIpAddress),
208                     DhcpMConstants.DEFAULT_DHCP_ARP_FLOW_PRIORITY, "DHCPArp", 0, 0,
209                     generateDhcpArpCookie(lportTag, dhcpIpAddress), matches, null);
210             LOG.trace("Removing DHCP ARP Flow DpId {}, DHCP Port IpAddress {}", dpId, dhcpIpAddress);
211             mdsalUtil.removeFlow(dpId, flow);
212         } else {
213             Flow flow = MDSALUtil.buildFlowNew(tableId, getDhcpArpFlowRef(dpId, tableId, lportTag, dhcpIpAddress),
214                     DhcpMConstants.DEFAULT_DHCP_ARP_FLOW_PRIORITY, "DHCPArp", 0, 0,
215                     generateDhcpArpCookie(lportTag, dhcpIpAddress), matches,
216                     getDhcpArpInstructions(elanTag, lportTag));
217             LOG.trace("Adding DHCP ARP Flow DpId {}, DHCPPort IpAddress {}", dpId, dhcpIpAddress);
218             mdsalUtil.installFlow(dpId, flow);
219         }
220     }
221
222     public static List<MatchInfo> getDhcpMatch() {
223         List<MatchInfo> matches = new ArrayList<>();
224         matches.add(MatchEthernetType.IPV4);
225         matches.add(MatchIpProtocol.UDP);
226         matches.add(new MatchUdpSourcePort(DhcpMConstants.DHCP_CLIENT_PORT));
227         matches.add(new MatchUdpDestinationPort(DhcpMConstants.DHCP_SERVER_PORT));
228         return matches;
229     }
230
231     public static List<MatchInfo> getDhcpMatch(String vmMacAddress) {
232         List<MatchInfo> matches = getDhcpMatch();
233         matches.add(new MatchEthernetSource(new MacAddress(vmMacAddress)));
234         return matches;
235     }
236
237     private static List<MatchInfo> getDhcpArpMatch(BigInteger vni, String ipAddress) {
238         return Arrays.asList(MatchEthernetType.ARP, MatchArpOp.REQUEST, new MatchTunnelId(vni),
239                 new MatchArpTpa(ipAddress, "32"));
240     }
241
242     private static List<Instruction> getDhcpArpInstructions(Long elanTag, int lportTag) {
243         List<Instruction> mkInstructions = new ArrayList<>();
244         int instructionKey = 0;
245         mkInstructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(
246                 ElanHelper.getElanMetadataLabel(elanTag, lportTag), ElanHelper.getElanMetadataMask(),
247                 ++instructionKey));
248         mkInstructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_RESPONDER_TABLE,
249                 ++instructionKey));
250         return mkInstructions;
251     }
252
253     private static BigInteger generateDhcpArpCookie(int lportTag, String ipAddress) {
254         try {
255             BigInteger cookie = NwConstants.TUNNEL_TABLE_COOKIE.add(BigInteger.valueOf(255))
256                     .add(BigInteger.valueOf(NWUtil.convertInetAddressToLong(InetAddress.getByName(ipAddress))));
257             return cookie.add(BigInteger.valueOf(lportTag));
258         } catch (UnknownHostException e) {
259             return NwConstants.TUNNEL_TABLE_COOKIE.add(BigInteger.valueOf(lportTag));
260         }
261     }
262
263     public static List<BigInteger> getListOfDpns(DataBroker broker) {
264         return extractDpnsFromNodes(MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
265                 InstanceIdentifier.builder(Nodes.class).build()));
266     }
267
268     @Nonnull
269     public static List<BigInteger> getListOfDpns(ReadTransaction tx) throws ReadFailedException {
270         return extractDpnsFromNodes(tx.read(LogicalDatastoreType.OPERATIONAL,
271                 InstanceIdentifier.builder(Nodes.class).build()).checkedGet());
272     }
273
274     @Nonnull
275     private static List<BigInteger> extractDpnsFromNodes(Optional<Nodes> optionalNodes) {
276         return optionalNodes.toJavaUtil().map(
277             nodes -> nodes.getNode().stream().map(Node::getId).filter(Objects::nonNull).map(
278                     MDSALUtil::getDpnIdFromNodeName).collect(
279                     Collectors.toList())).orElse(Collections.emptyList());
280     }
281
282     @Nonnull
283     public static List<BigInteger> getDpnsForElan(String elanInstanceName, DataBroker broker) {
284         List<BigInteger> elanDpns = new LinkedList<>();
285         InstanceIdentifier<ElanDpnInterfacesList> elanDpnInstanceIdentifier =
286                 InstanceIdentifier.builder(ElanDpnInterfaces.class)
287                         .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName)).build();
288         Optional<ElanDpnInterfacesList> elanDpnOptional =
289                 MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInstanceIdentifier);
290         if (elanDpnOptional.isPresent()) {
291             List<DpnInterfaces> dpns = elanDpnOptional.get().getDpnInterfaces();
292             for (DpnInterfaces dpnInterfaces : dpns) {
293                 elanDpns.add(dpnInterfaces.getDpId());
294             }
295         }
296         return elanDpns;
297     }
298
299     public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
300             .state.Interface getInterfaceFromOperationalDS(String interfaceName, DataBroker dataBroker) {
301         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
302                 .state.InterfaceKey interfaceKey =
303                 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
304                         .state.InterfaceKey(interfaceName);
305         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
306                 .interfaces.state.Interface> interfaceId = InstanceIdentifier.builder(InterfacesState.class)
307                 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
308                         .interfaces.state.Interface.class, interfaceKey).build();
309         return MDSALUtil.read(LogicalDatastoreType.OPERATIONAL, interfaceId, dataBroker).orNull();
310     }
311
312
313     public static String getSegmentationId(Uuid networkId, DataBroker broker) {
314         InstanceIdentifier<Network> inst = InstanceIdentifier.create(Neutron.class)
315                 .child(Networks.class).child(Network.class, new NetworkKey(networkId));
316         Optional<Network> optionalNetwork = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, inst);
317         if (!optionalNetwork.isPresent()) {
318             return null;
319         }
320         Network network = optionalNetwork.get();
321         String segmentationId = NeutronUtils.getSegmentationIdFromNeutronNetwork(network, NetworkTypeVxlan.class);
322         return segmentationId;
323     }
324
325     public static String getNodeIdFromDpnId(BigInteger dpnId) {
326         return MDSALUtil.NODE_PREFIX + MDSALUtil.SEPARATOR + dpnId.toString();
327     }
328
329     public static String getTrunkPortMacAddress(String parentRefName,
330             DataBroker broker) {
331         InstanceIdentifier<Port> portInstanceIdentifier =
332                 InstanceIdentifier.create(Neutron.class).child(Ports.class).child(Port.class);
333         Optional<Port> trunkPort = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, portInstanceIdentifier);
334         if (!trunkPort.isPresent()) {
335             LOG.warn("Trunk port {} not available for sub-port", parentRefName);
336             return null;
337         }
338         return trunkPort.get().getMacAddress().getValue();
339     }
340
341     public static String getJobKey(String interfaceName) {
342         return new StringBuilder().append(DhcpMConstants.DHCP_JOB_KEY_PREFIX).append(interfaceName).toString();
343     }
344
345     public static void bindDhcpService(String interfaceName, short tableId, WriteTransaction tx) {
346         int instructionKey = 0;
347         List<Instruction> instructions = new ArrayList<>();
348         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(tableId, ++instructionKey));
349         short serviceIndex = ServiceIndex.getIndex(NwConstants.DHCP_SERVICE_NAME, NwConstants.DHCP_SERVICE_INDEX);
350         BoundServices
351                 serviceInfo =
352                 getBoundServices(String.format("%s.%s", "dhcp", interfaceName),
353                         serviceIndex, DhcpMConstants.DEFAULT_FLOW_PRIORITY,
354                         DhcpMConstants.COOKIE_VM_INGRESS_TABLE, instructions);
355         tx.put(LogicalDatastoreType.CONFIGURATION,
356                 buildServiceId(interfaceName, serviceIndex), serviceInfo, WriteTransaction.CREATE_MISSING_PARENTS);
357     }
358
359     public static void unbindDhcpService(String interfaceName, WriteTransaction tx) {
360         short serviceIndex = ServiceIndex.getIndex(NwConstants.DHCP_SERVICE_NAME, NwConstants.DHCP_SERVICE_INDEX);
361         tx.delete(LogicalDatastoreType.CONFIGURATION,
362                 buildServiceId(interfaceName, serviceIndex));
363     }
364
365     private static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName,
366                                                              short dhcpServicePriority) {
367         return InstanceIdentifier.builder(ServiceBindings.class)
368                 .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
369                 .child(BoundServices.class, new BoundServicesKey(dhcpServicePriority)).build();
370     }
371
372     public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
373                                           BigInteger cookie, List<Instruction> instructions) {
374         StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie)
375                 .setFlowPriority(flowPriority).setInstruction(instructions);
376         return new BoundServicesBuilder().setKey(new BoundServicesKey(servicePriority))
377                 .setServiceName(serviceName).setServicePriority(servicePriority)
378                 .setServiceType(ServiceTypeFlowBased.class)
379                 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
380     }
381
382     @SuppressWarnings("checkstyle:IllegalCatch")
383     protected static void createSubnetDhcpPortData(Port port,
384             BiConsumer<InstanceIdentifier<SubnetToDhcpPort>, SubnetToDhcpPort> consumer) {
385         java.util.Optional<String> ip4Address = getIpV4Address(port);
386         java.util.Optional<String> subnetId = getNeutronSubnetId(port);
387         if (!(ip4Address.isPresent() && subnetId.isPresent())) {
388             return;
389         }
390         LOG.trace("Adding SubnetPortData entry for subnet {}", subnetId.get());
391         InstanceIdentifier<SubnetToDhcpPort> identifier = buildSubnetToDhcpPort(subnetId.get());
392         SubnetToDhcpPort subnetToDhcpPort = getSubnetToDhcpPort(port, subnetId.get(), ip4Address.get());
393         try {
394             LOG.trace("Adding to SubnetToDhcpPort subnet {}  mac {}.", subnetId.get(),
395                     port.getMacAddress().getValue());
396             consumer.accept(identifier, subnetToDhcpPort);
397         } catch (Exception e) {
398             LOG.error("Failure while creating SubnetToDhcpPort map for network {}.", port.getNetworkId(), e);
399         }
400     }
401
402     @SuppressWarnings("checkstyle:IllegalCatch")
403     protected static void removeSubnetDhcpPortData(Port port, Consumer<InstanceIdentifier<SubnetToDhcpPort>> consumer) {
404         String subnetId = port.getDeviceId().substring("OpenDaylight".length() + 1);
405         LOG.trace("Removing NetworkPortData entry for Subnet {}", subnetId);
406         InstanceIdentifier<SubnetToDhcpPort> identifier = buildSubnetToDhcpPort(subnetId);
407         try {
408             consumer.accept(identifier);
409             LOG.trace("Deleted SubnetDhcpPort for Subnet {}", subnetId);
410         } catch (Exception e) {
411             LOG.error("Failure while removing SubnetToDhcpPort for subnet {}.", subnetId, e);
412         }
413
414     }
415
416     static InstanceIdentifier<SubnetToDhcpPort> buildSubnetToDhcpPort(String subnetId) {
417         return InstanceIdentifier.builder(SubnetDhcpPortData.class)
418                 .child(SubnetToDhcpPort.class, new SubnetToDhcpPortKey(subnetId)).build();
419     }
420
421     public static java.util.Optional<SubnetToDhcpPort> getSubnetDhcpPortData(DataBroker broker, String subnetId) {
422         InstanceIdentifier<SubnetToDhcpPort> id = buildSubnetToDhcpPort(subnetId);
423         try {
424             return java.util.Optional
425                     .ofNullable(SingleTransactionDataBroker.syncRead(broker, LogicalDatastoreType.CONFIGURATION, id));
426         } catch (ReadFailedException e) {
427             LOG.warn("Failed to read SubnetToDhcpPort for DS due to error {}", e.getMessage());
428         }
429         return java.util.Optional.empty();
430     }
431
432     static IpAddress convertIntToIp(int ipn) {
433         String[] array = IntStream.of(24, 16, 8, 0) //
434                 .map(x -> ipn >> x & 0xFF).boxed() //
435                 .map(String::valueOf) //
436                 .toArray(String[]::new);
437         return new IpAddress(String.join(".", array).toCharArray());
438     }
439
440     static IpAddress convertLongToIp(long ip) {
441         String[] array = LongStream.of(24, 16, 8, 0) //
442                 .map(x -> ip >> x & 0xFF).boxed() //
443                 .map(String::valueOf) //
444                 .toArray(String[]::new);
445         return new IpAddress(String.join(".", array).toCharArray());
446     }
447
448     static long convertIpToLong(IpAddress ipa) {
449         String[] splitIp = String.valueOf(ipa.getValue()).split("\\.");
450         long result = 0;
451         for (String part : splitIp) {
452             result <<= 8;
453             result |= Integer.parseInt(part);
454         }
455         return result;
456     }
457
458
459     static SubnetToDhcpPort getSubnetToDhcpPort(Port port, String subnetId, String ipAddress) {
460         return new SubnetToDhcpPortBuilder()
461                 .setKey(new SubnetToDhcpPortKey(subnetId))
462                 .setSubnetId(subnetId).setPortName(port.getUuid().getValue())
463                 .setPortMacaddress(port.getMacAddress().getValue()).setPortFixedip(ipAddress).build();
464     }
465
466     static InterfaceInfo getInterfaceInfo(IInterfaceManager interfaceManager, String interfaceName) {
467         return interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName);
468     }
469
470     static BigInteger getDpIdFromInterface(IInterfaceManager interfaceManager, String interfaceName) {
471         return interfaceManager.getDpnForInterface(interfaceName);
472     }
473
474     public static java.util.Optional<String> getIpV4Address(Port port) {
475         if (port.getFixedIps() == null) {
476             return java.util.Optional.empty();
477         }
478         return port.getFixedIps().stream().filter(DhcpServiceUtils::isIpV4AddressAvailable)
479                 .map(v -> v.getIpAddress().getIpv4Address().getValue()).findFirst();
480     }
481
482     public static java.util.Optional<String> getNeutronSubnetId(Port port) {
483         if (port.getFixedIps() == null) {
484             return java.util.Optional.empty();
485         }
486         return port.getFixedIps().stream().filter(DhcpServiceUtils::isIpV4AddressAvailable)
487                 .map(v -> v.getSubnetId().getValue()).findFirst();
488     }
489
490     public static boolean isIpV4AddressAvailable(FixedIps fixedIp) {
491         return fixedIp != null && fixedIp.getIpAddress() != null && fixedIp.getIpAddress().getIpv4Address() != null;
492     }
493
494     public static String getAndUpdateVmMacAddress(DataBroker dataBroker, String interfaceName,
495             DhcpManager dhcpManager) {
496         InstanceIdentifier<InterfaceNameMacAddress> instanceIdentifier =
497                 InstanceIdentifier.builder(InterfaceNameMacAddresses.class)
498                         .child(InterfaceNameMacAddress.class, new InterfaceNameMacAddressKey(interfaceName)).build();
499         Optional<InterfaceNameMacAddress> existingEntry =
500                 MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, instanceIdentifier);
501         if (!existingEntry.isPresent()) {
502             LOG.trace("Entry for interface {} missing in InterfaceNameVmMacAddress map", interfaceName);
503             String vmMacAddress = getNeutronMacAddress(interfaceName, dhcpManager);
504             if (vmMacAddress == null || vmMacAddress.isEmpty()) {
505                 return null;
506             }
507             LOG.trace("Updating InterfaceNameVmMacAddress map with {}, {}", interfaceName,vmMacAddress);
508             InterfaceNameMacAddress interfaceNameMacAddress =
509                     new InterfaceNameMacAddressBuilder()
510                             .setKey(new InterfaceNameMacAddressKey(interfaceName))
511                             .setInterfaceName(interfaceName).setMacAddress(vmMacAddress).build();
512             MDSALDataStoreUtils.asyncUpdate(dataBroker, LogicalDatastoreType.OPERATIONAL, instanceIdentifier,
513                     interfaceNameMacAddress, DEFAULT_CALLBACK);
514             return vmMacAddress;
515         }
516         return existingEntry.get().getMacAddress();
517     }
518
519     private static String getNeutronMacAddress(String interfaceName, DhcpManager dhcpManager) {
520         Port port = dhcpManager.getNeutronPort(interfaceName);
521         if (port != null) {
522             LOG.trace("Port found in neutron. Interface Name {}, port {}", interfaceName, port);
523             return port.getMacAddress().getValue();
524         }
525         return null;
526     }
527
528     public static List<Uuid> getSubnetIdsFromNetworkId(DataBroker broker, Uuid networkId) {
529         InstanceIdentifier id = buildNetworkMapIdentifier(networkId);
530         Optional<NetworkMap> optionalNetworkMap = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
531         if (optionalNetworkMap.isPresent()) {
532             return optionalNetworkMap.get().getSubnetIdList();
533         }
534         return null;
535     }
536
537     static InstanceIdentifier<NetworkMap> buildNetworkMapIdentifier(Uuid networkId) {
538         InstanceIdentifier<NetworkMap> id = InstanceIdentifier.builder(NetworkMaps.class).child(NetworkMap.class, new
539                 NetworkMapKey(networkId)).build();
540         return id;
541     }
542
543     public static boolean isIpv4Subnet(DataBroker broker, Uuid subnetUuid) {
544         final SubnetKey subnetkey = new SubnetKey(subnetUuid);
545         final InstanceIdentifier<Subnet> subnetidentifier = InstanceIdentifier.create(Neutron.class)
546                 .child(Subnets.class).child(Subnet.class, subnetkey);
547         final Optional<Subnet> subnet = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, subnetidentifier);
548         if (subnet.isPresent()) {
549             Class<? extends IpVersionBase> ipVersionBase = subnet.get().getIpVersion();
550             if (ipVersionBase.equals(IpVersionV4.class)) {
551                 return true;
552             }
553         }
554         return false;
555     }
556
557 }
558