1163a54cf13fdfcc1d103036e8297936bab64289
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / VpnOpStatusListener.java
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.util.ArrayList;
13 import java.util.Collections;
14 import java.util.List;
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.binding.api.WriteTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
22 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
23 import org.opendaylight.genius.utils.SystemPropertyReader;
24 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
25 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
26 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
27 import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
28 import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.AddressFamily;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpntargets.VpnTarget;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.Vpn;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 @Singleton
39 public class VpnOpStatusListener extends AsyncDataTreeChangeListenerBase<VpnInstanceOpDataEntry, VpnOpStatusListener> {
40     private static final Logger LOG = LoggerFactory.getLogger(VpnOpStatusListener.class);
41     private final DataBroker dataBroker;
42     private final IBgpManager bgpManager;
43     private final IdManagerService idManager;
44     private final IFibManager fibManager;
45     private final IMdsalApiManager mdsalManager;
46     private final VpnFootprintService vpnFootprintService;
47     private final JobCoordinator jobCoordinator;
48
49     @Inject
50     public VpnOpStatusListener(final DataBroker dataBroker, final IBgpManager bgpManager,
51                                final IdManagerService idManager, final IFibManager fibManager,
52                                final IMdsalApiManager mdsalManager, final VpnFootprintService vpnFootprintService,
53                                final JobCoordinator jobCoordinator) {
54         super(VpnInstanceOpDataEntry.class, VpnOpStatusListener.class);
55         this.dataBroker = dataBroker;
56         this.bgpManager = bgpManager;
57         this.idManager = idManager;
58         this.fibManager = fibManager;
59         this.mdsalManager = mdsalManager;
60         this.vpnFootprintService = vpnFootprintService;
61         this.jobCoordinator = jobCoordinator;
62     }
63
64     @PostConstruct
65     public void start() {
66         LOG.info("{} start", getClass().getSimpleName());
67         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
68     }
69
70     @Override
71     protected InstanceIdentifier<VpnInstanceOpDataEntry> getWildCardPath() {
72         return InstanceIdentifier.create(VpnInstanceOpData.class).child(VpnInstanceOpDataEntry.class);
73     }
74
75     @Override
76     protected VpnOpStatusListener getDataTreeChangeListener() {
77         return VpnOpStatusListener.this;
78     }
79
80     @Override
81     protected void remove(InstanceIdentifier<VpnInstanceOpDataEntry> identifier, VpnInstanceOpDataEntry value) {
82         LOG.info("remove: Ignoring vpn Op {} with rd {}", value.getVpnInstanceName(), value.getVrfId());
83     }
84
85     @Override
86     @SuppressWarnings("checkstyle:IllegalCatch")
87     protected void update(InstanceIdentifier<VpnInstanceOpDataEntry> identifier,
88                           VpnInstanceOpDataEntry original, VpnInstanceOpDataEntry update) {
89         LOG.info("update: Processing update for vpn {} with rd {}", update.getVpnInstanceName(), update.getVrfId());
90         if (update.getVpnState() == VpnInstanceOpDataEntry.VpnState.PendingDelete
91                 && vpnFootprintService.isVpnFootPrintCleared(update)) {
92             //Cleanup VPN data
93             final String vpnName = update.getVpnInstanceName();
94             final List<String> rds = update.getRd();
95             String primaryRd = update.getVrfId();
96             final long vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
97             jobCoordinator.enqueueJob("VPN-" + update.getVpnInstanceName(), () -> {
98                 WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
99                 // Clean up VpnInstanceToVpnId from Config DS
100                 VpnUtil.removeVpnIdToVpnInstance(dataBroker, vpnId, writeTxn);
101                 VpnUtil.removeVpnInstanceToVpnId(dataBroker, vpnName, writeTxn);
102                 LOG.trace("Removed vpnIdentifier for  rd{} vpnname {}", primaryRd, vpnName);
103                 // Clean up FIB Entries Config DS
104                 fibManager.removeVrfTable(dataBroker, primaryRd, null);
105                 // Clean up VPNExtraRoutes Operational DS
106                 if (VpnUtil.isBgpVpn(vpnName, primaryRd)) {
107                     if (update.getType() == VpnInstanceOpDataEntry.Type.L2) {
108                         rds.parallelStream().forEach(rd -> bgpManager.deleteVrf(rd, false, AddressFamily.L2VPN));
109                     }
110                     if (update.isIpv4Configured()) {
111                         rds.parallelStream().forEach(rd -> bgpManager.deleteVrf(rd, false, AddressFamily.IPV4));
112                     }
113                     if (update.isIpv6Configured()) {
114                         rds.parallelStream().forEach(rd -> bgpManager.deleteVrf(rd, false, AddressFamily.IPV6));
115                     }
116                 }
117                 InstanceIdentifier<Vpn> vpnToExtraroute = VpnExtraRouteHelper.getVpnToExtrarouteVpnIdentifier(vpnName);
118                 Optional<Vpn> optVpnToExtraroute = VpnUtil.read(dataBroker,
119                         LogicalDatastoreType.OPERATIONAL, vpnToExtraroute);
120                 if (optVpnToExtraroute.isPresent()) {
121                     VpnUtil.removeVpnExtraRouteForVpn(dataBroker, vpnName, writeTxn);
122                 }
123
124                 if (VpnUtil.isL3VpnOverVxLan(update.getL3vni())) {
125                     VpnUtil.removeExternalTunnelDemuxFlows(vpnName, dataBroker, mdsalManager);
126                 }
127
128                 // Clean up VPNInstanceOpDataEntry
129                 VpnUtil.removeVpnOpInstance(dataBroker, primaryRd, writeTxn);
130                 // Clean up PrefixToInterface Operational DS
131                 VpnUtil.removePrefixToInterfaceForVpnId(dataBroker, vpnId, writeTxn);
132
133                 // Clean up L3NextHop Operational DS
134                 VpnUtil.removeL3nexthopForVpnId(dataBroker, vpnId, writeTxn);
135
136                 // Release the ID used for this VPN back to IdManager
137                 VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME, vpnName);
138
139                 List<ListenableFuture<Void>> futures = new ArrayList<>();
140                 futures.add(writeTxn.submit());
141                 return futures;
142             }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
143         } else if (update.getVpnState() == VpnInstanceOpDataEntry.VpnState.Created) {
144             final String vpnName = update.getVpnInstanceName();
145             final List<String> rds = update.getRd();
146             String primaryRd = update.getVrfId();
147             if (!VpnUtil.isBgpVpn(vpnName, primaryRd)) {
148                 return;
149             }
150             if (original == null) {
151                 LOG.error("VpnOpStatusListener.update: vpn {} with RD {}. add() handler already called",
152                        vpnName, primaryRd);
153                 return;
154             }
155             if (update.getVpnTargets() == null) {
156                 LOG.error("VpnOpStatusListener.update: vpn {} with RD {} vpnTargets not ready",
157                        vpnName, primaryRd);
158                 return;
159             }
160             List<VpnTarget> vpnTargetList = update.getVpnTargets().getVpnTarget();
161             List<String> ertList = new ArrayList<>();
162             List<String> irtList = new ArrayList<>();
163             if (vpnTargetList != null) {
164                 for (VpnTarget vpnTarget : vpnTargetList) {
165                     if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ExportExtcommunity) {
166                         ertList.add(vpnTarget.getVrfRTValue());
167                     }
168                     if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ImportExtcommunity) {
169                         irtList.add(vpnTarget.getVrfRTValue());
170                     }
171                     if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.Both) {
172                         ertList.add(vpnTarget.getVrfRTValue());
173                         irtList.add(vpnTarget.getVrfRTValue());
174                     }
175                 }
176             } else {
177                 LOG.error("VpnOpStatusListener.update: vpn target list is empty, cannot add BGP"
178                       + " VPN {} RD {}", vpnName, primaryRd);
179                 return;
180             }
181             jobCoordinator.enqueueJob("VPN-" + update.getVpnInstanceName(), () -> {
182                 WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
183                 long primaryRdAddFailed = rds.parallelStream().filter(rd -> {
184                     try {
185                         LOG.info("VpnOpStatusListener.update: updating BGPVPN for vpn {} with RD {}"
186                                 + " Type is {}, IPv4 is {}, IPv6 is {}", vpnName, primaryRd, update.getType(),
187                                 update.isIpv4Configured(), update.isIpv6Configured());
188                         if (update.getType() == VpnInstanceOpDataEntry.Type.L2) {
189                             bgpManager.addVrf(rd, irtList, ertList, AddressFamily.L2VPN);
190                         } else {
191                             bgpManager.deleteVrf(rd, false, AddressFamily.L2VPN);
192                         }
193                         if (!original.isIpv4Configured() && update.isIpv4Configured()) {
194                             bgpManager.addVrf(rd, irtList, ertList, AddressFamily.IPV4);
195                         } else if (original.isIpv4Configured() && !update.isIpv4Configured()) {
196                             bgpManager.deleteVrf(rd, false, AddressFamily.IPV4);
197                         }
198                         if (!original.isIpv6Configured() && update.isIpv6Configured()) {
199                             bgpManager.addVrf(rd, irtList, ertList, AddressFamily.IPV6);
200                         } else if (original.isIpv6Configured() && !update.isIpv6Configured()) {
201                             bgpManager.deleteVrf(rd, false, AddressFamily.IPV6);
202                         }
203                     } catch (Exception e) {
204                         LOG.error("VpnOpStatusListener.update: Exception when updating VRF to BGP"
205                                + " for vpn {} rd {}", vpnName, rd);
206                         return false;
207                     }
208                     return false;
209                 }).count();
210                 return Collections.emptyList();
211             });
212         }
213     }
214
215     @Override
216     protected void add(final InstanceIdentifier<VpnInstanceOpDataEntry> identifier,
217                        final VpnInstanceOpDataEntry value) {
218         LOG.debug("add: Ignoring vpn Op {} with rd {}", value.getVpnInstanceName(), value.getVrfId());
219     }
220 }