2 * Copyright (c) 2015 - 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.vpnmanager;
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;
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;
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;
66 LOG.info("{} start", getClass().getSimpleName());
67 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
71 protected InstanceIdentifier<VpnInstanceOpDataEntry> getWildCardPath() {
72 return InstanceIdentifier.create(VpnInstanceOpData.class).child(VpnInstanceOpDataEntry.class);
76 protected VpnOpStatusListener getDataTreeChangeListener() {
77 return VpnOpStatusListener.this;
81 protected void remove(InstanceIdentifier<VpnInstanceOpDataEntry> identifier, VpnInstanceOpDataEntry value) {
82 LOG.info("remove: Ignoring vpn Op {} with rd {}", value.getVpnInstanceName(), value.getVrfId());
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)) {
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));
110 if (update.isIpv4Configured()) {
111 rds.parallelStream().forEach(rd -> bgpManager.deleteVrf(rd, false, AddressFamily.IPV4));
113 if (update.isIpv6Configured()) {
114 rds.parallelStream().forEach(rd -> bgpManager.deleteVrf(rd, false, AddressFamily.IPV6));
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);
124 if (VpnUtil.isL3VpnOverVxLan(update.getL3vni())) {
125 VpnUtil.removeExternalTunnelDemuxFlows(vpnName, dataBroker, mdsalManager);
128 // Clean up VPNInstanceOpDataEntry
129 VpnUtil.removeVpnOpInstance(dataBroker, primaryRd, writeTxn);
130 // Clean up PrefixToInterface Operational DS
131 VpnUtil.removePrefixToInterfaceForVpnId(dataBroker, vpnId, writeTxn);
133 // Clean up L3NextHop Operational DS
134 VpnUtil.removeL3nexthopForVpnId(dataBroker, vpnId, writeTxn);
136 // Release the ID used for this VPN back to IdManager
137 VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME, vpnName);
139 List<ListenableFuture<Void>> futures = new ArrayList<>();
140 futures.add(writeTxn.submit());
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)) {
150 if (original == null) {
151 LOG.error("VpnOpStatusListener.update: vpn {} with RD {}. add() handler already called",
155 if (update.getVpnTargets() == null) {
156 LOG.error("VpnOpStatusListener.update: vpn {} with RD {} vpnTargets not ready",
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());
168 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ImportExtcommunity) {
169 irtList.add(vpnTarget.getVrfRTValue());
171 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.Both) {
172 ertList.add(vpnTarget.getVrfRTValue());
173 irtList.add(vpnTarget.getVrfRTValue());
177 LOG.error("VpnOpStatusListener.update: vpn target list is empty, cannot add BGP"
178 + " VPN {} RD {}", vpnName, primaryRd);
181 jobCoordinator.enqueueJob("VPN-" + update.getVpnInstanceName(), () -> {
182 WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
183 long primaryRdAddFailed = rds.parallelStream().filter(rd -> {
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);
191 bgpManager.deleteVrf(rd, false, AddressFamily.L2VPN);
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);
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);
203 } catch (Exception e) {
204 LOG.error("VpnOpStatusListener.update: Exception when updating VRF to BGP"
205 + " for vpn {} rd {}", vpnName, rd);
210 return Collections.emptyList();
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());