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