MRI version bumpup for Aluminium
[netvirt.git] / elanmanager / impl / src / main / java / org / opendaylight / netvirt / elan / utils / ElanItmUtils.java
1 /*
2  * Copyright © 2017 Red Hat, Inc. and others.
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.elan.utils;
9
10 import java.util.ArrayList;
11 import java.util.Collections;
12 import java.util.List;
13 import java.util.concurrent.ExecutionException;
14 import java.util.concurrent.Future;
15 import javax.inject.Inject;
16 import javax.inject.Singleton;
17 import org.eclipse.jdt.annotation.Nullable;
18 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
19 import org.opendaylight.mdsal.binding.api.DataBroker;
20 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
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.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInput;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetEgressActionsForTunnelInput;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetEgressActionsForTunnelInputBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetEgressActionsForTunnelOutput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameInput;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameInputBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameOutput;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
43 import org.opendaylight.yangtools.yang.common.RpcResult;
44 import org.opendaylight.yangtools.yang.common.Uint64;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48 @Singleton
49 public class ElanItmUtils {
50     private static final Logger LOG = LoggerFactory.getLogger(ElanItmUtils.class);
51
52     private final DataBroker broker;
53     private final ItmRpcService itmRpcService;
54     private final OdlInterfaceRpcService interfaceManagerRpcService;
55     private final IInterfaceManager interfaceManager;
56
57     @Inject
58     public ElanItmUtils(final DataBroker broker, final ItmRpcService itmRpcService,
59             final OdlInterfaceRpcService interfaceManagerRpcService, final IInterfaceManager interfaceManager) {
60         this.broker = broker;
61         this.itmRpcService = itmRpcService;
62         this.interfaceManagerRpcService = interfaceManagerRpcService;
63         this.interfaceManager = interfaceManager;
64     }
65
66     /**
67      * Builds the list of actions to be taken when sending the packet over an
68      * external VxLan tunnel interface, such as stamping the VNI on the VxLAN
69      * header, setting the vlanId if it proceeds and output the packet over the
70      * right port.
71      *
72      * @param srcDpnId
73      *            Dpn where the tunnelInterface is located
74      * @param torNode
75      *            NodeId of the ExternalDevice where the packet must be sent to.
76      * @param vni
77      *            Vni to be stamped on the VxLAN Header.
78      * @return the external itm egress action
79      */
80     public List<Action> getExternalTunnelItmEgressAction(Uint64 srcDpnId, NodeId torNode, long vni) {
81         List<Action> result = Collections.emptyList();
82
83         GetExternalTunnelInterfaceNameInput input = new GetExternalTunnelInterfaceNameInputBuilder()
84                 .setDestinationNode(torNode.getValue()).setSourceNode(srcDpnId.toString())
85                 .setTunnelType(TunnelTypeVxlan.class).build();
86         Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output = itmRpcService
87                 .getExternalTunnelInterfaceName(input);
88         try {
89             if (output.get().isSuccessful()) {
90                 GetExternalTunnelInterfaceNameOutput tunnelInterfaceNameOutput = output.get().getResult();
91                 String tunnelIfaceName = tunnelInterfaceNameOutput.getInterfaceName();
92                 LOG.debug("Received tunnelInterfaceName from getTunnelInterfaceName RPC {}", tunnelIfaceName);
93
94                 result = buildTunnelItmEgressActions(tunnelIfaceName, vni, false);
95             }
96
97         } catch (InterruptedException | ExecutionException e) {
98             LOG.error("Error in RPC call getTunnelInterfaceName", e);
99         }
100
101         return result;
102     }
103
104     public List<Action> getExternalTunnelItmEgressAction(Uint64 srcDpnId, String nexthopIP, long vni) {
105         List<Action> result = Collections.emptyList();
106
107         GetExternalTunnelInterfaceNameInput input = new GetExternalTunnelInterfaceNameInputBuilder()
108                 .setDestinationNode(nexthopIP).setSourceNode(srcDpnId.toString())
109                 .setTunnelType(TunnelTypeVxlan.class).build();
110         Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output = itmRpcService
111                 .getExternalTunnelInterfaceName(input);
112         try {
113             if (output.get().isSuccessful()) {
114                 GetExternalTunnelInterfaceNameOutput tunnelInterfaceNameOutput = output.get().getResult();
115                 String tunnelIfaceName = tunnelInterfaceNameOutput.getInterfaceName();
116                 LOG.debug("Received tunnelInterfaceName from getTunnelInterfaceName RPC {}", tunnelIfaceName);
117
118                 result = buildTunnelItmEgressActions(tunnelIfaceName, vni, false);
119             }
120
121         } catch (InterruptedException | ExecutionException e) {
122             LOG.error("Error in RPC call getTunnelInterfaceName", e);
123         }
124
125         return result;
126     }
127
128     /**
129      * Builds the list of actions to be taken when sending the packet over an internal VxLAN tunnel interface, such
130      * as setting the serviceTag/segmentationID on the VNI field of the VxLAN header, setting the vlanId if it proceeds
131      * and output the packet over the right port.
132      *
133      * @param sourceDpnId
134      *            Dpn where the tunnelInterface is located
135      * @param destinationDpnId
136      *            Dpn where the packet must be sent to. It is used here in order
137      *            to select the right tunnel interface.
138      * @param tunnelKey
139      *            Tunnel key to be sent on the VxLAN header.
140      * @return the internal itm egress action
141      */
142     public List<Action> getInternalTunnelItmEgressAction(Uint64 sourceDpnId, Uint64 destinationDpnId, long
143             tunnelKey) {
144         List<Action> result = Collections.emptyList();
145         LOG.trace("In getInternalItmEgressAction Action source {}, destination {}, serviceTag/Vni {}", sourceDpnId,
146                 destinationDpnId, tunnelKey);
147         Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
148         GetTunnelInterfaceNameInput input = new GetTunnelInterfaceNameInputBuilder()
149                 .setDestinationDpid(destinationDpnId).setSourceDpid(sourceDpnId).setTunnelType(tunType).build();
150         Future<RpcResult<GetTunnelInterfaceNameOutput>> output = itmRpcService.getTunnelInterfaceName(input);
151         try {
152             if (output.get().isSuccessful()) {
153                 GetTunnelInterfaceNameOutput tunnelInterfaceNameOutput = output.get().getResult();
154                 String tunnelIfaceName = tunnelInterfaceNameOutput.getInterfaceName();
155                 LOG.info("Received tunnelInterfaceName from getTunnelInterfaceName RPC {}", tunnelIfaceName);
156                 result = buildTunnelItmEgressActions(tunnelIfaceName, tunnelKey, true);
157             } else {
158                 LOG.trace("Tunnel interface doesn't exist between srcDpId {} dstDpId {}", sourceDpnId,
159                         destinationDpnId);
160             }
161         } catch (InterruptedException | ExecutionException e) {
162             LOG.error("Error in RPC call getTunnelInterfaceName", e);
163         }
164         return result;
165     }
166
167     /**
168      * Builds the list of actions to be taken when sending the packet over a VxLan Tunnel Interface, such as setting
169      * the network VNI in the tunnel_id field.
170      *
171      * @param tunnelIfaceName
172      *            the tunnel iface name
173      * @param tunnelKey
174      *            the tunnel key
175      * @return the list
176      */
177     public List<Action> buildTunnelItmEgressActions(String tunnelIfaceName, Long tunnelKey, boolean ineternal) {
178         if (tunnelIfaceName != null && !tunnelIfaceName.isEmpty()) {
179             return buildItmEgressActions(tunnelIfaceName, tunnelKey, ineternal);
180         }
181         return Collections.emptyList();
182     }
183
184     /**
185      * Build the list of actions to be taken when sending the packet to external
186      * (physical) port.
187      *
188      * @param interfaceName
189      *            Interface name
190      * @return the external port itm egress actions
191      */
192     public List<Action> getExternalPortItmEgressAction(String interfaceName) {
193         return buildItmEgressActions(interfaceName, null, false);
194     }
195
196     /**
197      * Builds the list of actions to be taken when sending the packet over external port such as tunnel, physical
198      * port etc.
199      *
200      * @param interfaceName
201      *            the interface name
202      * @param tunnelKey
203      *            can be VNI for VxLAN tunnel interfaces, Gre Key for GRE
204      *            tunnels, etc.
205      * @return the list
206      */
207     @SuppressWarnings("checkstyle:IllegalCatch")
208     public List<Action> buildItmEgressActions(String interfaceName, @Nullable Long tunnelKey, boolean internal) {
209         try {
210             if (internal && interfaceManager.isItmDirectTunnelsEnabled()) {
211                 GetEgressActionsForTunnelInput getEgressActInputItm = new GetEgressActionsForTunnelInputBuilder()
212                         .setIntfName(interfaceName).setTunnelKey(tunnelKey).build();
213                 Future<RpcResult<GetEgressActionsForTunnelOutput>> egressActionsOutputItm =
214                         itmRpcService.getEgressActionsForTunnel(getEgressActInputItm);
215                 if (egressActionsOutputItm.get().isSuccessful()) {
216                     return new ArrayList<Action>(egressActionsOutputItm.get().getResult().getAction().values());
217                 }
218             } else {
219                 GetEgressActionsForInterfaceInput getEgressActInput = new GetEgressActionsForInterfaceInputBuilder()
220                         .setIntfName(interfaceName).setTunnelKey(tunnelKey).build();
221                 Future<RpcResult<GetEgressActionsForInterfaceOutput>> egressActionsOutputFuture =
222                         interfaceManagerRpcService.getEgressActionsForInterface(getEgressActInput);
223                 if (egressActionsOutputFuture.get().isSuccessful()) {
224                     return new ArrayList<Action>(egressActionsOutputFuture.get().getResult().getAction().values());
225                 }
226             }
227         } catch (Exception e) {
228             LOG.error("Error in RPC call getEgressActionsForInterface", e);
229         }
230         LOG.warn("Could not build Egress actions for interface {} and tunnelId {}", interfaceName, tunnelKey);
231         return Collections.emptyList();
232     }
233
234     /**
235      * Gets the source dpn tep ip.
236      *
237      * @param srcDpnId
238      *            the src dpn id
239      * @param dstHwVtepNodeId
240      *            the dst hw vtep node id
241      * @return the dpn tep ip
242      */
243     public IpAddress getSourceDpnTepIp(Uint64 srcDpnId,
244             org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId dstHwVtepNodeId) {
245         IpAddress dpnTepIp = null;
246         String tunnelInterfaceName = getExternalTunnelInterfaceName(srcDpnId.toString(),
247                 dstHwVtepNodeId.getValue());
248         if (tunnelInterfaceName != null) {
249             Interface tunnelInterface =
250                     ElanL2GatewayUtils.getInterfaceFromConfigDS(new InterfaceKey(tunnelInterfaceName), broker);
251             if (tunnelInterface != null) {
252                 dpnTepIp = tunnelInterface.augmentation(IfTunnel.class).getTunnelSource();
253             } else {
254                 LOG.warn("Tunnel interface not found for tunnelInterfaceName {}", tunnelInterfaceName);
255             }
256         } else {
257             LOG.warn("Tunnel interface name not found for srcDpnId {} and dstHwVtepNodeId {}", srcDpnId,
258                     dstHwVtepNodeId);
259         }
260         return dpnTepIp;
261     }
262
263     /**
264      * Gets the external tunnel interface name.
265      *
266      * @param sourceNode
267      *            the source node
268      * @param dstNode
269      *            the dst node
270      * @return the external tunnel interface name
271      */
272     public String getExternalTunnelInterfaceName(String sourceNode, String dstNode) {
273         Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
274         String tunnelInterfaceName = null;
275         try {
276             Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output = itmRpcService
277                     .getExternalTunnelInterfaceName(new GetExternalTunnelInterfaceNameInputBuilder()
278                             .setSourceNode(sourceNode).setDestinationNode(dstNode).setTunnelType(tunType).build());
279
280             RpcResult<GetExternalTunnelInterfaceNameOutput> rpcResult = output.get();
281             if (rpcResult.isSuccessful()) {
282                 tunnelInterfaceName = rpcResult.getResult().getInterfaceName();
283                 LOG.debug("Tunnel interface name: {} for sourceNode: {} and dstNode: {}", tunnelInterfaceName,
284                         sourceNode, dstNode);
285             } else {
286                 LOG.warn("RPC call to ITM.GetExternalTunnelInterfaceName failed with error: {}", rpcResult.getErrors());
287             }
288         } catch (NullPointerException | InterruptedException | ExecutionException e) {
289             LOG.error("Failed to get external tunnel interface name for sourceNode: {} and dstNode: {}",
290                     sourceNode, dstNode, e);
291         }
292         return tunnelInterfaceName;
293     }
294 }