1164671f87140fabc39b648769975574b0fd363b
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / FibEntriesListener.java
1 /*
2  * Copyright (c) 2015 - 2016 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 static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
11
12 import java.util.ArrayList;
13 import java.util.List;
14 import java.util.stream.Collectors;
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.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
21 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
22 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
23 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryBuilder;
31 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
32 import org.opendaylight.yangtools.yang.common.Uint32;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 @Singleton
37 public class FibEntriesListener extends AsyncDataTreeChangeListenerBase<VrfEntry, FibEntriesListener> {
38     private static final Logger LOG = LoggerFactory.getLogger(FibEntriesListener.class);
39     private final DataBroker dataBroker;
40     private final ManagedNewTransactionRunner txRunner;
41     private final VpnInstanceListener vpnInstanceListener;
42
43     @Inject
44     public FibEntriesListener(final DataBroker dataBroker, final VpnInstanceListener vpnInstanceListener) {
45         super(VrfEntry.class, FibEntriesListener.class);
46         this.dataBroker = dataBroker;
47         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
48         this.vpnInstanceListener = vpnInstanceListener;
49     }
50
51     @PostConstruct
52     public void start() {
53         LOG.info("{} start", getClass().getSimpleName());
54         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
55     }
56
57     @Override
58     protected InstanceIdentifier<VrfEntry> getWildCardPath() {
59         return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
60     }
61
62     @Override
63     protected FibEntriesListener getDataTreeChangeListener() {
64         return FibEntriesListener.this;
65     }
66
67
68     @Override
69     protected void remove(InstanceIdentifier<VrfEntry> identifier,
70         VrfEntry del) {
71         LOG.trace("Remove Fib event - Key : {}, value : {} ", identifier, del);
72         final VrfTablesKey key = identifier.firstKeyOf(VrfTables.class);
73         String rd = key.getRouteDistinguisher();
74         List<RoutePaths> routePaths = del.getRoutePaths();
75         removeLabelFromVpnInstance(rd, routePaths);
76     }
77
78     @Override
79     protected void update(InstanceIdentifier<VrfEntry> identifier,
80         VrfEntry original, VrfEntry update) {
81         final VrfTablesKey key = identifier.firstKeyOf(VrfTables.class);
82         String rd = key.getRouteDistinguisher();
83         List<RoutePaths> originalRoutePaths = new ArrayList<>(original.getRoutePaths());
84         List<RoutePaths> updateRoutePaths = new ArrayList<>(update.getRoutePaths());
85         if (originalRoutePaths.size() < updateRoutePaths.size()) {
86             updateRoutePaths.removeAll(originalRoutePaths);
87             addLabelToVpnInstance(rd, updateRoutePaths);
88         } else if (originalRoutePaths.size() > updateRoutePaths.size()) {
89             originalRoutePaths.removeAll(updateRoutePaths);
90             removeLabelFromVpnInstance(rd, originalRoutePaths);
91         }
92     }
93
94     @Override
95     protected void add(InstanceIdentifier<VrfEntry> identifier,
96         VrfEntry add) {
97         LOG.trace("Add Vrf Entry event - Key : {}, value : {}", identifier, add);
98         final VrfTablesKey key = identifier.firstKeyOf(VrfTables.class);
99         String rd = key.getRouteDistinguisher();
100         addLabelToVpnInstance(rd, add.getRoutePaths());
101     }
102
103     private void addLabelToVpnInstance(String rd, List<RoutePaths> routePaths) {
104         List<Uint32> labels = routePaths.stream().map(RoutePaths::getLabel).distinct()
105                             .collect(Collectors.toList());
106         VpnInstanceOpDataEntry vpnInstanceOpData = vpnInstanceListener.getVpnInstanceOpData(rd);
107         if (vpnInstanceOpData != null) {
108             List<Uint32> routeIds = vpnInstanceOpData.getRouteEntryId() == null ? new ArrayList<>()
109                     : vpnInstanceOpData.getRouteEntryId();
110             labels.forEach(label -> {
111                 LOG.debug("Adding label to vpn info - {}", label);
112                 if (!routeIds.contains(label)) {
113                     routeIds.add(label);
114                 }
115             });
116             ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx ->
117                             tx.put(VpnUtil.getVpnInstanceOpDataIdentifier(rd),
118                                     new VpnInstanceOpDataEntryBuilder(vpnInstanceOpData).setRouteEntryId(routeIds)
119                                             .build())),
120                     LOG, "Error adding label to VPN instance");
121         } else {
122             LOG.warn("No VPN Instance found for RD: {}", rd);
123         }
124     }
125
126     private void removeLabelFromVpnInstance(String rd, List<RoutePaths> routePaths) {
127         List<Uint32> labels = routePaths.stream().map(RoutePaths::getLabel).distinct()
128                 .collect(Collectors.toList());
129         VpnInstanceOpDataEntry vpnInstanceOpData = vpnInstanceListener.getVpnInstanceOpData(rd);
130         if (vpnInstanceOpData != null) {
131             List<Uint32> routeIds = vpnInstanceOpData.getRouteEntryId();
132             if (routeIds == null) {
133                 LOG.debug("Fib Route entry is empty.");
134             } else {
135                 LOG.debug("Removing label from vpn info - {}", labels);
136                 routeIds.removeAll(labels);
137                 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx ->
138                                 tx.put(VpnUtil.getVpnInstanceOpDataIdentifier(rd),
139                                         new VpnInstanceOpDataEntryBuilder(vpnInstanceOpData).setRouteEntryId(routeIds)
140                                                 .build())),
141                         LOG, "Error removing label from VPN instance");
142             }
143         } else {
144             LOG.warn("No VPN Instance found for RD: {}", rd);
145         }
146     }
147 }