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