2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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
8 package org.opendaylight.genius.interfacemanager.renderer.ovs.utilities;
10 import com.google.common.collect.Maps;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.List;
17 import java.util.UUID;
18 import org.apache.commons.lang3.BooleanUtils;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.genius.interfacemanager.commons.InterfaceManagerCommonUtils;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge._interface.info.BridgeEntry;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge._interface.info.bridge.entry.BridgeInterfaceEntry;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelMonitoringTypeBfd;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeMplsOverGre;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlanGpe;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.tunnel.optional.params.TunnelOptions;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeBase;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeGre;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeVxlan;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbPortInterfaceAttributes;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentationBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceBfd;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceBfdBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceBfdKey;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Options;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.OptionsBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.OptionsKey;
52 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
53 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
55 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
56 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
57 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
58 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
59 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
60 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
61 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
62 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
66 public class SouthboundUtils {
67 private static final Logger LOG = LoggerFactory.getLogger(SouthboundUtils.class);
69 public static final String BFD_PARAM_ENABLE = "enable";
70 static final String BFD_PARAM_MIN_TX = "min_tx";
71 static final String BFD_PARAM_MIN_RX = "min_rx";
72 static final String BFD_PARAM_DECAY_MIN_RX = "decay_min_rx";
73 static final String BFD_PARAM_FORWARDING_IF_RX = "forwarding_if_rx";
74 static final String BFD_PARAM_CPATH_DOWN = "cpath_down";
75 static final String BFD_PARAM_CHECK_TNL_KEY = "check_tnl_key";
78 public static final String BFD_OP_STATE = "state";
79 public static final String BFD_STATE_UP = "up";
80 private static final String BFD_MIN_RX_VAL = "1000";
81 private static final String BFD_MIN_TX_VAL = "100";
82 private static final String BFD_DECAY_MIN_RX_VAL = "200";
83 private static final String BFD_FORWARDING_IF_RX_VAL = "true";
84 private static final String BFD_CPATH_DOWN_VAL = "false";
85 private static final String BFD_CHECK_TNL_KEY_VAL = "false";
88 private static final String TUNNEL_OPTIONS_KEY = "key";
89 private static final String TUNNEL_OPTIONS_LOCAL_IP = "local_ip";
90 private static final String TUNNEL_OPTIONS_REMOTE_IP = "remote_ip";
91 private static final String TUNNEL_OPTIONS_DESTINATION_PORT = "dst_port";
93 // Option values for VxLAN-GPE + NSH tunnels
94 private static final String TUNNEL_OPTIONS_EXTS = "exts";
95 private static final String TUNNEL_OPTIONS_NSI = "nsi";
96 private static final String TUNNEL_OPTIONS_NSP = "nsp";
97 private static final String TUNNEL_OPTIONS_NSHC1 = "nshc1";
98 private static final String TUNNEL_OPTIONS_NSHC2 = "nshc2";
99 private static final String TUNNEL_OPTIONS_NSHC3 = "nshc3";
100 private static final String TUNNEL_OPTIONS_NSHC4 = "nshc4";
102 // Option values for VxLAN-GPE + NSH tunnels
103 private static final String TUNNEL_OPTIONS_VALUE_FLOW = "flow";
104 private static final String TUNNEL_OPTIONS_VALUE_GPE = "gpe";
105 // UDP port for VxLAN-GPE Tunnels
106 private static final String TUNNEL_OPTIONS_VALUE_GPE_DESTINATION_PORT = "4880";
109 public static final TopologyId OVSDB_TOPOLOGY_ID = new TopologyId(new Uri("ovsdb:1"));
111 // To keep the mapping between Tunnel Types and Tunnel Interfaces
112 private static final Map<Class<? extends TunnelTypeBase>, Class<? extends InterfaceTypeBase>> TUNNEL_TYPE_MAP = new HashMap<Class<? extends TunnelTypeBase>, Class<? extends InterfaceTypeBase>>() {
114 put(TunnelTypeGre.class, InterfaceTypeGre.class);
115 put(TunnelTypeVxlan.class, InterfaceTypeVxlan.class);
116 put(TunnelTypeVxlanGpe.class, InterfaceTypeVxlan.class);
120 public static void addPortToBridge(InstanceIdentifier<?> bridgeIid, Interface iface, String portName, DataBroker dataBroker,
121 List<ListenableFuture<Void>> futures) {
122 IfTunnel ifTunnel = iface.getAugmentation(IfTunnel.class);
123 if (ifTunnel != null) {
124 addTunnelPortToBridge(ifTunnel, bridgeIid, iface, portName, dataBroker);
129 * Add all tunnels ports corresponding to the bridge to the topology config
132 public static void addAllPortsToBridge(BridgeEntry bridgeEntry, DataBroker dataBroker,
133 InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid, OvsdbBridgeAugmentation bridgeNew,
134 List<ListenableFuture<Void>> futures) {
135 String bridgeName = bridgeNew.getBridgeName().getValue();
136 LOG.debug("adding all ports to bridge: {}", bridgeName);
137 List<BridgeInterfaceEntry> bridgeInterfaceEntries = bridgeEntry.getBridgeInterfaceEntry();
138 if (bridgeInterfaceEntries != null) {
139 for (BridgeInterfaceEntry bridgeInterfaceEntry : bridgeInterfaceEntries) {
140 String portName = bridgeInterfaceEntry.getInterfaceName();
141 InterfaceKey interfaceKey = new InterfaceKey(portName);
142 Interface iface = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(interfaceKey, dataBroker);
144 IfTunnel ifTunnel = iface.getAugmentation(IfTunnel.class);
145 if (ifTunnel != null) {
146 addTunnelPortToBridge(ifTunnel, bridgeIid, iface, portName, dataBroker);
148 if(SouthboundUtils.isOfTunnel(ifTunnel)) {
149 LOG.debug("Using OFTunnel. Only one tunnel port will be added");
153 LOG.debug("Interface {} not found in config DS", portName);
160 * delete all tunnels ports corresponding to the bridge to the topology config
163 * FIXME: This is not being called from anywhere.
165 public static void removeAllPortsFromBridge(BridgeEntry bridgeEntry, DataBroker dataBroker,
166 InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid, OvsdbBridgeAugmentation bridgeNew) {
167 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
168 String bridgeName = bridgeNew.getBridgeName().getValue();
169 LOG.debug("removing all ports from bridge: {}", bridgeName);
170 List<BridgeInterfaceEntry> bridgeInterfaceEntries = bridgeEntry.getBridgeInterfaceEntry();
171 if (bridgeInterfaceEntries != null) {
172 for (BridgeInterfaceEntry bridgeInterfaceEntry : bridgeInterfaceEntries) {
173 String portName = bridgeInterfaceEntry.getInterfaceName();
174 InterfaceKey interfaceKey = new InterfaceKey(portName);
175 Interface iface = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(interfaceKey, dataBroker);
177 IfTunnel ifTunnel = iface.getAugmentation(IfTunnel.class);
178 if (ifTunnel != null) {
179 removeTerminationEndPoint(dataBroker, bridgeIid, iface.getName());
181 if(SouthboundUtils.isOfTunnel(ifTunnel)) {
182 LOG.debug("Using OFTunnel. Only one tunnel port to be removed");
186 LOG.debug("Interface {} not found in config DS", portName);
192 private static void addVlanPortToBridge(InstanceIdentifier<?> bridgeIid, IfL2vlan ifL2vlan, IfTunnel ifTunnel,
193 OvsdbBridgeAugmentation bridgeAugmentation, String bridgeName, String portName, DataBroker dataBroker,
194 WriteTransaction t) {
195 if (ifL2vlan.getVlanId() != null) {
196 addTerminationPoint(bridgeIid, portName, ifL2vlan.getVlanId().getValue(),
197 null, null, ifTunnel);
201 private static void addTunnelPortToBridge(IfTunnel ifTunnel, InstanceIdentifier<?> bridgeIid, Interface iface,
202 String portName, DataBroker dataBroker) {
203 LOG.debug("adding tunnel port {} to bridge {}", portName, bridgeIid);
205 Class<? extends InterfaceTypeBase> type = TUNNEL_TYPE_MAP.get(ifTunnel.getTunnelInterfaceType());
208 LOG.warn("Unknown Tunnel Type obtained while creating interface: {}", iface);
213 IfL2vlan ifL2vlan = iface.getAugmentation(IfL2vlan.class);
214 if (ifL2vlan != null && ifL2vlan.getVlanId() != null) {
215 vlanId = ifL2vlan.getVlanId().getValue();
218 Map<String, String> options = Maps.newHashMap();
220 // Options common to any kind of tunnel
221 if(BooleanUtils.isTrue(ifTunnel.isTunnelSourceIpFlow())) {
222 options.put(TUNNEL_OPTIONS_LOCAL_IP, TUNNEL_OPTIONS_VALUE_FLOW);
224 IpAddress localIp = ifTunnel.getTunnelSource();
225 options.put(TUNNEL_OPTIONS_LOCAL_IP, localIp.getIpv4Address().getValue());
227 if(BooleanUtils.isTrue(ifTunnel.isTunnelRemoteIpFlow())) {
228 options.put(TUNNEL_OPTIONS_REMOTE_IP, TUNNEL_OPTIONS_VALUE_FLOW);
230 IpAddress remoteIp = ifTunnel.getTunnelDestination();
231 options.put(TUNNEL_OPTIONS_REMOTE_IP, remoteIp.getIpv4Address().getValue());
234 // Specific options for each type of tunnel
235 if (!ifTunnel.getTunnelInterfaceType().equals(TunnelTypeMplsOverGre.class)) {
236 options.put(TUNNEL_OPTIONS_KEY, TUNNEL_OPTIONS_VALUE_FLOW);
238 if (ifTunnel.getTunnelInterfaceType().equals(TunnelTypeVxlanGpe.class)) {
239 options.put(TUNNEL_OPTIONS_EXTS, TUNNEL_OPTIONS_VALUE_GPE);
240 options.put(TUNNEL_OPTIONS_NSI, TUNNEL_OPTIONS_VALUE_FLOW);
241 options.put(TUNNEL_OPTIONS_NSP, TUNNEL_OPTIONS_VALUE_FLOW);
242 options.put(TUNNEL_OPTIONS_NSHC1, TUNNEL_OPTIONS_VALUE_FLOW);
243 options.put(TUNNEL_OPTIONS_NSHC2, TUNNEL_OPTIONS_VALUE_FLOW);
244 options.put(TUNNEL_OPTIONS_NSHC3, TUNNEL_OPTIONS_VALUE_FLOW);
245 options.put(TUNNEL_OPTIONS_NSHC4, TUNNEL_OPTIONS_VALUE_FLOW);
246 // VxLAN-GPE interfaces will not use the default UDP port to avoid problems with other meshes
247 options.put(TUNNEL_OPTIONS_DESTINATION_PORT, TUNNEL_OPTIONS_VALUE_GPE_DESTINATION_PORT);
250 if(ifTunnel.getTunnelOptions() != null) {
251 for(TunnelOptions tunOpt : ifTunnel.getTunnelOptions()) {
252 options.putIfAbsent(tunOpt.getTunnelOption(), tunOpt.getValue());
256 addTerminationPoint(bridgeIid, portName, vlanId, type, options, ifTunnel);
259 // Update is allowed only for tunnel monitoring attributes
260 public static void updateBfdParamtersForTerminationPoint(InstanceIdentifier<?> bridgeIid, IfTunnel ifTunnel,
261 String portName, WriteTransaction transaction) {
262 InstanceIdentifier<TerminationPoint> tpIid = createTerminationPointInstanceIdentifier(
263 InstanceIdentifier.keyOf(bridgeIid.firstIdentifierOf(Node.class)), portName);
264 if(isOfTunnel(ifTunnel)) {
265 LOG.warn("BFD monitoring not supported for OFTunnels. Skipping BFD parameters for {}", portName);
268 LOG.debug("update bfd parameters for interface {}", tpIid);
269 OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = new OvsdbTerminationPointAugmentationBuilder();
270 List<InterfaceBfd> bfdParams = getBfdParams(ifTunnel);
271 tpAugmentationBuilder.setInterfaceBfd(bfdParams);
273 TerminationPointBuilder tpBuilder = new TerminationPointBuilder();
274 tpBuilder.setKey(InstanceIdentifier.keyOf(tpIid));
275 tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build());
277 transaction.merge(LogicalDatastoreType.CONFIGURATION, tpIid, tpBuilder.build(), true);
280 private static void addTerminationPoint(InstanceIdentifier<?> bridgeIid, String portName, int vlanId,
281 Class<? extends InterfaceTypeBase> type, Map<String, String> options, IfTunnel ifTunnel) {
282 InstanceIdentifier<TerminationPoint> tpIid = createTerminationPointInstanceIdentifier(
283 InstanceIdentifier.keyOf(bridgeIid.firstIdentifierOf(Node.class)), portName);
284 OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = new OvsdbTerminationPointAugmentationBuilder();
286 tpAugmentationBuilder.setName(portName);
289 tpAugmentationBuilder.setInterfaceType(type);
292 if (options != null) {
293 List<Options> optionsList = new ArrayList<>();
294 for (Map.Entry<String, String> entry : options.entrySet()) {
295 OptionsBuilder optionsBuilder = new OptionsBuilder();
296 optionsBuilder.setKey(new OptionsKey(entry.getKey()));
297 optionsBuilder.setOption(entry.getKey());
298 optionsBuilder.setValue(entry.getValue());
299 optionsList.add(optionsBuilder.build());
301 tpAugmentationBuilder.setOptions(optionsList);
305 tpAugmentationBuilder.setVlanMode(OvsdbPortInterfaceAttributes.VlanMode.Access);
306 tpAugmentationBuilder.setVlanTag(new VlanId(vlanId));
309 if (bfdMonitoringEnabled(ifTunnel)) {
310 if(isOfTunnel(ifTunnel)) {
311 LOG.warn("BFD Monitoring not supported for OFTunnels");
313 List<InterfaceBfd> bfdParams = getBfdParams(ifTunnel);
314 tpAugmentationBuilder.setInterfaceBfd(bfdParams);
318 TerminationPointBuilder tpBuilder = new TerminationPointBuilder();
319 tpBuilder.setKey(InstanceIdentifier.keyOf(tpIid));
320 tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build());
322 BatchingUtils.write(tpIid, tpBuilder.build(), BatchingUtils.EntityType.TOPOLOGY_CONFIG);
326 private static List<InterfaceBfd> getBfdParams(IfTunnel ifTunnel) {
327 List<InterfaceBfd> bfdParams = new ArrayList<>();
328 bfdParams.add(getIfBfdObj(BFD_PARAM_ENABLE,ifTunnel != null ? ifTunnel.isMonitorEnabled().toString() :"false"));
329 bfdParams.add(getIfBfdObj(BFD_PARAM_MIN_TX, ifTunnel != null && ifTunnel.getMonitorInterval() != null ?
330 ifTunnel.getMonitorInterval().toString() : BFD_MIN_TX_VAL));
334 private static InterfaceBfd getIfBfdObj(String key, String value) {
335 InterfaceBfdBuilder bfdBuilder = new InterfaceBfdBuilder();
336 bfdBuilder.setBfdKey(key).setKey(new InterfaceBfdKey(key)).setBfdValue(value);
337 return bfdBuilder.build();
340 public static InstanceIdentifier<TerminationPoint> createTerminationPointInstanceIdentifier(NodeKey nodekey,
342 InstanceIdentifier<TerminationPoint> terminationPointPath = InstanceIdentifier.create(NetworkTopology.class)
343 .child(Topology.class, new TopologyKey(OVSDB_TOPOLOGY_ID)).child(Node.class, nodekey)
344 .child(TerminationPoint.class, new TerminationPointKey(new TpId(portName)));
346 LOG.debug("Termination point InstanceIdentifier generated : {}", terminationPointPath);
347 return terminationPointPath;
350 public static void removeTerminationEndPoint(DataBroker dataBroker,
351 InstanceIdentifier<?> bridgeIid, String interfaceName) {
352 LOG.debug("removing termination point for {}", interfaceName);
353 WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
354 InstanceIdentifier<TerminationPoint> tpIid = SouthboundUtils.createTerminationPointInstanceIdentifier(
355 InstanceIdentifier.keyOf(bridgeIid.firstIdentifierOf(Node.class)), interfaceName);
356 BatchingUtils.delete(tpIid, BatchingUtils.EntityType.TOPOLOGY_CONFIG);
359 public static boolean bfdMonitoringEnabled(IfTunnel ifTunnel) {
360 return ifTunnel.isMonitorEnabled()
361 && TunnelMonitoringTypeBfd.class.isAssignableFrom(ifTunnel.getMonitorProtocol());
364 public static boolean isMonitorProtocolBfd(IfTunnel ifTunnel) {
365 return TunnelMonitoringTypeBfd.class.isAssignableFrom(ifTunnel.getMonitorProtocol());
368 public static String generateOfTunnelName(BigInteger dpId, IfTunnel ifTunnel) {
369 String sourceKey = ifTunnel.getTunnelSource().getIpv4Address().getValue();
370 String remoteKey = ifTunnel.getTunnelDestination().getIpv4Address().getValue();
371 if( ifTunnel.isTunnelSourceIpFlow() != null) {
374 if( ifTunnel.isTunnelRemoteIpFlow() != null) {
377 String tunnelNameKey = dpId.toString()+sourceKey+remoteKey;
378 String uuidStr = UUID.nameUUIDFromBytes(tunnelNameKey.getBytes()).toString().substring(0, 12).replace("-", "");
379 return String.format("%s%s", "tun", uuidStr);
382 public static boolean isOfTunnel(IfTunnel ifTunnel) {
383 if( BooleanUtils.isTrue(ifTunnel.isTunnelRemoteIpFlow()) ||
384 BooleanUtils.isTrue(ifTunnel.isTunnelSourceIpFlow()) ) {