c360f1585486a4252e68eb03e30a330f7769d0ed
[netvirt.git] / 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 import java.util.Collections;
13 import java.util.List;
14 import javax.annotation.PostConstruct;
15 import javax.inject.Inject;
16 import javax.inject.Singleton;
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.genius.interfacemanager.globals.InterfaceServiceUtil;
21 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
22 import org.opendaylight.genius.mdsalutil.MDSALUtil;
23 import org.opendaylight.genius.mdsalutil.NwConstants;
24 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
25 import org.opendaylight.netvirt.policyservice.PolicyRouteFlowProgrammer;
26 import org.opendaylight.netvirt.policyservice.PolicyServiceConstants;
27 import org.opendaylight.netvirt.policyservice.util.PolicyServiceUtil;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeLogicalGroup;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeEgress;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepInfoAttributes;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.policy.profiles.PolicyProfile;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay.network.DpnToInterface;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 /**
44  * Listen on operational {@link StateTunnelList} changes and update
45  * {@link DpnToInterface} accordingly for tunnel interfaces of type VxLAN.<br>
46  * When logical tunnel interface state is added or removed, the corresponding
47  * POLICY_ROUTING_TABLE entries will be updated and the policy service will be
48  * bounded/unbounded.
49  *
50  */
51 @Singleton
52 public class TunnelStateChangeListener
53         extends AsyncDataTreeChangeListenerBase<StateTunnelList, TunnelStateChangeListener> {
54     private static final Logger LOG = LoggerFactory.getLogger(TunnelStateChangeListener.class);
55
56     private final DataBroker dataBroker;
57     private final PolicyServiceUtil policyServiceUtil;
58     private final PolicyRouteFlowProgrammer routeFlowProgrammer;
59     private final IInterfaceManager interfaceManager;
60     private final JobCoordinator coordinator;
61
62     @Inject
63     public TunnelStateChangeListener(DataBroker dataBroker, final PolicyServiceUtil policyServiceUtil,
64             final PolicyRouteFlowProgrammer routeFlowProgrammer, final IInterfaceManager interfaceManager,
65             final JobCoordinator coordinator) {
66         this.dataBroker = dataBroker;
67         this.policyServiceUtil = policyServiceUtil;
68         this.routeFlowProgrammer = routeFlowProgrammer;
69         this.interfaceManager = interfaceManager;
70         this.coordinator = coordinator;
71     }
72
73     @Override
74     @PostConstruct
75     public void init() {
76         LOG.info("init");
77         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
78     }
79
80     @Override
81     protected InstanceIdentifier<StateTunnelList> getWildCardPath() {
82         return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
83     }
84
85     @Override
86     protected TunnelStateChangeListener getDataTreeChangeListener() {
87         return this;
88     }
89
90     @Override
91     protected void remove(InstanceIdentifier<StateTunnelList> key, StateTunnelList tunnelState) {
92         LOG.debug("Tunnel state {} removed", tunnelState);
93         if (isLogicalGroupTunnel(tunnelState)) {
94             unbindService(tunnelState.getTunnelInterfaceName());
95             populatePolicyRoutesToDpn(tunnelState, NwConstants.DEL_FLOW);
96         } else if (isVxlanTunnel(tunnelState)) {
97             updateTunnelToUnderlayNetworkOperDs(tunnelState, false);
98         }
99     }
100
101     @Override
102     protected void update(InstanceIdentifier<StateTunnelList> key, StateTunnelList origTunnelState,
103             StateTunnelList updtedTunnelState) {
104     }
105
106     @Override
107     protected void add(InstanceIdentifier<StateTunnelList> key, StateTunnelList tunnelState) {
108         LOG.trace("Tunnel state {} added", tunnelState);
109         if (isVxlanTunnel(tunnelState)) {
110             updateTunnelToUnderlayNetworkOperDs(tunnelState, true);
111         } else if (isLogicalGroupTunnel(tunnelState)) {
112             bindService(tunnelState.getTunnelInterfaceName());
113             populatePolicyRoutesToDpn(tunnelState, NwConstants.ADD_FLOW);
114         }
115     }
116
117     private void populatePolicyRoutesToDpn(StateTunnelList tunnelState, int addOrRemove) {
118         BigInteger srcDpId = getTepDpnId(tunnelState.getSrcInfo());
119         BigInteger dstDpId = getTepDpnId(tunnelState.getDstInfo());
120         String tunnelInterfaceName = tunnelState.getTunnelInterfaceName();
121         if (BigInteger.ZERO.equals(srcDpId) || BigInteger.ZERO.equals(dstDpId)) {
122             LOG.warn("No valid DPN found for logical tunnel {}", tunnelInterfaceName);
123             return;
124         }
125
126         List<PolicyProfile> policyProfiles = policyServiceUtil.getAllPolicyProfiles();
127         if (policyProfiles == null || policyProfiles.isEmpty()) {
128             LOG.debug("No policy profiles found on addition of {}", tunnelInterfaceName);
129             return;
130         }
131
132         policyProfiles.forEach(policyProfile -> {
133             String policyClassifier = policyProfile.getPolicyClassifier();
134             List<String> underlayNetworks = PolicyServiceUtil
135                     .getUnderlayNetworksFromPolicyRoutes(policyProfile.getPolicyRoute());
136             underlayNetworks.forEach(underlayNetwork -> {
137                 if (policyServiceUtil.underlayNetworkContainsDpn(underlayNetwork, srcDpId)
138                         && policyServiceUtil.underlayNetworkContainsRemoteDpn(underlayNetwork, dstDpId)) {
139                     routeFlowProgrammer.programPolicyClassifierFlow(policyClassifier, srcDpId, dstDpId, addOrRemove,
140                             true);
141                 } else {
142                     LOG.trace("logical tunnel {} source DPN {} dest DPN {} not associated to policy classifier {}",
143                             tunnelInterfaceName, srcDpId, dstDpId, policyClassifier);
144                 }
145             });
146         });
147     }
148
149     private void updateTunnelToUnderlayNetworkOperDs(StateTunnelList tunnelState, boolean isAdded) {
150         BigInteger srcDpId = getTepDpnId(tunnelState.getSrcInfo());
151         BigInteger dstDpId = getTepDpnId(tunnelState.getDstInfo());
152         String tunnelInterfaceName = tunnelState.getTunnelInterfaceName();
153         if (BigInteger.ZERO.equals(srcDpId) || BigInteger.ZERO.equals(dstDpId)) {
154             LOG.warn("No valid DPN found for tunnel {}", tunnelInterfaceName);
155             return;
156         }
157
158         IpAddress tunnelIp = getTunnelIp(tunnelState);
159         if (tunnelIp == null) {
160             LOG.warn("No tunnel ip found for tunnel {} DPN {}", tunnelInterfaceName, srcDpId);
161             return;
162         }
163
164         String underlayNetwork = policyServiceUtil.getTunnelUnderlayNetwork(srcDpId, tunnelIp);
165         if (underlayNetwork == null) {
166             LOG.debug("No underlay networks defined for tunnel {} DPN {}", tunnelInterfaceName, srcDpId);
167             return;
168         }
169
170         LOG.info("Handle tunnel state update for interface {} on DPN {} underlay network {}", tunnelInterfaceName,
171                 srcDpId, underlayNetwork);
172         policyServiceUtil.updateTunnelInterfaceForUnderlayNetwork(underlayNetwork, srcDpId, dstDpId,
173                 tunnelInterfaceName, isAdded);
174     }
175
176     private void bindService(String tunnelInterfaceName) {
177         coordinator.enqueueJob(tunnelInterfaceName, () -> {
178             LOG.info("Bind egress policy service on tunnel {}", tunnelInterfaceName);
179             List<Instruction> instructions = Collections.singletonList(
180                     MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.EGRESS_POLICY_CLASSIFIER_TABLE, 0));
181             BoundServices boundServices = getBoundServices(tunnelInterfaceName, instructions);
182             interfaceManager.bindService(tunnelInterfaceName, ServiceModeEgress.class, boundServices);
183             return null;
184         });
185     }
186
187     private void unbindService(String tunnelInterfaceName) {
188         coordinator.enqueueJob(tunnelInterfaceName, () -> {
189             LOG.info("Unbind egress policy service on tunnel {}", tunnelInterfaceName);
190             BoundServices boundServices = getBoundServices(tunnelInterfaceName, Collections.emptyList());
191             interfaceManager.unbindService(tunnelInterfaceName, ServiceModeEgress.class, boundServices);
192             return null;
193         });
194     }
195
196     private static BoundServices getBoundServices(String tunnelInterfaceName, List<Instruction> instructions) {
197         BoundServices boundServices = InterfaceServiceUtil.getBoundServices(tunnelInterfaceName,
198                 NwConstants.EGRESS_POLICY_SERVICE_INDEX, PolicyServiceConstants.POLICY_DEFAULT_DISPATCHER_FLOW_PRIORITY,
199                 NwConstants.EGRESS_POLICY_CLASSIFIER_COOKIE, instructions);
200         return boundServices;
201     }
202
203     private static boolean isVxlanTunnel(StateTunnelList tunnelState) {
204         return tunnelState.getTransportType() != null
205                 && tunnelState.getTransportType().isAssignableFrom(TunnelTypeVxlan.class);
206     }
207
208     private static boolean isLogicalGroupTunnel(StateTunnelList tunnelState) {
209         return tunnelState.getTransportType() != null
210                 && tunnelState.getTransportType().isAssignableFrom(TunnelTypeLogicalGroup.class);
211     }
212
213     private static BigInteger getTepDpnId(TepInfoAttributes tepInfoAttributes) {
214         if (tepInfoAttributes != null && tepInfoAttributes.getTepDeviceId() != null) {
215             return new BigInteger(tepInfoAttributes.getTepDeviceId());
216         }
217
218         return BigInteger.ZERO;
219     }
220
221     private static IpAddress getTunnelIp(StateTunnelList tunnelState) {
222         return tunnelState.getSrcInfo() != null ? tunnelState.getSrcInfo().getTepIp() : null;
223     }
224 }