Merge "Add ovsdb/netvirt ui to vpnservice netvirt code."
[netvirt.git] / vpnservice / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / netvirt / vpnmanager / TunnelInterfaceStateListener.java
1 /*
2  * Copyright (c) 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 com.google.common.base.Optional;
11 import java.math.BigInteger;
12 import java.util.Iterator;
13 import java.util.List;
14 import java.util.concurrent.Future;
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
17 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
20 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
21 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
22 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
23 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
24 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentInputBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentOutput;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
37 import org.opendaylight.yangtools.concepts.ListenerRegistration;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.opendaylight.yangtools.yang.common.RpcResult;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 public class TunnelInterfaceStateListener extends AbstractDataChangeListener<StateTunnelList>
44         implements AutoCloseable{
45     private static final Logger LOG = LoggerFactory.getLogger(TunnelInterfaceStateListener.class);
46     private ListenerRegistration<DataChangeListener> listenerRegistration;
47     private final DataBroker dataBroker;
48     private final IBgpManager bgpManager;
49     private IFibManager fibManager;
50     private ItmRpcService itmRpcService;
51     protected enum UpdateRouteAction {
52         ADVERTISE_ROUTE, WITHDRAW_ROUTE
53     }
54
55     /**
56      * Responsible for listening to tunnel interface state change
57      *
58      * @param dataBroker dataBroker
59      * @param bgpManager bgpManager
60      * @param fibManager fibManager
61      * @param itmRpcService itmRpcService
62      */
63     public TunnelInterfaceStateListener(final DataBroker dataBroker,
64                                         final IBgpManager bgpManager,
65                                         final IFibManager fibManager,
66                                         final ItmRpcService itmRpcService) {
67         super(StateTunnelList.class);
68         this.dataBroker = dataBroker;
69         this.bgpManager = bgpManager;
70         this.fibManager = fibManager;
71         this.itmRpcService = itmRpcService;
72     }
73
74     public void start() {
75         LOG.info("{} start", getClass().getSimpleName());
76         listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
77                 getWildCardPath(), this, AsyncDataBroker.DataChangeScope.SUBTREE);
78     }
79
80     private InstanceIdentifier<StateTunnelList> getWildCardPath() {
81         return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
82     }
83
84     @Override
85     public void close() throws Exception {
86         if (listenerRegistration != null) {
87             listenerRegistration.close();
88             listenerRegistration = null;
89         }
90         LOG.info("{} close", getClass().getSimpleName());
91     }
92
93     @Override
94     protected void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
95         LOG.trace("Tunnel deletion---- {}", del);
96         handlePrefixesForDPNs(del, UpdateRouteAction.WITHDRAW_ROUTE);
97     }
98
99     @Override
100     protected void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original, StateTunnelList update) {
101         LOG.trace("Tunnel updation---- {}", update);
102         LOG.trace("ITM Tunnel {} of type {} state event changed from :{} to :{}",
103                 update.getTunnelInterfaceName(),
104                 fibManager.getTransportTypeStr(update.getTransportType().toString()),
105                 original.isTunnelState(), update.isTunnelState());
106         //withdraw all prefixes in all vpns for this dpn
107         boolean isTunnelUp = update.isTunnelState();
108         handlePrefixesForDPNs(update, isTunnelUp ? UpdateRouteAction.ADVERTISE_ROUTE :
109                 UpdateRouteAction.WITHDRAW_ROUTE);
110     }
111
112     @Override
113     protected void add(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList add) {
114         LOG.trace("Tunnel addition---- {}", add);
115
116         if (!add.isTunnelState()) {
117             LOG.trace("Tunnel {} is not yet UP.",
118                     add.getTunnelInterfaceName());
119             return;
120         } else {
121             LOG.trace("ITM Tunnel ,type {} ,State is UP b/w src: {} and dest: {}",
122                     fibManager.getTransportTypeStr(add.getTransportType().toString()),
123                     add.getSrcInfo().getTepDeviceId(), add.getDstInfo().getTepDeviceId());
124             handlePrefixesForDPNs(add, UpdateRouteAction.ADVERTISE_ROUTE);
125         }
126     }
127
128     private void handlePrefixesForDPNs(StateTunnelList stateTunnelList, UpdateRouteAction action) {
129         BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
130         BigInteger destDpnId;
131         String srcTepIp = String.valueOf(stateTunnelList.getSrcInfo().getTepIp().getValue());
132         String destTepIp = String.valueOf(stateTunnelList.getDstInfo().getTepIp().getValue());
133
134         InstanceIdentifier.InstanceIdentifierBuilder<VpnInstances> idBuilder = InstanceIdentifier.builder(VpnInstances.class);
135         InstanceIdentifier<VpnInstances> vpnInstancesId = idBuilder.build();
136         Optional<VpnInstances> vpnInstances = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnInstancesId);
137         long tunTypeVal = 0, vpnId;
138
139         if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
140             tunTypeVal = VpnConstants.ITMTunnelLocType.Internal.getValue();
141         } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
142             tunTypeVal = VpnConstants.ITMTunnelLocType.External.getValue();
143         } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
144             tunTypeVal = VpnConstants.ITMTunnelLocType.Hwvtep.getValue();
145         } else {
146             tunTypeVal = VpnConstants.ITMTunnelLocType.Invalid.getValue();
147         }
148         LOG.trace("tunTypeVal is {}", tunTypeVal);
149
150         long dcgwPresentStatus = VpnConstants.DCGWPresentStatus.Invalid.getValue();
151         if (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) {
152             Future<RpcResult<IsDcgwPresentOutput>> result;
153             try {
154                 result = itmRpcService.isDcgwPresent(new IsDcgwPresentInputBuilder()
155                         .setDcgwIp(destTepIp)
156                         .build());
157                 RpcResult<IsDcgwPresentOutput> rpcResult = result.get();
158                 if (!rpcResult.isSuccessful()) {
159                     LOG.warn("RPC Call to isDcgwPresent {} returned with Errors {}", destTepIp, rpcResult.getErrors());
160                 } else {
161                     dcgwPresentStatus = rpcResult.getResult().getRetVal();
162                 }
163             } catch (Exception e) {
164                 LOG.warn("Exception {} when querying for isDcgwPresent {}, trace {}", e, destTepIp, e.getStackTrace());
165             }
166         }
167
168         if (vpnInstances.isPresent()) {
169             List<VpnInstance> vpnInstanceList = vpnInstances.get().getVpnInstance();
170             Iterator<VpnInstance> vpnInstIter = vpnInstanceList.iterator();
171             LOG.trace("vpnInstIter {}", vpnInstIter);
172             while (vpnInstIter.hasNext()) {
173                 VpnInstance vpnInstance = vpnInstIter.next();
174                 LOG.trace("vpnInstance {}", vpnInstance);
175                 vpnId = VpnUtil.getVpnId(dataBroker, vpnInstance.getVpnInstanceName());
176                 try {
177                     VpnAfConfig vpnConfig = vpnInstance.getIpv4Family();
178                     LOG.trace("vpnConfig {}", vpnConfig);
179                     String rd = vpnConfig.getRouteDistinguisher();
180                     if (rd == null || rd.isEmpty()) {
181                         rd = vpnInstance.getVpnInstanceName();
182                         LOG.trace("rd is null or empty. Assigning VpnInstanceName to rd {}", rd);
183                     }
184                     InstanceIdentifier<VpnToDpnList> srcId =
185                             VpnUtil.getVpnToDpnListIdentifier(rd, srcDpnId);
186                     Optional<VpnToDpnList> srcDpnInVpn =
187                             VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, srcId);
188                     if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
189                         destDpnId = new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId());
190                         InstanceIdentifier<VpnToDpnList> destId =
191                                 VpnUtil.getVpnToDpnListIdentifier(rd, destDpnId);
192                         Optional<VpnToDpnList> destDpnInVpn =
193                                 VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, destId);
194                         if (!(srcDpnInVpn.isPresent() &&
195                                 destDpnInVpn.isPresent())) {
196                             LOG.trace(" srcDpn {} - destDPN {}, do not share the VPN {} with rd {}.",
197                                     srcDpnId, destDpnId, vpnInstance.getVpnInstanceName(), rd);
198                             continue;
199                         }
200                     }
201                     if (srcDpnInVpn.isPresent()) {
202                         List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
203                                 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces>
204                                 vpnInterfaces = srcDpnInVpn.get().getVpnInterfaces();
205                         for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
206                                 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces vpnInterface : vpnInterfaces) {
207                             InstanceIdentifier<VpnInterface> vpnIntfId =
208                                     VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getInterfaceName());
209                             LOG.trace("vpnInterface {}", vpnInterface);
210                             InstanceIdentifier<Adjacencies> path =
211                                     vpnIntfId.augmentation(Adjacencies.class);
212                             Optional<Adjacencies> adjacencies =
213                                     VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, path);
214                             LOG.trace("adjacencies {}", adjacencies);
215                             if (adjacencies.isPresent()) {
216                                 List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
217                                 Iterator<Adjacency> adjacencyIterator = adjacencyList.iterator();
218
219                                 while (adjacencyIterator.hasNext()) {
220                                     Adjacency adjacency = adjacencyIterator.next();
221                                     try {
222                                         if (action == UpdateRouteAction.ADVERTISE_ROUTE) {
223                                             LOG.info("VPNInterfaceManager : Added Fib Entry rd {} prefix {} nextHop {} label {}",
224                                                     rd, adjacency.getIpAddress(), adjacency.getNextHopIpList(),
225                                                     adjacency.getLabel());
226 //                                            vrf = new VrfEntryBuilder().set
227                                             if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
228                                                 fibManager.handleRemoteRoute(true,
229                                                         new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId()),
230                                                         new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId()),
231                                                         VpnUtil.getVpnId(dataBroker, vpnInstance.getVpnInstanceName()),
232                                                         rd, adjacency.getIpAddress(), srcTepIp, destTepIp);
233                                             }
234                                             if (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) {
235                                                 fibManager.populateFibOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
236                                             }
237                                         } else if (action == UpdateRouteAction.WITHDRAW_ROUTE) {
238                                             LOG.info("VPNInterfaceManager : Removed Fib entry rd {} prefix {}",
239                                                     rd, adjacency.getIpAddress());
240                                             if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
241                                                 fibManager.handleRemoteRoute(false, srcDpnId,
242                                                         new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId()),
243                                                         vpnId, rd, adjacency.getIpAddress(), srcTepIp, destTepIp);
244                                             }
245                                             if ((tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) &&
246                                                     (dcgwPresentStatus == VpnConstants.DCGWPresentStatus.Absent.getValue())) {                                                bgpManager.withdrawPrefix(rd, adjacency.getIpAddress());
247                                                 fibManager.cleanUpDpnForVpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
248                                             }
249                                         }
250                                     } catch (Exception e) {
251                                         LOG.error("Exception when updating prefix {} in vrf {} to BGP",
252                                                 adjacency.getIpAddress(), rd);
253                                     }
254                                 }
255                             } else {
256                                 LOG.trace("no adjacencies present for path {}.", path);
257                             }
258                         }
259                         // if (action == UpdateRouteAction.WITHDRAW_ROUTE) {
260                         //    fibManager.cleanUpDpnForVpn(dpnId, VpnUtil.getVpnId(dataBroker, vpnInstance.getVpnInstanceName()), rd);
261                         // }
262                         // Go through all the VrfEntries and withdraw and readvertise the prefixes to BGP for which the nextHop is the SrcTepIp
263                         if ((action == UpdateRouteAction.ADVERTISE_ROUTE) &&
264                                 (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue())) {
265                             List<VrfEntry> vrfEntries = VpnUtil.getAllVrfEntries(dataBroker, rd);
266                             if (vrfEntries != null) {
267                                 for (VrfEntry vrfEntry : vrfEntries) {
268                                     String destPrefix = vrfEntry.getDestPrefix().trim();
269                                     int vpnLabel = vrfEntry.getLabel().intValue();
270                                     List<String> nextHops = vrfEntry.getNextHopAddressList();
271                                     if (nextHops.contains(srcTepIp.trim())) {
272                                         bgpManager.withdrawPrefix(rd, destPrefix);
273                                         bgpManager.advertisePrefix(rd, destPrefix, nextHops, vpnLabel);
274                                     }
275                                 }
276                             }
277                         }
278                     } else {
279                         LOG.trace("dpnInVpn check failed for srcDpnId {}.", srcDpnId);
280                     }
281                 } catch (Exception e) {
282                     LOG.error("updatePrefixesForDPN {} in vpn {} failed", 0, vpnInstance.getVpnInstanceName(), e);
283                 }
284             }
285         } else {
286             LOG.trace("No vpn instances present.");
287         }
288     }
289 }