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