2 * Copyright (c) 2016 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.neutronvpn;
10 import java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.HashSet;
14 import java.util.Iterator;
15 import java.util.List;
17 import java.util.concurrent.ExecutionException;
18 import java.util.concurrent.Future;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
22 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMap;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.bgpvpns.rev150903.BgpvpnTypeBase;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.bgpvpns.rev150903.BgpvpnTypeL3;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.bgpvpns.rev150903.bgpvpns.attributes.Bgpvpns;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.bgpvpns.rev150903.bgpvpns.attributes.bgpvpns.Bgpvpn;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
33 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
34 import org.opendaylight.yangtools.yang.common.RpcResult;
35 import org.osgi.framework.BundleContext;
36 import org.osgi.framework.FrameworkUtil;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
40 public class NeutronBgpvpnChangeListener extends AsyncDataTreeChangeListenerBase<Bgpvpn, NeutronBgpvpnChangeListener>
41 implements AutoCloseable {
42 private static final Logger LOG = LoggerFactory.getLogger(NeutronBgpvpnChangeListener.class);
43 private final DataBroker dataBroker;
44 private final NeutronvpnManager nvpnManager;
45 private final IdManagerService idManager;
46 private final String adminRDValue;
48 public NeutronBgpvpnChangeListener(final DataBroker dataBroker, final NeutronvpnManager nVpnMgr,
49 final IdManagerService idManager) {
50 super(Bgpvpn.class, NeutronBgpvpnChangeListener.class);
51 this.dataBroker = dataBroker;
52 nvpnManager = nVpnMgr;
53 this.idManager = idManager;
54 BundleContext bundleContext=FrameworkUtil.getBundle(NeutronBgpvpnChangeListener.class).getBundleContext();
55 adminRDValue = bundleContext.getProperty(NeutronConstants.RD_PROPERTY_KEY);
59 LOG.info("{} start", getClass().getSimpleName());
61 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
65 protected InstanceIdentifier<Bgpvpn> getWildCardPath() {
66 return InstanceIdentifier.create(Neutron.class).child(Bgpvpns.class).child(Bgpvpn.class);
70 protected NeutronBgpvpnChangeListener getDataTreeChangeListener() {
71 return NeutronBgpvpnChangeListener.this;
74 private boolean isBgpvpnTypeL3(Class<? extends BgpvpnTypeBase> bgpvpnType) {
75 if (BgpvpnTypeL3.class.equals(bgpvpnType)) {
78 LOG.warn("CRUD operations supported only for L3 type Bgpvpn");
84 protected void add(InstanceIdentifier<Bgpvpn> identifier, Bgpvpn input) {
85 LOG.trace("Adding Bgpvpn : key: {}, value={}", identifier, input);
86 if (isBgpvpnTypeL3(input.getType())) {
87 // handle route-target(s)
88 List<String> importRouteTargets = new ArrayList<String>();
89 List<String> exportRouteTargets = new ArrayList<String>();
90 List<String> inputRouteList = input.getRouteTargets();
91 List<String> inputImportRouteList = input.getImportTargets();
92 List<String> inputExportRouteList = input.getExportTargets();
93 Set<String> inputImportRouteSet = new HashSet<>();
94 Set<String> inputExportRouteSet = new HashSet<>();
96 if (inputRouteList != null && !inputRouteList.isEmpty()) {
97 inputImportRouteSet.addAll(inputRouteList);
98 inputExportRouteSet.addAll(inputRouteList);
100 if (inputImportRouteList != null && !inputImportRouteList.isEmpty()) {
101 inputImportRouteSet.addAll(inputImportRouteList);
103 if (inputExportRouteList != null && !inputExportRouteList.isEmpty()) {
104 inputExportRouteSet.addAll(inputExportRouteList);
107 importRouteTargets.addAll(inputImportRouteSet);
108 exportRouteTargets.addAll(inputExportRouteSet);
110 List<String> rd = input.getRouteDistinguishers();
112 if (rd == null || rd.isEmpty()) {
114 rd = generateNewRD(input.getUuid());
116 String[] rdParams = rd.get(0).split(":");
117 if (rdParams[0].trim().equals(adminRDValue)) {
118 LOG.error("AS specific part of RD should not be same as that defined by DC Admin");
123 if (input.getRouters() != null && !input.getRouters().isEmpty()) {
124 // currently only one router
125 router = input.getRouters().get(0);
129 nvpnManager.createL3Vpn(input.getUuid(), input.getName(), input.getTenantId(), rd, importRouteTargets,
130 exportRouteTargets, router, input.getNetworks());
131 } catch (Exception e) {
132 LOG.error("Creation of BGPVPN {} failed with error message {}. ", input.getUuid(),
136 LOG.error("Create BgpVPN with id " + input.getUuid() + " failed due to missing/invalid RD value.");
141 private List<String> generateNewRD(Uuid vpn) {
142 if (adminRDValue != null) {
143 Integer rdId = NeutronvpnUtils.getUniqueRDId(idManager, NeutronConstants.RD_IDPOOL_NAME, vpn.toString());
145 String rd = adminRDValue + ":" + rdId;
146 LOG.debug("Generated RD {} for L3VPN {}", rd, vpn);
147 return Collections.singletonList(rd);
150 return Collections.emptyList();
154 protected void remove(InstanceIdentifier<Bgpvpn> identifier, Bgpvpn input) {
155 LOG.trace("Removing Bgpvpn : key: {}, value={}", identifier, input);
156 if (isBgpvpnTypeL3(input.getType())) {
157 nvpnManager.removeL3Vpn(input.getUuid());
158 // Release RD Id in pool
159 NeutronvpnUtils.releaseRDId(idManager, NeutronConstants.RD_IDPOOL_NAME, input.getUuid().toString());
164 protected void update(InstanceIdentifier<Bgpvpn> identifier, Bgpvpn original, Bgpvpn update) {
165 LOG.trace("Update Bgpvpn : key: {}, value={}", identifier, update);
166 if (isBgpvpnTypeL3(update.getType())) {
167 List<Uuid> oldNetworks = original.getNetworks();
168 List<Uuid> newNetworks = update.getNetworks();
169 List<Uuid> oldRouters = original.getRouters();
170 List<Uuid> newRouters = update.getRouters();
171 Uuid vpnId = update.getUuid();
172 handleNetworksUpdate(vpnId, oldNetworks, newNetworks);
173 handleRoutersUpdate(vpnId, oldRouters, newRouters);
177 protected void handleNetworksUpdate(Uuid vpnId, List<Uuid> oldNetworks, List<Uuid> newNetworks) {
178 if (newNetworks != null && !newNetworks.isEmpty()) {
179 if (oldNetworks != null && !oldNetworks.isEmpty()) {
180 if (oldNetworks != newNetworks) {
181 Iterator<Uuid> iter = newNetworks.iterator();
182 while (iter.hasNext()) {
183 Uuid net = iter.next();
184 if (oldNetworks.contains(net)) {
185 oldNetworks.remove(net);
189 //clear removed networks
190 if (!oldNetworks.isEmpty()) {
191 LOG.trace("Removing old networks {} ", oldNetworks);
192 nvpnManager.dissociateNetworksFromVpn(vpnId, oldNetworks);
195 //add new (Delta) Networks
196 if (!newNetworks.isEmpty()) {
197 LOG.trace("Adding delta New networks {} ", newNetworks);
198 nvpnManager.associateNetworksToVpn(vpnId, newNetworks);
203 LOG.trace("Adding New networks {} ", newNetworks);
204 nvpnManager.associateNetworksToVpn(vpnId, newNetworks);
206 } else if (oldNetworks != null && !oldNetworks.isEmpty()) {
207 LOG.trace("Removing old networks {} ", oldNetworks);
208 nvpnManager.dissociateNetworksFromVpn(vpnId, oldNetworks);
213 protected void handleRoutersUpdate(Uuid vpnId, List<Uuid> oldRouters, List<Uuid> newRouters) {
214 if (newRouters != null && !newRouters.isEmpty()) {
215 if (oldRouters != null && !oldRouters.isEmpty()) {
216 if (oldRouters.size() > 1 || newRouters.size() > 1) {
217 VpnMap vpnMap = NeutronvpnUtils.getVpnMap(dataBroker, vpnId);
218 if (vpnMap.getRouterId() != null) {
219 LOG.warn("Only Single Router association to a given bgpvpn is allowed .Kindly de-associate " +
220 "router " + vpnMap.getRouterId().getValue() + " from vpn " + vpnId + " before " +
221 "proceeding with associate");
225 } else if (validateRouteInfo(newRouters.get(0))) {
226 nvpnManager.associateRouterToVpn(vpnId, newRouters.get(0));
229 } else if (oldRouters != null && !oldRouters.isEmpty()) {
230 /* dissociate old router */
231 Uuid oldRouter = oldRouters.get(0);
232 nvpnManager.dissociateRouterFromVpn(vpnId, oldRouter);
236 private void createIdPool() {
237 CreateIdPoolInput createPool = new CreateIdPoolInputBuilder().setPoolName(NeutronConstants.RD_IDPOOL_NAME)
238 .setLow(NeutronConstants.RD_IDPOOL_START)
239 .setHigh(new BigInteger(NeutronConstants.RD_IDPOOL_SIZE).longValue()).build();
241 Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
242 if ((result != null) && (result.get().isSuccessful())) {
243 LOG.info("Created IdPool for Bgpvpn RD");
245 } catch (InterruptedException | ExecutionException e) {
246 LOG.error("Failed to create idPool for Bgpvpn RD", e);
250 private boolean validateRouteInfo(Uuid routerID) {
252 if ((assocVPNId = NeutronvpnUtils.getVpnForRouter(dataBroker, routerID, true)) != null) {
253 LOG.warn("VPN router association failed due to router " + routerID.getValue()
254 + " already associated to another VPN " + assocVPNId.getValue());