NETVIRT-1630 migrate to md-sal APIs
[netvirt.git] / dhcpservice / impl / src / main / java / org / opendaylight / netvirt / dhcpservice / DhcpUCastMacListener.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 package org.opendaylight.netvirt.dhcpservice;
9
10 import java.util.Optional;
11 import java.util.concurrent.ExecutionException;
12 import javax.annotation.PreDestroy;
13 import javax.inject.Inject;
14 import javax.inject.Singleton;
15 import org.apache.commons.lang3.tuple.ImmutablePair;
16 import org.apache.commons.lang3.tuple.Pair;
17 import org.eclipse.jdt.annotation.Nullable;
18 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
19 import org.opendaylight.infrautils.utils.concurrent.Executors;
20 import org.opendaylight.mdsal.binding.api.DataBroker;
21 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
22 import org.opendaylight.netvirt.dhcpservice.api.DhcpMConstants;
23 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
24 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
25 import org.opendaylight.serviceutils.tools.listener.AbstractClusteredAsyncDataTreeChangeListener;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dhcpservice.config.rev150710.DhcpserviceConfig;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalUcastMacs;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
33 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
34 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
35 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
36 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.opendaylight.yangtools.yang.common.Uint64;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 @Singleton
43 public class DhcpUCastMacListener extends AbstractClusteredAsyncDataTreeChangeListener<LocalUcastMacs> {
44
45     private static final Logger LOG = LoggerFactory.getLogger(DhcpUCastMacListener.class);
46     private final DhcpExternalTunnelManager dhcpExternalTunnelManager;
47     private final DhcpManager dhcpManager;
48     private final DataBroker broker;
49     private final DhcpserviceConfig config;
50
51     @Inject
52     public DhcpUCastMacListener(final DhcpManager dhcpManager, final DhcpExternalTunnelManager dhcpExtTunnelMgr,
53                                 final DataBroker dataBroker, final DhcpserviceConfig config) {
54         super(dataBroker, LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(NetworkTopology.class)
55                 .child(Topology.class).child(Node.class).augmentation(HwvtepGlobalAugmentation.class)
56                 .child(LocalUcastMacs.class),
57                 Executors.newListeningSingleThreadExecutor("DhcpUCastMacListener", LOG));
58         this.broker = dataBroker;
59         this.dhcpExternalTunnelManager = dhcpExtTunnelMgr;
60         this.dhcpManager = dhcpManager;
61         this.config = config;
62         init();
63     }
64
65     public void init() {
66         if (config.isControllerDhcpEnabled()) {
67             LOG.info("{} init", getClass().getSimpleName());
68         }
69     }
70
71     @Override
72     @PreDestroy
73     public void close() {
74         super.close();
75         Executors.shutdownAndAwaitTermination(getExecutorService());
76         LOG.info("DhcpUCastMacListener Closed");
77     }
78
79     @Override
80     public void remove(InstanceIdentifier<LocalUcastMacs> identifier,
81             LocalUcastMacs del) {
82         if (!config.isControllerDhcpEnabled()) {
83             return;
84         }
85         // Flow removal for table 18 is handled in Neutron Port delete.
86         //remove the new CR-DHCP
87         NodeId torNodeId = identifier.firstKeyOf(Node.class).getNodeId();
88         LogicalSwitches logicalSwitch = getLogicalSwitches(del);
89         if (null == logicalSwitch) {
90             LOG.error("DhcpUCastMacListener remove :Logical Switch ref doesn't have data");
91             return;
92         }
93         String elanInstanceName = logicalSwitch.getHwvtepNodeName().getValue();
94         L2GatewayDevice device = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanInstanceName, torNodeId.getValue());
95         if (device == null) {
96             LOG.error("Logical Switch Device with name {} is not present in L2GWCONN cache", elanInstanceName);
97             return;
98         }
99         IpAddress tunnelIp = device.getTunnelIp();
100         Pair<IpAddress, String> tunnelIpElanName = new ImmutablePair<>(tunnelIp, elanInstanceName);
101         dhcpExternalTunnelManager.removeFromAvailableCache(tunnelIpElanName);
102     }
103
104     @Override
105     public void update(InstanceIdentifier<LocalUcastMacs> identifier,
106             LocalUcastMacs original, LocalUcastMacs update) {
107         // TODO Auto-generated method stub
108
109     }
110
111     @Override
112     public void add(InstanceIdentifier<LocalUcastMacs> identifier,
113             LocalUcastMacs add) {
114         if (!config.isControllerDhcpEnabled()) {
115             return;
116         }
117         NodeId torNodeId = identifier.firstKeyOf(Node.class).getNodeId();
118         InstanceIdentifier<LogicalSwitches> logicalSwitchRef =
119                 (InstanceIdentifier<LogicalSwitches>) add.getLogicalSwitchRef().getValue();
120         Optional<LogicalSwitches> logicalSwitchOptional;
121         try {
122             logicalSwitchOptional = SingleTransactionDataBroker.syncReadOptional(broker,
123                     LogicalDatastoreType.OPERATIONAL, logicalSwitchRef);
124         } catch (ExecutionException | InterruptedException e) {
125             LOG.error("add: Exception while reading LogicalSwitches DS for the TOR Node ID {}", torNodeId, e);
126             return;
127         }
128         if (!logicalSwitchOptional.isPresent()) {
129             LOG.error("Logical Switch ref doesn't have data {}", logicalSwitchRef);
130             return;
131         }
132         LogicalSwitches logicalSwitch = logicalSwitchOptional.get();
133         String elanInstanceName = logicalSwitch.getHwvtepNodeName().getValue();
134         String macAddress = add.getMacEntryKey().getValue();
135         Uint64 vni = Uint64.valueOf(logicalSwitch.getTunnelKey());
136         Port port = dhcpExternalTunnelManager.readVniMacToPortCache(vni, macAddress);
137         if (port == null) {
138             LOG.trace("No neutron port created for macAddress {}, tunnelKey {}", macAddress, vni);
139             return;
140         }
141         L2GatewayDevice device = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanInstanceName, torNodeId.getValue());
142         if (device == null) {
143             LOG.error("Logical Switch Device with name {} is not present in L2GWCONN cache", elanInstanceName);
144             return;
145         }
146         IpAddress tunnelIp = device.getTunnelIp();
147         Subnet subnet = dhcpManager.getNeutronSubnet(port);
148         if (null != subnet && !subnet.isEnableDhcp()) {
149             dhcpExternalTunnelManager.updateExistingVMTunnelIPCache(tunnelIp, elanInstanceName, macAddress);
150             LOG.warn("DhcpUCastMacListener add: flag for the subnetId {} is False so Table 18 entries are not added",
151                      subnet.getUuid());
152             return;
153         }
154         Uint64 designatedDpnId =
155                 dhcpExternalTunnelManager.readDesignatedSwitchesForExternalTunnel(tunnelIp, elanInstanceName);
156         if (designatedDpnId == null || designatedDpnId.equals(DhcpMConstants.INVALID_DPID)) {
157             LOG.trace("Unable to install flows for macAddress {}. TunnelIp {}, elanInstanceName {}, designatedDpn {} ",
158                     macAddress, tunnelIp, elanInstanceName, designatedDpnId);
159             dhcpExternalTunnelManager.updateLocalCache(tunnelIp, elanInstanceName, macAddress);
160             return;
161         }
162         dhcpExternalTunnelManager.installDhcpFlowsForVms(tunnelIp, elanInstanceName,
163                 DhcpServiceUtils.getListOfDpns(broker), designatedDpnId, macAddress);
164     }
165
166     @Nullable
167     private LogicalSwitches getLogicalSwitches(LocalUcastMacs ucastMacs) {
168         InstanceIdentifier<LogicalSwitches> logicalSwitchRef =
169                 (InstanceIdentifier<LogicalSwitches>)ucastMacs.getLogicalSwitchRef().getValue();
170         try {
171             return SingleTransactionDataBroker.syncReadOptional(broker, LogicalDatastoreType.OPERATIONAL,
172                     logicalSwitchRef).orElse(null);
173         } catch (ExecutionException | InterruptedException e) {
174             LOG.error("getLogicalSwitches: Exception while reading LogicalSwitches DS for ucastMacs {}", ucastMacs, e);
175             return null;
176         }
177     }
178 }