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