1e3f3c52968bca6ed3410a56a380e049712b5730
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / ExternalSubnetVpnInstanceListener.java
1 /*
2  * Copyright (c) 2017 HPE, Inc. 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.natservice.internal;
9
10 import com.google.common.base.Optional;
11 import java.util.List;
12 import javax.annotation.PostConstruct;
13 import javax.inject.Inject;
14 import javax.inject.Singleton;
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.controller.md.sal.common.api.data.ReadFailedException;
18 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
19 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
20 import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
21 import org.opendaylight.genius.mdsalutil.NwConstants;
22 import org.opendaylight.genius.mdsalutil.UpgradeState;
23 import org.opendaylight.netvirt.elanmanager.api.IElanService;
24 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceToVpnId;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.Subnets;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
33 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 @Singleton
38 public class ExternalSubnetVpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInstance,
39     ExternalSubnetVpnInstanceListener> {
40     private static final Logger LOG = LoggerFactory.getLogger(ExternalSubnetVpnInstanceListener.class);
41     private final DataBroker dataBroker;
42     private final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer;
43     private final IElanService elanService;
44     private final IVpnManager vpnManager;
45     private final UpgradeState upgradeState;
46     private final DataTreeEventCallbackRegistrar dataTreeEventCallbackRegistrar;
47
48     @Inject
49     public ExternalSubnetVpnInstanceListener(final DataBroker dataBroker,
50                      final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
51                      final IElanService elanService, final IVpnManager vpnManager,
52                      final UpgradeState upgradeState, DataTreeEventCallbackRegistrar dataTreeEventCallbackRegistrar) {
53         this.dataBroker = dataBroker;
54         this.snatDefaultRouteProgrammer = snatDefaultRouteProgrammer;
55         this.elanService = elanService;
56         this.vpnManager = vpnManager;
57         this.upgradeState = upgradeState;
58         this.dataTreeEventCallbackRegistrar = dataTreeEventCallbackRegistrar;
59     }
60
61     @Override
62     @PostConstruct
63     public void init() {
64         LOG.info("{} init", getClass().getSimpleName());
65         registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
66     }
67
68     @Override
69     protected InstanceIdentifier<VpnInstance> getWildCardPath() {
70         return InstanceIdentifier.create(VpnInstanceToVpnId.class).child(VpnInstance.class);
71     }
72
73     @Override
74     protected void remove(InstanceIdentifier<VpnInstance> key, VpnInstance vpnInstance) {
75         LOG.trace("remove : External Subnet VPN Instance remove mapping method - key:{}. value={}",
76                 vpnInstance.getKey(), vpnInstance);
77         String possibleExtSubnetUuid = vpnInstance.getVpnInstanceName();
78         Optional<Subnets> optionalSubnets = NatUtil.getOptionalExternalSubnets(dataBroker,
79                 new Uuid(possibleExtSubnetUuid));
80         if (optionalSubnets.isPresent()) {
81             addOrDelDefaultFibRouteToSNATFlow(vpnInstance, optionalSubnets.get(), NwConstants.DEL_FLOW);
82             invokeSubnetDeletedFromVpn(possibleExtSubnetUuid);
83         }
84     }
85
86     @Override
87     protected void update(InstanceIdentifier<VpnInstance> key, VpnInstance vpnInstanceOrig,
88             VpnInstance vpnInstanceNew) {
89         LOG.trace("update : External Subnet VPN Instance update mapping method - key:{} original:{} new:{}",
90                 vpnInstanceNew.getKey(), vpnInstanceOrig, vpnInstanceNew);
91     }
92
93     @Override
94     protected void add(InstanceIdentifier<VpnInstance> key, VpnInstance vpnInstance) {
95         LOG.trace("add : External Subnet VPN Instance OP Data Entry add mapping method - key:{}. value={}",
96                 vpnInstance.getKey(), vpnInstance);
97         String possibleExtSubnetUuid = vpnInstance.getVpnInstanceName();
98         Optional<Subnets> optionalSubnets = NatUtil.getOptionalExternalSubnets(dataBroker,
99                 new Uuid(possibleExtSubnetUuid));
100         if (optionalSubnets.isPresent()) {
101             LOG.debug("add : VpnInstance {} for external subnet {}.", possibleExtSubnetUuid,
102                     optionalSubnets.get());
103             addOrDelDefaultFibRouteToSNATFlow(vpnInstance, optionalSubnets.get(), NwConstants.ADD_FLOW);
104             invokeSubnetAddedToVpn(possibleExtSubnetUuid);
105         }
106     }
107
108     private void invokeSubnetAddedToVpn(String externalSubnetId) {
109         Uuid externalSubnetUuid = new Uuid(externalSubnetId);
110         Subnetmap subnetMap = NatUtil.getSubnetMap(dataBroker, externalSubnetUuid);
111         if (subnetMap == null) {
112             LOG.error("invokeSubnetAddedToVpn : Cannot invoke onSubnetAddedToVpn for subnet-id {} in vpn-id {}"
113                     + " due to this subnet missing in Subnetmap model", externalSubnetUuid, externalSubnetId);
114             return;
115         }
116         ElanInstance elanInstance = elanService.getElanInstance(subnetMap.getNetworkId().getValue());
117         vpnManager.onSubnetAddedToVpn(subnetMap, false, elanInstance.getElanTag());
118
119     }
120
121     private void invokeSubnetDeletedFromVpn(String externalSubnetId) {
122         Uuid externalSubnetUuid = new Uuid(externalSubnetId);
123         Subnetmap subnetMap = NatUtil.getSubnetMap(dataBroker, externalSubnetUuid);
124         vpnManager.onSubnetDeletedFromVpn(subnetMap, false);
125     }
126
127     private void addOrDelDefaultFibRouteToSNATFlow(VpnInstance vpnInstance, Subnets subnet, int flowAction) {
128         String vpnInstanceName = vpnInstance.getVpnInstanceName();
129         LOG.debug("addOrDelDefaultFibRouteToSNATFlow : VpnInstance {} for external subnet {}.",
130                 vpnInstanceName, subnet);
131         Long vpnId = vpnInstance.getVpnId();
132
133         if (upgradeState.isUpgradeInProgress()) {
134             LOG.info("Upgrade in process, checking for existence of VpnInstanceOpDataEntry's vpn->dpn list");
135             InstanceIdentifier<VpnInstanceOpDataEntry> vpnOpDataIid =
136                     NatUtil.getVpnInstanceOpDataIdentifier(subnet.getExternalNetworkId().getValue());
137
138             Optional<VpnInstanceOpDataEntry> networkVpnInstanceOp;
139             try {
140                 networkVpnInstanceOp = SingleTransactionDataBroker.syncReadOptional(
141                                             dataBroker, LogicalDatastoreType.OPERATIONAL, vpnOpDataIid);
142             } catch (ReadFailedException e) {
143                 LOG.error("Exception while attempting to read VpnInstanceOpDataEntry", e);
144                 return;
145             }
146
147             List<VpnToDpnList> dpnListInVpn = null;
148             if (networkVpnInstanceOp.isPresent()) {
149                 dpnListInVpn = networkVpnInstanceOp.get().getVpnToDpnList();
150             }
151
152             if (dpnListInVpn == null) {
153                 LOG.info("VpnInstanceOpDataEntry's vpn->dpn list not present, wait for it");
154                 dataTreeEventCallbackRegistrar.onAddOrUpdate(LogicalDatastoreType.OPERATIONAL, vpnOpDataIid,
155                     (beforeOpData, afterOpData) -> {
156                         LOG.info("VpnInstanceOpDataEntry added/updated {}", afterOpData);
157                         if (afterOpData.getVpnToDpnList() == null) {
158                             if (upgradeState.isUpgradeInProgress()) {
159                                 return DataTreeEventCallbackRegistrar.NextAction.CALL_AGAIN;
160                             } else {
161                                 return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
162                             }
163                         }
164                         snatDefaultRouteProgrammer.addOrDelDefaultFibRouteToSNATForSubnet(subnet,
165                                 subnet.getExternalNetworkId().getValue(), flowAction, vpnId);
166                         return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
167                     });
168                 return;
169             }
170             LOG.info("VpnInstanceOpDataEntry's vpn->dpn list present, continue with regular scheduled programming");
171
172         }
173
174         snatDefaultRouteProgrammer.addOrDelDefaultFibRouteToSNATForSubnet(subnet,
175                 subnet.getExternalNetworkId().getValue(), flowAction, vpnId);
176     }
177
178     @Override
179     protected ExternalSubnetVpnInstanceListener getDataTreeChangeListener() {
180         return ExternalSubnetVpnInstanceListener.this;
181     }
182 }