afd80169b78332cd7ab0b9e0e8ecb9dde467f121
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / iplearn / IpMonitoringHandler.java
1 /*
2  * Copyright (c) 2015 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.vpnmanager.iplearn;
9
10 import java.net.InetAddress;
11 import java.net.UnknownHostException;
12 import java.util.Optional;
13 import javax.annotation.PreDestroy;
14 import javax.inject.Inject;
15 import javax.inject.Singleton;
16 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
17 import org.opendaylight.genius.mdsalutil.NWUtil;
18 import org.opendaylight.genius.utils.clustering.EntityOwnershipUtils;
19 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
20 import org.opendaylight.infrautils.utils.concurrent.Executors;
21 import org.opendaylight.mdsal.binding.api.DataBroker;
22 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
23 import org.opendaylight.mdsal.eos.binding.api.Entity;
24 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipCandidateRegistration;
25 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService;
26 import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
27 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
28 import org.opendaylight.netvirt.vpnmanager.VpnConstants;
29 import org.opendaylight.netvirt.vpnmanager.VpnUtil;
30 import org.opendaylight.netvirt.vpnmanager.iplearn.model.MacEntry;
31 import org.opendaylight.serviceutils.tools.listener.AbstractClusteredAsyncDataTreeChangeListener;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.AlivenessMonitorService;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortData;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
36 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
37 import org.opendaylight.yangtools.yang.common.Uint32;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 @Singleton
42 public class IpMonitoringHandler extends AbstractClusteredAsyncDataTreeChangeListener<LearntVpnVipToPort> {
43     private static final Logger LOG = LoggerFactory.getLogger(IpMonitoringHandler.class);
44     private final DataBroker dataBroker;
45     private final AlivenessMonitorService alivenessManager;
46     private final AlivenessMonitorUtils alivenessMonitorUtils;
47     private final INeutronVpnManager neutronVpnService;
48     private final IInterfaceManager interfaceManager;
49     private final EntityOwnershipUtils entityOwnershipUtils;
50     private final JobCoordinator jobCoordinator;
51     private final VpnUtil vpnUtil;
52
53     private Optional<Uint32> arpMonitorProfileId = Optional.empty();
54     private Optional<Uint32> ipv6NdMonitorProfileId = Optional.empty();
55     private EntityOwnershipCandidateRegistration candidateRegistration;
56
57     @Inject
58     public IpMonitoringHandler(final DataBroker dataBroker, AlivenessMonitorService alivenessManager,
59             INeutronVpnManager neutronVpnService, IInterfaceManager interfaceManager,
60             EntityOwnershipService entityOwnershipService, JobCoordinator jobCoordinator,
61             AlivenessMonitorUtils alivenessMonitorUtils, VpnUtil vpnUtil) {
62         super(dataBroker, LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(LearntVpnVipToPortData.class)
63                 .child(LearntVpnVipToPort.class),
64                 Executors.newListeningSingleThreadExecutor("IpMonitoringHandler", LOG));
65         this.dataBroker = dataBroker;
66         this.alivenessManager = alivenessManager;
67         this.neutronVpnService = neutronVpnService;
68         this.interfaceManager = interfaceManager;
69         this.entityOwnershipUtils = new EntityOwnershipUtils(entityOwnershipService);
70         this.jobCoordinator = jobCoordinator;
71         this.alivenessMonitorUtils = alivenessMonitorUtils;
72         this.vpnUtil = vpnUtil;
73         start();
74     }
75
76     public void start() {
77         LOG.info("{} start", getClass().getSimpleName());
78         this.arpMonitorProfileId = alivenessMonitorUtils.allocateArpMonitorProfile();
79         this.ipv6NdMonitorProfileId = alivenessMonitorUtils.allocateIpv6NaMonitorProfile();
80         if (this.arpMonitorProfileId == null || this.ipv6NdMonitorProfileId == null) {
81             LOG.error("Error while allocating ARP and IPv6 ND Profile Ids: ARP={}, IPv6ND={}", arpMonitorProfileId,
82                     ipv6NdMonitorProfileId);
83         }
84
85         try {
86             candidateRegistration = entityOwnershipUtils.getEntityOwnershipService().registerCandidate(
87                     new Entity(VpnConstants.IP_MONITORING_ENTITY, VpnConstants.IP_MONITORING_ENTITY));
88         } catch (CandidateAlreadyRegisteredException e) {
89             LOG.error("failed to register the entity {}", VpnConstants.IP_MONITORING_ENTITY);
90         }
91     }
92
93     @Override
94     @PreDestroy
95     public void close() {
96         super.close();
97
98         if (candidateRegistration != null) {
99             candidateRegistration.close();
100         }
101         Executors.shutdownAndAwaitTermination(getExecutorService());
102     }
103
104     // TODO Clean up the exception handling
105     @SuppressWarnings("checkstyle:IllegalCatch")
106     @Override
107     public void update(InstanceIdentifier<LearntVpnVipToPort> id, LearntVpnVipToPort value,
108             LearntVpnVipToPort dataObjectModificationAfter) {
109         runOnlyInOwnerNode("IpMonitoringHandler: update event", () -> {
110             try {
111                 if (value.getMacAddress() == null || dataObjectModificationAfter.getMacAddress() == null) {
112                     LOG.warn("The mac address received is null for LearntVpnVipIpToPort {}, ignoring the DTCN",
113                             dataObjectModificationAfter);
114                     return;
115                 }
116                 remove(id, value);
117                 add(id, dataObjectModificationAfter);
118             } catch (Exception e) {
119                 LOG.error("Error in handling update to LearntVpnVipIpToPort for vpnName {} and IP Address {}",
120                         value.getVpnName(), value.getPortFixedip(), e);
121             }
122         });
123     }
124
125     @Override
126     public void add(InstanceIdentifier<LearntVpnVipToPort> identifier, LearntVpnVipToPort value) {
127         runOnlyInOwnerNode("IpMonitoringHandler: add event", () -> {
128             try {
129                 InetAddress srcInetAddr = InetAddress.getByName(value.getPortFixedip());
130                 if (value.getMacAddress() == null) {
131                     LOG.warn("The mac address received is null for VpnPortipToPort {}, ignoring the DTCN", value);
132                     return;
133                 }
134                 MacAddress srcMacAddress = MacAddress.getDefaultInstance(value.getMacAddress());
135                 String vpnName =  value.getVpnName();
136                 MacEntry macEntry = new MacEntry(vpnName, srcMacAddress, srcInetAddr, value.getPortName(),
137                         value.getCreationTime());
138
139                 Optional<Uint32> monitorProfileId = getMonitorProfileId(value.getPortFixedip());
140                 if (monitorProfileId.isPresent()) {
141                     jobCoordinator.enqueueJob(VpnUtil.buildIpMonitorJobKey(srcInetAddr.toString(), vpnName),
142                             new IpMonitorStartTask(macEntry, monitorProfileId.get().toJava(), alivenessMonitorUtils));
143                 }
144             } catch (UnknownHostException e) {
145                 LOG.error("Error in deserializing packet {} with exception", value, e);
146             }
147         });
148     }
149
150     @Override
151     public void remove(InstanceIdentifier<LearntVpnVipToPort> key, LearntVpnVipToPort value) {
152         runOnlyInOwnerNode("IpMonitoringHandler: remove event", () -> {
153             try {
154                 InetAddress srcInetAddr = InetAddress.getByName(value.getPortFixedip());
155                 if (value.getMacAddress() == null) {
156                     LOG.warn("The mac address received is null for LearntVpnVipToPort {}, ignoring the DTCN", value);
157                     return;
158                 }
159                 String vpnName =  value.getVpnName();
160                 String learntIp = srcInetAddr.getHostAddress();
161                 LearntVpnVipToPort vpnVipToPort = vpnUtil.getLearntVpnVipToPort(vpnName, learntIp);
162                 if (vpnVipToPort != null && !vpnVipToPort.getCreationTime().equals(value.getCreationTime())) {
163                     LOG.warn("The MIP {} over vpn {} has been learnt again and processed. "
164                             + "Ignoring this remove event.", learntIp, vpnName);
165                     return;
166                 }
167                 MacAddress srcMacAddress = MacAddress.getDefaultInstance(value.getMacAddress());
168                 String interfaceName =  value.getPortName();
169                 MacEntry macEntry = new MacEntry(vpnName, srcMacAddress, srcInetAddr, interfaceName,
170                         value.getCreationTime());
171
172                 jobCoordinator.enqueueJob(VpnUtil.buildIpMonitorJobKey(srcInetAddr.toString(), vpnName),
173                         new IpMonitorStopTask(macEntry, dataBroker, Boolean.FALSE, vpnUtil, alivenessMonitorUtils));
174             } catch (UnknownHostException e) {
175                 LOG.error("Error in deserializing packet {} with exception", value, e);
176             }
177         });
178     }
179
180     private void runOnlyInOwnerNode(String jobDesc, final Runnable job) {
181         entityOwnershipUtils.runOnlyInOwnerNode(VpnConstants.IP_MONITORING_ENTITY, VpnConstants.IP_MONITORING_ENTITY,
182                 jobCoordinator, jobDesc, job);
183     }
184
185     private Optional<Uint32> getMonitorProfileId(String ipAddress) {
186         if (NWUtil.isIpv4Address(ipAddress)) {
187             return this.arpMonitorProfileId;
188         } else {
189             return this.ipv6NdMonitorProfileId;
190         }
191     }
192 }
193