2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
9 package org.opendaylight.netvirt.dhcpservice;
11 import static org.opendaylight.controller.md.sal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
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.IntStream;
29 import java.util.stream.LongStream;
30 import javax.annotation.Nonnull;
31 import javax.annotation.Nullable;
32 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
33 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
34 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
35 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
36 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
37 import org.opendaylight.genius.infra.Datastore.Configuration;
38 import org.opendaylight.genius.infra.Datastore.Operational;
39 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
40 import org.opendaylight.genius.infra.TypedWriteTransaction;
41 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
42 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
43 import org.opendaylight.genius.mdsalutil.ActionInfo;
44 import org.opendaylight.genius.mdsalutil.FlowEntity;
45 import org.opendaylight.genius.mdsalutil.InstructionInfo;
46 import org.opendaylight.genius.mdsalutil.MDSALUtil;
47 import org.opendaylight.genius.mdsalutil.MatchInfo;
48 import org.opendaylight.genius.mdsalutil.NWUtil;
49 import org.opendaylight.genius.mdsalutil.NwConstants;
50 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
51 import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
52 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
53 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
54 import org.opendaylight.genius.mdsalutil.matches.MatchArpOp;
55 import org.opendaylight.genius.mdsalutil.matches.MatchArpTpa;
56 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetSource;
57 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
58 import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
59 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
60 import org.opendaylight.genius.mdsalutil.matches.MatchUdpDestinationPort;
61 import org.opendaylight.genius.mdsalutil.matches.MatchUdpSourcePort;
62 import org.opendaylight.genius.utils.ServiceIndex;
63 import org.opendaylight.netvirt.dhcpservice.api.DhcpMConstants;
64 import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
65 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
66 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
67 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
68 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
69 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
70 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
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.StypeOpenflow;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
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.neutronvpn.rev150602.NetworkMaps;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMap;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMapKey;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionBase;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.IpVersionV4;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVxlan;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.NetworkKey;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
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.slf4j.Logger;
115 import org.slf4j.LoggerFactory;
117 public final class DhcpServiceUtils {
119 private static final Logger LOG = LoggerFactory.getLogger(DhcpServiceUtils.class);
120 private static List<BigInteger> connectedDpnIds = new CopyOnWriteArrayList<>();
122 private DhcpServiceUtils() { }
124 public static void setupDhcpFlowEntry(@Nullable BigInteger dpId, short tableId, @Nullable String vmMacAddress,
126 IMdsalApiManager mdsalUtil, DhcpServiceCounters dhcpServiceCounters,
127 TypedReadWriteTransaction<Configuration> tx)
128 throws ExecutionException, InterruptedException {
129 if (dpId == null || dpId.equals(DhcpMConstants.INVALID_DPID) || vmMacAddress == null) {
132 List<MatchInfo> matches = getDhcpMatch(vmMacAddress);
133 List<InstructionInfo> instructions = new ArrayList<>();
134 List<ActionInfo> actionsInfos = new ArrayList<>();
136 // Punt to controller
137 actionsInfos.add(new ActionPuntToController());
138 instructions.add(new InstructionApplyActions(actionsInfos));
139 if (addOrRemove == NwConstants.DEL_FLOW) {
140 LOG.trace("Removing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
141 dhcpServiceCounters.removeDhcpFlow();
142 mdsalUtil.removeFlow(tx, dpId, getDhcpFlowRef(dpId, tableId, vmMacAddress), tableId);
144 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
145 getDhcpFlowRef(dpId, tableId, vmMacAddress), DhcpMConstants.DEFAULT_DHCP_FLOW_PRIORITY,
146 "DHCP", 0, 0, DhcpMConstants.COOKIE_DHCP_BASE, matches, instructions);
147 LOG.trace("Installing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
148 dhcpServiceCounters.installDhcpFlow();
149 mdsalUtil.addFlow(tx, flowEntity);
153 private static String getDhcpFlowRef(BigInteger dpId, long tableId, String vmMacAddress) {
154 return new StringBuffer().append(DhcpMConstants.FLOWID_PREFIX)
155 .append(dpId).append(NwConstants.FLOWID_SEPARATOR)
156 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
157 .append(vmMacAddress).toString();
160 private static String getDhcpArpFlowRef(BigInteger dpId, long tableId, long lportTag, String ipAddress) {
161 return new StringBuffer().append(DhcpMConstants.FLOWID_PREFIX)
162 .append(dpId).append(NwConstants.FLOWID_SEPARATOR)
163 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
164 .append(lportTag).append(NwConstants.FLOWID_SEPARATOR)
165 .append(ipAddress).toString();
168 public static void setupDhcpDropAction(BigInteger dpId, short tableId, String vmMacAddress, int addOrRemove,
169 IMdsalApiManager mdsalUtil, DhcpServiceCounters dhcpServiceCounters,
170 TypedReadWriteTransaction<Configuration> tx)
171 throws ExecutionException, InterruptedException {
172 if (dpId == null || dpId.equals(DhcpMConstants.INVALID_DPID) || vmMacAddress == null) {
175 List<MatchInfo> matches = getDhcpMatch(vmMacAddress);
177 List<ActionInfo> actionsInfos = new ArrayList<>();
178 List<InstructionInfo> instructions = new ArrayList<>();
179 instructions.add(new InstructionApplyActions(actionsInfos));
181 actionsInfos.add(new ActionDrop());
182 if (addOrRemove == NwConstants.DEL_FLOW) {
183 LOG.trace("Removing DHCP Drop Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
184 dhcpServiceCounters.removeDhcpDropFlow();
185 mdsalUtil.removeFlow(tx, dpId, getDhcpFlowRef(dpId, tableId, vmMacAddress), tableId);
187 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
188 getDhcpFlowRef(dpId, tableId, vmMacAddress), DhcpMConstants.DEFAULT_DHCP_FLOW_PRIORITY,
189 "DHCP", 0, 0, DhcpMConstants.COOKIE_DHCP_BASE, matches, instructions);
190 LOG.trace("Installing DHCP Drop Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
191 dhcpServiceCounters.installDhcpDropFlow();
192 mdsalUtil.addFlow(tx, flowEntity);
196 public static void setupDhcpArpRequest(BigInteger dpId, short tableId, BigInteger vni, String dhcpIpAddress,
197 int lportTag, @Nullable Long elanTag, boolean add,
198 IMdsalApiManager mdsalUtil, TypedReadWriteTransaction<Configuration> tx)
199 throws ExecutionException, InterruptedException {
200 List<MatchInfo> matches = getDhcpArpMatch(vni, dhcpIpAddress);
202 Flow flow = MDSALUtil.buildFlowNew(tableId, getDhcpArpFlowRef(dpId, tableId, lportTag, dhcpIpAddress),
203 DhcpMConstants.DEFAULT_DHCP_ARP_FLOW_PRIORITY, "DHCPArp", 0, 0,
204 generateDhcpArpCookie(lportTag, dhcpIpAddress), matches, null);
205 LOG.trace("Removing DHCP ARP Flow DpId {}, DHCP Port IpAddress {}", dpId, dhcpIpAddress);
206 mdsalUtil.removeFlow(tx, dpId, flow);
208 Flow flow = MDSALUtil.buildFlowNew(tableId, getDhcpArpFlowRef(dpId, tableId, lportTag, dhcpIpAddress),
209 DhcpMConstants.DEFAULT_DHCP_ARP_FLOW_PRIORITY, "DHCPArp", 0, 0,
210 generateDhcpArpCookie(lportTag, dhcpIpAddress), matches,
211 getDhcpArpInstructions(elanTag, lportTag));
212 LOG.trace("Adding DHCP ARP Flow DpId {}, DHCPPort IpAddress {}", dpId, dhcpIpAddress);
213 mdsalUtil.addFlow(tx, dpId, flow);
217 public static List<MatchInfo> getDhcpMatch() {
218 List<MatchInfo> matches = new ArrayList<>();
219 matches.add(MatchEthernetType.IPV4);
220 matches.add(MatchIpProtocol.UDP);
221 matches.add(new MatchUdpSourcePort(DhcpMConstants.DHCP_CLIENT_PORT));
222 matches.add(new MatchUdpDestinationPort(DhcpMConstants.DHCP_SERVER_PORT));
226 public static List<MatchInfo> getDhcpMatch(String vmMacAddress) {
227 List<MatchInfo> matches = getDhcpMatch();
228 matches.add(new MatchEthernetSource(new MacAddress(vmMacAddress)));
232 private static List<MatchInfo> getDhcpArpMatch(BigInteger vni, String ipAddress) {
233 return Arrays.asList(MatchEthernetType.ARP, MatchArpOp.REQUEST, new MatchTunnelId(vni),
234 new MatchArpTpa(ipAddress, "32"));
237 private static List<Instruction> getDhcpArpInstructions(Long elanTag, int lportTag) {
238 List<Instruction> mkInstructions = new ArrayList<>();
239 int instructionKey = 0;
240 mkInstructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(
241 ElanHelper.getElanMetadataLabel(elanTag, lportTag), ElanHelper.getElanMetadataMask(),
243 mkInstructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ARP_RESPONDER_TABLE,
245 return mkInstructions;
248 private static BigInteger generateDhcpArpCookie(int lportTag, String ipAddress) {
250 BigInteger cookie = NwConstants.TUNNEL_TABLE_COOKIE.add(BigInteger.valueOf(255))
251 .add(BigInteger.valueOf(NWUtil.convertInetAddressToLong(InetAddress.getByName(ipAddress))));
252 return cookie.add(BigInteger.valueOf(lportTag));
253 } catch (UnknownHostException e) {
254 return NwConstants.TUNNEL_TABLE_COOKIE.add(BigInteger.valueOf(lportTag));
258 public static List<BigInteger> getListOfDpns(DataBroker broker) {
259 if (!connectedDpnIds.isEmpty()) {
260 return connectedDpnIds;
262 return extractDpnsFromNodes(MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
263 InstanceIdentifier.builder(Nodes.class).build()));
267 public static List<BigInteger> getListOfDpns(ReadTransaction tx) throws ReadFailedException {
268 if (!connectedDpnIds.isEmpty()) {
269 return connectedDpnIds;
271 return extractDpnsFromNodes(tx.read(LogicalDatastoreType.OPERATIONAL,
272 InstanceIdentifier.builder(Nodes.class).build()).checkedGet());
276 private static List<BigInteger> extractDpnsFromNodes(Optional<Nodes> optionalNodes) {
277 return optionalNodes.toJavaUtil().map(
278 nodes -> nodes.nonnullNode().stream().map(Node::getId).filter(Objects::nonNull).map(
279 MDSALUtil::getDpnIdFromNodeName).collect(
280 Collectors.toList())).orElse(Collections.emptyList());
284 public static List<BigInteger> getDpnsForElan(String elanInstanceName, DataBroker broker) {
285 List<BigInteger> elanDpns = new LinkedList<>();
286 InstanceIdentifier<ElanDpnInterfacesList> elanDpnInstanceIdentifier =
287 InstanceIdentifier.builder(ElanDpnInterfaces.class)
288 .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName)).build();
289 Optional<ElanDpnInterfacesList> elanDpnOptional =
290 MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInstanceIdentifier);
291 if (elanDpnOptional.isPresent()) {
292 List<DpnInterfaces> dpns = elanDpnOptional.get().nonnullDpnInterfaces();
293 for (DpnInterfaces dpnInterfaces : dpns) {
294 elanDpns.add(dpnInterfaces.getDpId());
301 public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
302 .state.Interface getInterfaceFromOperationalDS(String interfaceName, DataBroker dataBroker) {
303 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
304 .state.InterfaceKey interfaceKey =
305 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
306 .state.InterfaceKey(interfaceName);
307 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
308 .interfaces.state.Interface> interfaceId = InstanceIdentifier.builder(InterfacesState.class)
309 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
310 .interfaces.state.Interface.class, interfaceKey).build();
311 return MDSALUtil.read(LogicalDatastoreType.OPERATIONAL, interfaceId, dataBroker).orNull();
316 public static String getSegmentationId(Uuid networkId, DataBroker broker) {
317 InstanceIdentifier<Network> inst = InstanceIdentifier.create(Neutron.class)
318 .child(Networks.class).child(Network.class, new NetworkKey(networkId));
319 Optional<Network> optionalNetwork = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, inst);
320 if (!optionalNetwork.isPresent()) {
323 Network network = optionalNetwork.get();
324 String segmentationId = NeutronUtils.getSegmentationIdFromNeutronNetwork(network, NetworkTypeVxlan.class);
325 return segmentationId;
328 public static String getNodeIdFromDpnId(BigInteger dpnId) {
329 return MDSALUtil.NODE_PREFIX + MDSALUtil.SEPARATOR + dpnId.toString();
333 public static String getTrunkPortMacAddress(String parentRefName,
335 InstanceIdentifier<Port> portInstanceIdentifier =
336 InstanceIdentifier.create(Neutron.class).child(Ports.class).child(Port.class);
337 Optional<Port> trunkPort = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, portInstanceIdentifier);
338 if (!trunkPort.isPresent()) {
339 LOG.warn("Trunk port {} not available for sub-port", parentRefName);
342 return trunkPort.get().getMacAddress().getValue();
345 public static String getJobKey(String interfaceName) {
346 return new StringBuilder().append(DhcpMConstants.DHCP_JOB_KEY_PREFIX).append(interfaceName).toString();
349 public static void bindDhcpService(String interfaceName, short tableId, TypedWriteTransaction<Configuration> tx) {
350 int instructionKey = 0;
351 List<Instruction> instructions = new ArrayList<>();
352 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(tableId, ++instructionKey));
353 short serviceIndex = ServiceIndex.getIndex(NwConstants.DHCP_SERVICE_NAME, NwConstants.DHCP_SERVICE_INDEX);
356 getBoundServices(String.format("%s.%s", "dhcp", interfaceName),
357 serviceIndex, DhcpMConstants.DEFAULT_FLOW_PRIORITY,
358 DhcpMConstants.COOKIE_VM_INGRESS_TABLE, instructions);
359 tx.put(buildServiceId(interfaceName, serviceIndex), serviceInfo, CREATE_MISSING_PARENTS);
362 public static void unbindDhcpService(String interfaceName, TypedWriteTransaction<Configuration> tx) {
363 short serviceIndex = ServiceIndex.getIndex(NwConstants.DHCP_SERVICE_NAME, NwConstants.DHCP_SERVICE_INDEX);
364 tx.delete(buildServiceId(interfaceName, serviceIndex));
367 private static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName,
368 short dhcpServicePriority) {
369 return InstanceIdentifier.builder(ServiceBindings.class)
370 .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
371 .child(BoundServices.class, new BoundServicesKey(dhcpServicePriority)).build();
374 public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
375 BigInteger cookie, List<Instruction> instructions) {
376 StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie)
377 .setFlowPriority(flowPriority).setInstruction(instructions);
378 return new BoundServicesBuilder().withKey(new BoundServicesKey(servicePriority))
379 .setServiceName(serviceName).setServicePriority(servicePriority)
380 .setServiceType(ServiceTypeFlowBased.class)
381 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
384 @SuppressWarnings("checkstyle:IllegalCatch")
385 protected static void createSubnetDhcpPortData(Port port,
386 BiConsumer<InstanceIdentifier<SubnetToDhcpPort>, SubnetToDhcpPort> consumer) {
387 java.util.Optional<String> ip4Address = getIpV4Address(port);
388 java.util.Optional<String> subnetId = getNeutronSubnetId(port);
389 if (!(ip4Address.isPresent() && subnetId.isPresent())) {
392 LOG.trace("Adding SubnetPortData entry for subnet {}", subnetId.get());
393 InstanceIdentifier<SubnetToDhcpPort> identifier = buildSubnetToDhcpPort(subnetId.get());
394 SubnetToDhcpPort subnetToDhcpPort = getSubnetToDhcpPort(port, subnetId.get(), ip4Address.get());
396 LOG.trace("Adding to SubnetToDhcpPort subnet {} mac {}.", subnetId.get(),
397 port.getMacAddress().getValue());
398 consumer.accept(identifier, subnetToDhcpPort);
399 } catch (Exception e) {
400 LOG.error("Failure while creating SubnetToDhcpPort map for network {}.", port.getNetworkId(), e);
404 @SuppressWarnings("checkstyle:IllegalCatch")
405 protected static void removeSubnetDhcpPortData(Port port, Consumer<InstanceIdentifier<SubnetToDhcpPort>> consumer) {
406 String subnetId = port.getDeviceId().substring("OpenDaylight".length() + 1);
407 LOG.trace("Removing NetworkPortData entry for Subnet {}", subnetId);
408 InstanceIdentifier<SubnetToDhcpPort> identifier = buildSubnetToDhcpPort(subnetId);
410 consumer.accept(identifier);
411 LOG.trace("Deleted SubnetDhcpPort for Subnet {}", subnetId);
412 } catch (Exception e) {
413 LOG.error("Failure while removing SubnetToDhcpPort for subnet {}.", subnetId, e);
418 static InstanceIdentifier<SubnetToDhcpPort> buildSubnetToDhcpPort(String subnetId) {
419 return InstanceIdentifier.builder(SubnetDhcpPortData.class)
420 .child(SubnetToDhcpPort.class, new SubnetToDhcpPortKey(subnetId)).build();
423 public static java.util.Optional<SubnetToDhcpPort> getSubnetDhcpPortData(DataBroker broker, String subnetId) {
424 InstanceIdentifier<SubnetToDhcpPort> id = buildSubnetToDhcpPort(subnetId);
426 return java.util.Optional
427 .ofNullable(SingleTransactionDataBroker.syncRead(broker, LogicalDatastoreType.CONFIGURATION, id));
428 } catch (ReadFailedException e) {
429 LOG.warn("Failed to read SubnetToDhcpPort for DS due to error {}", e.getMessage());
431 return java.util.Optional.empty();
434 static IpAddress convertIntToIp(int ipn) {
435 String[] array = IntStream.of(24, 16, 8, 0) //
436 .map(x -> ipn >> x & 0xFF).boxed() //
437 .map(String::valueOf) //
438 .toArray(String[]::new);
439 return IpAddressBuilder.getDefaultInstance(String.join(".", array));
442 static IpAddress convertLongToIp(long ip) {
443 String[] array = LongStream.of(24, 16, 8, 0) //
444 .map(x -> ip >> x & 0xFF).boxed() //
445 .map(String::valueOf) //
446 .toArray(String[]::new);
447 return IpAddressBuilder.getDefaultInstance(String.join(".", array));
450 static long convertIpToLong(IpAddress ipa) {
451 String[] splitIp = ipa.stringValue().split("\\.");
453 for (String part : splitIp) {
455 result |= Integer.parseInt(part);
461 static SubnetToDhcpPort getSubnetToDhcpPort(Port port, String subnetId, String ipAddress) {
462 return new SubnetToDhcpPortBuilder()
463 .withKey(new SubnetToDhcpPortKey(subnetId))
464 .setSubnetId(subnetId).setPortName(port.getUuid().getValue())
465 .setPortMacaddress(port.getMacAddress().getValue()).setPortFixedip(ipAddress).build();
468 static InterfaceInfo getInterfaceInfo(IInterfaceManager interfaceManager, String interfaceName) {
469 return interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName);
472 static BigInteger getDpIdFromInterface(IInterfaceManager interfaceManager, String interfaceName) {
473 return interfaceManager.getDpnForInterface(interfaceName);
476 public static java.util.Optional<String> getIpV4Address(Port port) {
477 if (port.getFixedIps() == null) {
478 return java.util.Optional.empty();
480 return port.getFixedIps().stream().filter(DhcpServiceUtils::isIpV4AddressAvailable)
481 .map(v -> v.getIpAddress().getIpv4Address().getValue()).findFirst();
484 public static java.util.Optional<String> getNeutronSubnetId(Port port) {
485 if (port.getFixedIps() == null) {
486 return java.util.Optional.empty();
488 return port.getFixedIps().stream().filter(DhcpServiceUtils::isIpV4AddressAvailable)
489 .map(v -> v.getSubnetId().getValue()).findFirst();
492 public static boolean isIpV4AddressAvailable(FixedIps fixedIp) {
493 return fixedIp != null && fixedIp.getIpAddress() != null && fixedIp.getIpAddress().getIpv4Address() != null;
497 public static String getAndUpdateVmMacAddress(TypedReadWriteTransaction<Operational> tx, String interfaceName,
498 DhcpManager dhcpManager) throws ExecutionException, InterruptedException {
499 InstanceIdentifier<InterfaceNameMacAddress> instanceIdentifier =
500 InstanceIdentifier.builder(InterfaceNameMacAddresses.class)
501 .child(InterfaceNameMacAddress.class, new InterfaceNameMacAddressKey(interfaceName)).build();
502 Optional<InterfaceNameMacAddress> existingEntry = tx.read(instanceIdentifier).get();
503 if (!existingEntry.isPresent()) {
504 LOG.trace("Entry for interface {} missing in InterfaceNameVmMacAddress map", interfaceName);
505 String vmMacAddress = getNeutronMacAddress(interfaceName, dhcpManager);
506 if (vmMacAddress == null || vmMacAddress.isEmpty()) {
509 LOG.trace("Updating InterfaceNameVmMacAddress map with {}, {}", interfaceName,vmMacAddress);
510 InterfaceNameMacAddress interfaceNameMacAddress =
511 new InterfaceNameMacAddressBuilder()
512 .withKey(new InterfaceNameMacAddressKey(interfaceName))
513 .setInterfaceName(interfaceName).setMacAddress(vmMacAddress).build();
514 tx.merge(instanceIdentifier, interfaceNameMacAddress, CREATE_MISSING_PARENTS);
517 return existingEntry.get().getMacAddress();
521 private static String getNeutronMacAddress(String interfaceName, DhcpManager dhcpManager) {
522 Port port = dhcpManager.getNeutronPort(interfaceName);
524 LOG.trace("Port found in neutron. Interface Name {}, port {}", interfaceName, port);
525 return port.getMacAddress().getValue();
531 public static List<Uuid> getSubnetIdsFromNetworkId(DataBroker broker, Uuid networkId) {
532 InstanceIdentifier id = buildNetworkMapIdentifier(networkId);
533 Optional<NetworkMap> optionalNetworkMap = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
534 if (optionalNetworkMap.isPresent()) {
535 @Nullable List<Uuid> subnetIdList = optionalNetworkMap.get().getSubnetIdList();
536 if (subnetIdList != null) {
540 return Collections.emptyList();
543 static InstanceIdentifier<NetworkMap> buildNetworkMapIdentifier(Uuid networkId) {
544 return InstanceIdentifier.builder(NetworkMaps.class).child(NetworkMap.class,
545 new NetworkMapKey(networkId)).build();
548 public static boolean isIpv4Subnet(DataBroker broker, Uuid subnetUuid) {
549 final SubnetKey subnetkey = new SubnetKey(subnetUuid);
550 final InstanceIdentifier<Subnet> subnetidentifier = InstanceIdentifier.create(Neutron.class)
551 .child(Subnets.class).child(Subnet.class, subnetkey);
552 final Optional<Subnet> subnet = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, subnetidentifier);
553 if (subnet.isPresent()) {
554 Class<? extends IpVersionBase> ipVersionBase = subnet.get().getIpVersion();
555 return IpVersionV4.class.equals(ipVersionBase);
560 public static void addToDpnIdCache(BigInteger dpnId) {
561 if (!connectedDpnIds.contains(dpnId)) {
562 connectedDpnIds.add(dpnId);
566 public static void removeFromDpnIdCache(BigInteger dpnId) {
567 connectedDpnIds.remove(dpnId);