7f6c346f90285ddae2a7137b4908a649f59e3cd4
[netvirt.git] /
1 /*
2  * Copyright (c) 2015, 2017 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;
9
10 import com.google.common.base.Optional;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.List;
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
18 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
19 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
20 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
21 import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
22 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntry;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
29 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 public class SubnetRouteInterfaceStateChangeListener extends AsyncDataTreeChangeListenerBase<Interface,
34     SubnetRouteInterfaceStateChangeListener> implements AutoCloseable {
35     private static final Logger LOG = LoggerFactory.getLogger(SubnetRouteInterfaceStateChangeListener.class);
36     private static final String LOGGING_PREFIX = "SUBNETROUTE:";
37     private final DataBroker dataBroker;
38     private final VpnInterfaceManager vpnInterfaceManager;
39     private final VpnSubnetRouteHandler vpnSubnetRouteHandler;
40     private final SubnetOpDpnManager subOpDpnManager;
41     private final INeutronVpnManager neutronVpnManager;
42
43     public SubnetRouteInterfaceStateChangeListener(final DataBroker dataBroker,
44         final VpnInterfaceManager vpnInterfaceManager,
45         final VpnSubnetRouteHandler vpnSubnetRouteHandler,
46         final SubnetOpDpnManager subnetOpDpnManager,
47         final INeutronVpnManager neutronVpnService) {
48         super(Interface.class, SubnetRouteInterfaceStateChangeListener.class);
49         this.dataBroker = dataBroker;
50         this.vpnInterfaceManager = vpnInterfaceManager;
51         this.vpnSubnetRouteHandler = vpnSubnetRouteHandler;
52         this.subOpDpnManager = subnetOpDpnManager;
53         this.neutronVpnManager = neutronVpnService;
54     }
55
56     public void start() {
57         LOG.info("{} start", getClass().getSimpleName());
58         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
59     }
60
61     @Override
62     protected InstanceIdentifier<Interface> getWildCardPath() {
63         return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
64     }
65
66     @Override
67     protected SubnetRouteInterfaceStateChangeListener getDataTreeChangeListener() {
68         return SubnetRouteInterfaceStateChangeListener.this;
69     }
70
71     // TODO Clean up the exception handling
72     @SuppressWarnings("checkstyle:IllegalCatch")
73     @Override
74     protected void add(InstanceIdentifier<Interface> identifier, Interface intrf) {
75         LOG.trace("{} add: Received interface {} up event", LOGGING_PREFIX, intrf);
76         final Uuid subnetId;
77         try {
78             if (L2vlan.class.equals(intrf.getType())) {
79                 LOG.trace("SubnetRouteInterfaceListener add: Received interface {} up event", intrf);
80                 if (intrf.getOperStatus().equals(Interface.OperStatus.Up)) {
81                     subnetId = getSubnetId(intrf);
82                     if (subnetId == null) {
83                         LOG.error("SubnetRouteInterfaceListener add: Port {} doesnt exist in configDS",
84                                 intrf.getName());
85                         return;
86                     }
87                     DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
88                     dataStoreCoordinator.enqueueJob("SUBNETROUTE-" + subnetId,
89                         () -> {
90                             List<ListenableFuture<Void>> futures = new ArrayList<>();
91                             String interfaceName = intrf.getName();
92                             LOG.info("{} add: Received port UP event for interface {} subnetId {}",
93                                     LOGGING_PREFIX, interfaceName, subnetId.getValue());
94                             try {
95                                 BigInteger dpnId = InterfaceUtils.getDpIdFromInterface(intrf);
96                                 vpnSubnetRouteHandler.onInterfaceUp(dpnId, intrf.getName(), subnetId);
97                             } catch (Exception e) {
98                                 LOG.error("{} add: Unable to obtain dpnId for interface {} in subnet {},"
99                                         + " subnetroute inclusion for this interface failed with exception {}",
100                                         LOGGING_PREFIX, interfaceName, subnetId.getValue(), e);
101                             }
102                             return futures;
103                         });
104                 }
105             }
106             LOG.info("{} add: Processed interface {} up event", LOGGING_PREFIX, intrf.getName());
107         } catch (Exception e) {
108             LOG.error("{} add: Exception observed in handling addition for VPN Interface {}.", LOGGING_PREFIX,
109                 intrf.getName(), e);
110         }
111     }
112
113     // TODO Clean up the exception handling
114     @SuppressWarnings("checkstyle:IllegalCatch")
115     @Override
116     protected void remove(InstanceIdentifier<Interface> identifier, Interface intrf) {
117         final Uuid subnetId;
118         try {
119             if (L2vlan.class.equals(intrf.getType())) {
120                 LOG.trace("SubnetRouteInterfaceListener remove: Received interface {} down event", intrf);
121                 subnetId = getSubnetId(intrf);
122                 if (subnetId == null) {
123                     LOG.error("SubnetRouteInterfaceListener add: Port {} doesnt exist in configDS",
124                             intrf.getName());
125                     return;
126                 }
127                 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
128                 dataStoreCoordinator.enqueueJob("SUBNETROUTE-" + subnetId,
129                     () -> {
130                         String interfaceName = intrf.getName();
131                         BigInteger dpnId = BigInteger.ZERO;
132                         LOG.info("{} remove: Received port DOWN event for interface {} in subnet {} ",
133                                 LOGGING_PREFIX, interfaceName, subnetId.getValue());
134                         try {
135                             dpnId = InterfaceUtils.getDpIdFromInterface(intrf);
136                         } catch (Exception e) {
137                             LOG.error("{} remove: Unable to retrieve dpnId for interface {} in subnet {}. "
138                                             + "Fetching from vpn interface itself due to exception {}",
139                                     LOGGING_PREFIX, intrf.getName(), subnetId.getValue(), e);
140                             InstanceIdentifier<VpnInterface> id = VpnUtil
141                                     .getVpnInterfaceIdentifier(interfaceName);
142                             Optional<VpnInterface> optVpnInterface = VpnUtil.read(dataBroker,
143                                     LogicalDatastoreType.OPERATIONAL, id);
144                             if (optVpnInterface.isPresent()) {
145                                 dpnId = optVpnInterface.get().getDpnId();
146                             }
147                         }
148                         if (!dpnId.equals(BigInteger.ZERO)) {
149                             vpnSubnetRouteHandler.onInterfaceDown(dpnId, intrf.getName(), subnetId);
150                         }
151                         List<ListenableFuture<Void>> futures = new ArrayList<>();
152                         return futures;
153                     });
154             }
155             LOG.info("{} remove: Processed interface {} down event in ", LOGGING_PREFIX, intrf.getName());
156         } catch (Exception e) {
157             LOG.error("{} remove: Exception observed in handling deletion of VPN Interface {}.", LOGGING_PREFIX,
158                 intrf.getName(), e);
159         }
160     }
161
162     // TODO Clean up the exception handling
163     @SuppressWarnings("checkstyle:IllegalCatch")
164     @Override
165     protected void update(InstanceIdentifier<Interface> identifier,
166         Interface original, Interface update) {
167         final Uuid subnetId;
168         try {
169             String interfaceName = update.getName();
170             if (L2vlan.class.equals(update.getType())) {
171                 LOG.trace("{} update: Operation Interface update event - Old: {}, New: {}", LOGGING_PREFIX,
172                     original, update);
173                 subnetId = getSubnetId(update);
174                 if (subnetId == null) {
175                     LOG.error("SubnetRouteInterfaceListener update: Port {} doesnt exist in configDS",
176                             update.getName());
177                     return;
178                 }
179                 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
180                 dataStoreCoordinator.enqueueJob("SUBNETROUTE-" + subnetId,
181                     () -> {
182                         List<ListenableFuture<Void>> futures = new ArrayList<>();
183                         BigInteger dpnId = BigInteger.ZERO;
184                         try {
185                             dpnId = InterfaceUtils.getDpIdFromInterface(update);
186                         } catch (Exception e) {
187                             LOG.error("{} remove: Unable to retrieve dpnId for interface {} in subnet  {}. "
188                                     + "Fetching from vpn interface itself due to exception {}", LOGGING_PREFIX,
189                                     update.getName(), subnetId.getValue(), e);
190                             InstanceIdentifier<VpnInterface> id = VpnUtil
191                                     .getVpnInterfaceIdentifier(interfaceName);
192                             Optional<VpnInterface> optVpnInterface = VpnUtil.read(dataBroker,
193                                     LogicalDatastoreType.OPERATIONAL, id);
194                             if (optVpnInterface.isPresent()) {
195                                 dpnId = optVpnInterface.get().getDpnId();
196                             }
197                         }
198                         if (!dpnId.equals(BigInteger.ZERO)) {
199                             if (update.getOperStatus().equals(Interface.OperStatus.Up)) {
200                                 LOG.info("{} update: Received port UP event for interface {} in subnet {}",
201                                         LOGGING_PREFIX, update.getName(), subnetId.getValue());
202                                 vpnSubnetRouteHandler.onInterfaceUp(dpnId, update.getName(), subnetId);
203                             } else if (update.getOperStatus().equals(Interface.OperStatus.Down)
204                                     || update.getOperStatus().equals(Interface.OperStatus.Unknown)) {
205                                 /*
206                                  * If the interface went down voluntarily (or) if the interface is not
207                                  * reachable from control-path involuntarily, trigger subnetRoute election
208                                  */
209                                 LOG.info("{} update: Received port {} event for interface {} in subnet {} ",
210                                         LOGGING_PREFIX, update.getOperStatus().equals(Interface.OperStatus.Unknown)
211                                                 ? "UNKNOWN" : "DOWN", update.getName(), subnetId.getValue());
212                                 vpnSubnetRouteHandler.onInterfaceDown(dpnId, update.getName(), subnetId);
213                             }
214                         }
215                         return futures;
216                     });
217             }
218             LOG.info("{} update: Processed Interface {} update event", LOGGING_PREFIX, update.getName());
219         } catch (Exception e) {
220             LOG.error("{} update: Exception observed in handling deletion of VPNInterface {}", LOGGING_PREFIX,
221                     update.getName(), e);
222         }
223     }
224
225     protected Uuid getSubnetId(Interface intrf) {
226
227         if (!NeutronUtils.isUuid(intrf.getName())) {
228             LOG.debug("SubnetRouteInterfaceListener: Interface {} doesnt have valid uuid pattern", intrf.getName());
229             return null;
230         }
231
232         PortOpDataEntry portOpEntry = subOpDpnManager.getPortOpDataEntry(intrf.getName());
233         if (portOpEntry != null) {
234             return portOpEntry.getSubnetId();
235         }
236         LOG.trace("SubnetRouteInterfaceListener : Received Port {} event for {} that is not part of subnetRoute",
237                 intrf.getOperStatus(), intrf.getName());
238         Port port = neutronVpnManager.getNeutronPort(intrf.getName());
239         if (port != null && port.getFixedIps() != null && port.getFixedIps().size() > 0) {
240             return port.getFixedIps().get(0).getSubnetId();
241         } else {
242             return null;
243         }
244     }
245 }