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