2 * Copyright (c) 2017 Hewlett Packard Enterprise, Co. and others. All rights reserved.
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
9 package org.opendaylight.netvirt.policyservice.listeners;
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;
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
52 public class TunnelStateChangeListener
53 extends AsyncDataTreeChangeListenerBase<StateTunnelList, TunnelStateChangeListener> {
54 private static final Logger LOG = LoggerFactory.getLogger(TunnelStateChangeListener.class);
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;
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;
77 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
81 protected InstanceIdentifier<StateTunnelList> getWildCardPath() {
82 return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
86 protected TunnelStateChangeListener getDataTreeChangeListener() {
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);
102 protected void update(InstanceIdentifier<StateTunnelList> key, StateTunnelList origTunnelState,
103 StateTunnelList updtedTunnelState) {
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);
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);
126 List<PolicyProfile> policyProfiles = policyServiceUtil.getAllPolicyProfiles();
127 if (policyProfiles == null || policyProfiles.isEmpty()) {
128 LOG.debug("No policy profiles found on addition of {}", tunnelInterfaceName);
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,
142 LOG.trace("logical tunnel {} source DPN {} dest DPN {} not associated to policy classifier {}",
143 tunnelInterfaceName, srcDpId, dstDpId, policyClassifier);
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);
158 IpAddress tunnelIp = getTunnelIp(tunnelState);
159 if (tunnelIp == null) {
160 LOG.warn("No tunnel ip found for tunnel {} DPN {}", tunnelInterfaceName, srcDpId);
164 String underlayNetwork = policyServiceUtil.getTunnelUnderlayNetwork(srcDpId, tunnelIp);
165 if (underlayNetwork == null) {
166 LOG.debug("No underlay networks defined for tunnel {} DPN {}", tunnelInterfaceName, srcDpId);
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);
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);
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);
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;
203 private static boolean isVxlanTunnel(StateTunnelList tunnelState) {
204 return tunnelState.getTransportType() != null
205 && tunnelState.getTransportType().isAssignableFrom(TunnelTypeVxlan.class);
208 private static boolean isLogicalGroupTunnel(StateTunnelList tunnelState) {
209 return tunnelState.getTransportType() != null
210 && tunnelState.getTransportType().isAssignableFrom(TunnelTypeLogicalGroup.class);
213 private static BigInteger getTepDpnId(TepInfoAttributes tepInfoAttributes) {
214 if (tepInfoAttributes != null && tepInfoAttributes.getTepDeviceId() != null) {
215 return new BigInteger(tepInfoAttributes.getTepDeviceId());
218 return BigInteger.ZERO;
221 private static IpAddress getTunnelIp(StateTunnelList tunnelState) {
222 return tunnelState.getSrcInfo() != null ? tunnelState.getSrcInfo().getTepIp() : null;