NETVIRT-1062: refactor SubnetmapChangeListener
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / SubnetmapChangeListener.java
1 /*
2  * Copyright (c) 2016, 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
9 package org.opendaylight.netvirt.vpnmanager;
10
11 import com.google.common.base.Optional;
12 import java.util.ArrayList;
13 import java.util.List;
14 import java.util.Objects;
15 import javax.annotation.PostConstruct;
16 import javax.inject.Inject;
17 import javax.inject.Singleton;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
28 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 @Singleton
33 public class SubnetmapChangeListener extends AsyncDataTreeChangeListenerBase<Subnetmap, SubnetmapChangeListener> {
34     private static final Logger LOG = LoggerFactory.getLogger(SubnetmapChangeListener.class);
35     private final DataBroker dataBroker;
36     private final VpnSubnetRouteHandler vpnSubnetRouteHandler;
37
38     @Inject
39     public SubnetmapChangeListener(final DataBroker dataBroker, final VpnSubnetRouteHandler vpnSubnetRouteHandler) {
40         super(Subnetmap.class, SubnetmapChangeListener.class);
41         this.dataBroker = dataBroker;
42         this.vpnSubnetRouteHandler = vpnSubnetRouteHandler;
43     }
44
45     @PostConstruct
46     public void start() {
47         LOG.info("{} start", getClass().getSimpleName());
48         registerListener(dataBroker);
49     }
50
51     @Override
52     protected InstanceIdentifier<Subnetmap> getWildCardPath() {
53         return InstanceIdentifier.create(Subnetmaps.class).child(Subnetmap.class);
54     }
55
56     // TODO Clean up the exception handling
57     @SuppressWarnings("checkstyle:IllegalCatch")
58     private void registerListener(final DataBroker db) {
59         try {
60             registerListener(LogicalDatastoreType.CONFIGURATION, db);
61         } catch (final Exception e) {
62             LOG.error("VPNManager subnetMap config DataChange listener registration fail!", e);
63             throw new IllegalStateException("VPNManager subnetMap config DataChange listener registration failed.", e);
64         }
65     }
66
67     @Override
68     protected void add(InstanceIdentifier<Subnetmap> identifier, Subnetmap subnetmap) {
69         LOG.debug("SubnetmapChangeListener add subnetmap method - key: {}, value: {}", identifier, subnetmap);
70         Uuid subnetId = subnetmap.getId();
71         Network network = VpnUtil.getNeutronNetwork(dataBroker, subnetmap.getNetworkId());
72         if (network == null) {
73             LOG.error("SubnetMapChangeListener:add: network was not found for subnetId {}", subnetId.getValue());
74             return;
75         }
76         if (VpnUtil.getIsExternal(network)) {
77             LOG.debug("SubnetmapListener:add: provider subnetwork {} is handling in "
78                       + "ExternalSubnetVpnInstanceListener", subnetId.getValue());
79             return;
80         }
81         String elanInstanceName = subnetmap.getNetworkId().getValue();
82         long elanTag = getElanTag(elanInstanceName);
83         if (elanTag == 0L) {
84             LOG.error("SubnetMapChangeListener:add: unable to fetch elantag from ElanInstance {} for subnet {}",
85                       elanInstanceName, subnetId.getValue());
86             return;
87         }
88         if (subnetmap.getVpnId() != null) {
89             boolean isBgpVpn = !subnetmap.getVpnId().equals(subnetmap.getRouterId());
90             LOG.info("SubnetMapChangeListener:add: subnetmap {} with elanTag {} to VPN {}", subnetmap, elanTag,
91                      subnetmap.getVpnId());
92             vpnSubnetRouteHandler.onSubnetAddedToVpn(subnetmap, isBgpVpn, elanTag);
93         }
94     }
95
96     @Override
97     protected void remove(InstanceIdentifier<Subnetmap> identifier, Subnetmap subnetmap) {
98         LOG.trace("SubnetmapListener:remove: subnetmap method - key: {}, value: {}", identifier, subnetmap);
99     }
100
101     @Override
102     // TODO Clean up the exception handling
103     @SuppressWarnings("checkstyle:IllegalCatch")
104     protected void update(InstanceIdentifier<Subnetmap> identifier, Subnetmap subnetmapOriginal, Subnetmap
105             subnetmapUpdate) {
106         LOG.debug("SubnetMapChangeListener update method - key {}, original {}, update {}", identifier,
107                   subnetmapOriginal, subnetmapUpdate);
108         Uuid subnetId = subnetmapUpdate.getId();
109         Network network = VpnUtil.getNeutronNetwork(dataBroker, subnetmapUpdate.getNetworkId());
110         if (network == null) {
111             LOG.error("SubnetMapChangeListener:update: network was not found for subnetId {}", subnetId.getValue());
112             return;
113         }
114         if (VpnUtil.getIsExternal(network)) {
115             LOG.debug("SubnetMapChangeListener:update: provider subnetwork {} is handling in "
116                       + "ExternalSubnetVpnInstanceListener", subnetId.getValue());
117             return;
118         }
119         String elanInstanceName = subnetmapUpdate.getNetworkId().getValue();
120         long elanTag = getElanTag(elanInstanceName);
121         if (elanTag == 0L) {
122             LOG.error("SubnetMapChangeListener:update: unable to fetch elantag from ElanInstance {} for subnetId {}",
123                       elanInstanceName, subnetId);
124             return;
125         }
126         // update on BGPVPN or InternalVPN change
127         Uuid vpnIdOld = subnetmapOriginal.getVpnId();
128         Uuid vpnIdNew = subnetmapUpdate.getVpnId();
129         if (!Objects.equals(vpnIdOld, vpnIdNew)) {
130             LOG.info("SubnetMapChangeListener:update: update subnetOpDataEntry for subnet {} imported in VPN",
131                      subnetmapUpdate.getId().getValue());
132             updateSubnetmapOpDataEntry(subnetmapOriginal.getVpnId(), subnetmapUpdate.getVpnId(), subnetmapUpdate,
133                                        subnetmapOriginal, elanTag);
134         }
135         // update on Internet VPN Id change
136         Uuid inetVpnIdOld = subnetmapOriginal.getInternetVpnId();
137         Uuid inetVpnIdNew = subnetmapUpdate.getInternetVpnId();
138         if (!Objects.equals(inetVpnIdOld, inetVpnIdNew)) {
139             LOG.info("SubnetMapChangeListener:update: update subnetOpDataEntry for subnet {} imported in InternetVPN",
140                      subnetmapUpdate.getId().getValue());
141             updateSubnetmapOpDataEntry(inetVpnIdOld, inetVpnIdNew, subnetmapUpdate, subnetmapOriginal, elanTag);
142         }
143         // update on PortList change
144         List<Uuid> oldPortList;
145         List<Uuid> newPortList;
146         newPortList = subnetmapUpdate.getPortList() != null ? subnetmapUpdate.getPortList() : new ArrayList<>();
147         oldPortList = subnetmapOriginal.getPortList() != null ? subnetmapOriginal.getPortList() : new ArrayList<>();
148         if (newPortList.size() == oldPortList.size()) {
149             return;
150         }
151         LOG.info("SubnetMapChangeListener:update: update port list for subnet {}", subnetmapUpdate.getId().getValue());
152         if (newPortList.size() > oldPortList.size()) {
153             for (Uuid portId : newPortList) {
154                 if (! oldPortList.contains(portId)) {
155                     vpnSubnetRouteHandler.onPortAddedToSubnet(subnetmapUpdate, portId);
156                     return;
157                 }
158             }
159         } else {
160             for (Uuid portId : oldPortList) {
161                 if (! newPortList.contains(portId)) {
162                     vpnSubnetRouteHandler.onPortRemovedFromSubnet(subnetmapUpdate, portId);
163                     return;
164                 }
165             }
166         }
167     }
168
169     private void updateSubnetmapOpDataEntry(Uuid vpnIdOld, Uuid vpnIdNew, Subnetmap subnetmapUpdate,
170                                     Subnetmap subnetmapOriginal, Long elanTag) {
171
172         // subnet added to VPN
173         if (vpnIdNew != null && vpnIdOld == null) {
174             if (vpnIdNew.equals(subnetmapUpdate.getRouterId())) {
175                 return;
176             }
177             vpnSubnetRouteHandler.onSubnetAddedToVpn(subnetmapUpdate, true, elanTag);
178         }
179         // subnet removed from VPN
180         if (vpnIdOld != null && vpnIdNew == null) {
181             if (vpnIdOld.equals(subnetmapOriginal.getRouterId())) {
182                 return;
183             }
184             vpnSubnetRouteHandler.onSubnetDeletedFromVpn(subnetmapOriginal, true);
185         }
186         // subnet updated in VPN
187         if (vpnIdOld != null && vpnIdNew != null && (!vpnIdNew.equals(vpnIdOld))) {
188             vpnSubnetRouteHandler.onSubnetUpdatedInVpn(subnetmapUpdate, elanTag);
189         }
190     }
191
192     @Override
193     protected SubnetmapChangeListener getDataTreeChangeListener() {
194         return this;
195     }
196
197     // TODO Clean up the exception handling
198     @SuppressWarnings("checkstyle:IllegalCatch")
199     protected long getElanTag(String elanInstanceName) {
200         InstanceIdentifier<ElanInstance> elanIdentifierId = InstanceIdentifier.builder(ElanInstances.class)
201                 .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
202         long elanTag = 0L;
203         try {
204             Optional<ElanInstance> elanInstance = VpnUtil.read(dataBroker, LogicalDatastoreType
205                     .CONFIGURATION, elanIdentifierId);
206             if (elanInstance.isPresent()) {
207                 if (elanInstance.get().getElanTag() != null) {
208                     elanTag = elanInstance.get().getElanTag();
209                 } else {
210                     LOG.error("Notification failed because of failure in fetching elanTag for ElanInstance {}",
211                             elanInstanceName);
212                 }
213             } else {
214                 LOG.error("Notification failed because of failure in reading ELANInstance {}", elanInstanceName);
215             }
216         } catch (Exception e) {
217             LOG.error("Notification failed because of failure in fetching elanTag for ElanInstance {}",
218                 elanInstanceName, e);
219         }
220         return elanTag;
221     }
222 }