2 * Copyright (c) 2016, 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.cloudservicechain.listeners;
10 import java.util.Optional;
11 import java.math.BigInteger;
12 import java.util.Collection;
13 import java.util.Collections;
14 import java.util.List;
15 import java.util.stream.Collectors;
16 import javax.annotation.PostConstruct;
17 import javax.inject.Inject;
18 import javax.inject.Singleton;
19 import org.opendaylight.mdsal.binding.api.DataBroker;
20 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
21 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
22 import org.opendaylight.genius.mdsalutil.NwConstants;
23 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
24 import org.opendaylight.netvirt.cloudservicechain.utils.VpnPseudoPortCache;
25 import org.opendaylight.netvirt.cloudservicechain.utils.VpnServiceChainUtils;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
32 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
37 * Listens for VrfEntry creations or removal with the purpose of including the
38 * new label in the LFIB (or removing it) pointing to the VpnPseudoPort.
42 public class VrfListener extends AsyncDataTreeChangeListenerBase<VrfEntry, VrfListener> {
44 private static final Logger LOG = LoggerFactory.getLogger(VrfListener.class);
45 private final DataBroker broker;
46 private final IMdsalApiManager mdsalMgr;
47 private final VpnPseudoPortCache vpnPseudoPortCache;
50 public VrfListener(DataBroker broker, IMdsalApiManager mdsalMgr, VpnPseudoPortCache vpnPseudoPortCache) {
52 this.mdsalMgr = mdsalMgr;
53 this.vpnPseudoPortCache = vpnPseudoPortCache;
59 registerListener(LogicalDatastoreType.CONFIGURATION, broker);
63 protected InstanceIdentifier<VrfEntry> getWildCardPath() {
64 return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
69 protected void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntryDeleted) {
70 LOG.debug("VrfEntry removed: id={} vrfEntry=[ destination={}, route-paths=[{}]]",
71 identifier, vrfEntryDeleted.getDestPrefix(), vrfEntryDeleted.getRoutePaths());
72 String vpnRd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
73 programLabelInAllVpnDpns(vpnRd, vrfEntryDeleted, NwConstants.DEL_FLOW);
77 protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
78 LOG.debug("VrfEntry updated: id={} vrfEntry=[ destination={}, route-paths=[{}]]",
79 identifier, update.getDestPrefix(), update.getRoutePaths());
80 List<Long> originalLabels = getUniqueLabelList(original);
81 List<Long> updateLabels = getUniqueLabelList(update);
82 if (!updateLabels.equals(originalLabels)) {
83 remove(identifier, original);
84 add(identifier, update);
89 protected void add(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntryAdded) {
90 LOG.debug("VrfEntry added: id={} vrfEntry=[ destination={}, route-paths=[{}]]",
91 identifier, vrfEntryAdded.getDestPrefix(), vrfEntryAdded.getRoutePaths());
92 String vpnRd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
93 programLabelInAllVpnDpns(vpnRd, vrfEntryAdded, NwConstants.ADD_FLOW);
97 * Adds or Removes a VPN's route in all the DPNs where the VPN has footprint.
99 * @param vpnRd Route-Distinguisher of the VPN
100 * @param vrfEntry The route to add or remove
101 * @param addOrRemove States if the route must be added or removed
103 protected void programLabelInAllVpnDpns(String vpnRd, VrfEntry vrfEntry, int addOrRemove) {
104 Long vpnPseudoLPortTag = vpnPseudoPortCache.get(vpnRd);
105 if (vpnPseudoLPortTag == null) {
106 LOG.debug("Vpn with rd={} not related to any VpnPseudoPort", vpnRd);
110 Optional<VpnInstanceOpDataEntry> vpnOpData = VpnServiceChainUtils.getVpnInstanceOpData(broker, vpnRd);
111 if (! vpnOpData.isPresent()) {
112 if (addOrRemove == NwConstants.ADD_FLOW) {
113 LOG.error("VrfEntry added: Could not find operational data for VPN with RD={}", vpnRd);
115 LOG.warn("VrfEntry removed: No Operational data found for VPN with RD={}. No further action", vpnRd);
121 Collection<VpnToDpnList> vpnToDpnList = vpnOpData.get().getVpnToDpnList();
122 if (vpnToDpnList == null || vpnToDpnList.isEmpty()) {
123 LOG.warn("Empty VpnToDpnlist found in Operational for VPN with RD={}. No label will be {}",
124 vpnRd, addOrRemove == NwConstants.ADD_FLOW ? "programmed" : "cleaned");
128 for (VpnToDpnList dpnInVpn : vpnToDpnList) {
129 BigInteger dpnId = dpnInVpn.getDpnId();
130 VpnServiceChainUtils.programLFibEntriesForSCF(mdsalMgr, dpnId, Collections.singletonList(vrfEntry),
131 (int) vpnPseudoLPortTag.longValue(), addOrRemove);
135 private List<Long> getUniqueLabelList(VrfEntry original) {
136 List<RoutePaths> vrfRoutePaths = original.getRoutePaths();
137 if (vrfRoutePaths == null || vrfRoutePaths.isEmpty()) {
138 return Collections.emptyList();
141 return vrfRoutePaths.stream()
142 .filter(rPath -> rPath.getLabel() != null).map(RoutePaths::getLabel)
143 .distinct().sorted().collect(Collectors.toList());
147 protected VrfListener getDataTreeChangeListener() {
148 return VrfListener.this;