Fix NPE if underlay network is missing from TEP
[netvirt.git] / vpnservice / policyservice / impl / src / main / java / org / opendaylight / netvirt / policyservice / listeners / TunnelStateChangeListener.java
1 /*
2  * Copyright (c) 2017 Hewlett Packard Enterprise, Co. 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.policyservice.listeners;
10
11 import java.math.BigInteger;
12
13 import javax.annotation.PostConstruct;
14 import javax.inject.Inject;
15 import javax.inject.Singleton;
16
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
20 import org.opendaylight.netvirt.policyservice.util.PolicyServiceUtil;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay.network.DpnToInterface;
26 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 /**
31  * Listen on operational {@link StateTunnelList} changes and update
32  * {@link DpnToInterface} accordingly for tunnel interfaces of type VxLAN.
33  *
34  */
35 @Singleton
36 public class TunnelStateChangeListener
37         extends AsyncDataTreeChangeListenerBase<StateTunnelList, TunnelStateChangeListener> {
38     private static final Logger LOG = LoggerFactory.getLogger(TunnelStateChangeListener.class);
39
40     private final DataBroker dataBroker;
41     private final PolicyServiceUtil policyServiceUtil;
42
43     @Inject
44     public TunnelStateChangeListener(DataBroker dataBroker, final PolicyServiceUtil policyServiceUtil) {
45         this.dataBroker = dataBroker;
46         this.policyServiceUtil = policyServiceUtil;
47     }
48
49     @Override
50     @PostConstruct
51     public void init() {
52         LOG.info("init");
53         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
54     }
55
56     @Override
57     protected InstanceIdentifier<StateTunnelList> getWildCardPath() {
58         return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
59     }
60
61     @Override
62     protected TunnelStateChangeListener getDataTreeChangeListener() {
63         return this;
64     }
65
66     @Override
67     protected void remove(InstanceIdentifier<StateTunnelList> key, StateTunnelList tunnelState) {
68         LOG.debug("Tunnel state {} removed", tunnelState);
69         handleTunnelUpdate(tunnelState, false);
70     }
71
72     @Override
73     protected void update(InstanceIdentifier<StateTunnelList> key, StateTunnelList origTunnelState,
74             StateTunnelList updtedTunnelState) {
75     }
76
77     @Override
78     protected void add(InstanceIdentifier<StateTunnelList> key, StateTunnelList tunnelState) {
79         LOG.debug("Tunnel state {} added", tunnelState);
80         handleTunnelUpdate(tunnelState, true);
81     }
82
83     private void handleTunnelUpdate(StateTunnelList tunnelState, boolean isAdded) {
84         if (!isVxlanTunnel(tunnelState)) {
85             return;
86         }
87
88         BigInteger dpnId = getTunnelDpnId(tunnelState);
89         String tunnelInterfaceName = tunnelState.getTunnelInterfaceName();
90         if (BigInteger.ZERO.equals(dpnId)) {
91             LOG.warn("No valid DPN found for tunnel {}", tunnelInterfaceName);
92             return;
93         }
94
95         IpAddress tunnelIp = getTunnelIp(tunnelState);
96         if (tunnelIp == null) {
97             LOG.warn("No tunnel ip found for tunnel {} DPN {}", tunnelInterfaceName, dpnId);
98             return;
99         }
100
101         String underlayNetwork = policyServiceUtil.getTunnelUnderlayNetwork(dpnId, tunnelIp);
102         if (underlayNetwork == null) {
103             LOG.debug("No underlay networks defined for tunnel {} DPN {}", tunnelInterfaceName, dpnId);
104             return;
105         }
106
107         LOG.info("Handle tunnel state update for interface {} on DPN {} underlay network", tunnelInterfaceName, dpnId,
108                 underlayNetwork);
109         policyServiceUtil.updateTunnelInterfaceForUnderlayNetwork(underlayNetwork, dpnId, tunnelInterfaceName, isAdded);
110     }
111
112     private static boolean isVxlanTunnel(StateTunnelList tunnelState) {
113         return tunnelState.getTransportType() != null
114                 && tunnelState.getTransportType().isAssignableFrom(TunnelTypeVxlan.class);
115     }
116
117     private static BigInteger getTunnelDpnId(StateTunnelList tunnelState) {
118         if (tunnelState.getSrcInfo() != null && tunnelState.getSrcInfo().getTepDeviceId() != null) {
119             return new BigInteger(tunnelState.getSrcInfo().getTepDeviceId());
120         }
121
122         return BigInteger.ZERO;
123     }
124
125     private static IpAddress getTunnelIp(StateTunnelList tunnelState) {
126         return tunnelState.getSrcInfo() != null ? tunnelState.getSrcInfo().getTepIp() : null;
127     }
128 }