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