33d459b6b3da22b69c9fb412b6009b113d88a0b2
[bgpcep.git] / bgp / rib-impl / src / main / java / org / opendaylight / protocol / bgp / rib / impl / config / OpenConfigMappingUtil.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
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
9 package org.opendaylight.protocol.bgp.rib.impl.config;
10
11 import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil.INSTANCE;
12
13 import com.google.common.collect.ImmutableList;
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Optional;
20 import java.util.Set;
21 import java.util.stream.Collectors;
22 import javax.annotation.Nonnull;
23 import javax.annotation.Nullable;
24 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
25 import org.opendaylight.protocol.bgp.mode.impl.add.all.paths.AllPathSelection;
26 import org.opendaylight.protocol.bgp.mode.impl.add.n.paths.AddPathBestNPathSelection;
27 import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
28 import org.opendaylight.protocol.bgp.parser.spi.RevisedErrorHandlingSupport;
29 import org.opendaylight.protocol.bgp.parser.spi.pojo.RevisedErrorHandlingSupportImpl;
30 import org.opendaylight.protocol.concepts.KeyMapping;
31 import org.opendaylight.protocol.util.Ipv4Util;
32 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.BgpCommonAfiSafiList;
33 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.common.afi.safi.list.AfiSafi;
34 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.common.afi.safi.list.AfiSafiBuilder;
35 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.BgpNeighborAddPathsConfig;
36 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.BgpNeighborGroup;
37 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.BgpNeighborTransportConfig;
38 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.graceful.restart.GracefulRestart;
39 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.ErrorHandling;
40 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.RouteReflector;
41 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.Timers;
42 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.Transport;
43 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.transport.Config;
44 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbors.Neighbor;
45 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbors.NeighborKey;
46 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.peer.group.PeerGroup;
47 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.Bgp;
48 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Neighbors;
49 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.IPV4UNICAST;
50 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.PeerType;
51 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.Protocol;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.BgpTableType;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.SendReceive;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.mp.capabilities.add.path.capability.AddressFamilies;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.mp.capabilities.add.path.capability.AddressFamiliesBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.GlobalAddPathsConfig;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.GlobalConfigAugmentation;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.NeighborAddPathsConfig;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.NeighborPeerGroupConfig;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.NeighborTransportConfig;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.PeerGroupTransportConfig;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.TransportConfig;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerRole;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.ClusterIdentifier;
69 import org.opendaylight.yangtools.yang.binding.Augmentation;
70 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
71
72 final class OpenConfigMappingUtil {
73
74     static final String APPLICATION_PEER_GROUP_NAME = "application-peers";
75     static final Optional<String> APPLICATION_PEER_GROUP_NAME_OPT = Optional.of(APPLICATION_PEER_GROUP_NAME);
76     static final int HOLDTIMER = 90;
77     private static final AfiSafi IPV4_AFISAFI = new AfiSafiBuilder().setAfiSafiName(IPV4UNICAST.class).build();
78     private static final List<AfiSafi> DEFAULT_AFISAFI = ImmutableList.of(IPV4_AFISAFI);
79     private static final int CONNECT_RETRY = 30;
80     private static final PortNumber PORT = new PortNumber(179);
81
82     private OpenConfigMappingUtil() {
83         throw new UnsupportedOperationException();
84     }
85
86     static String getRibInstanceName(final InstanceIdentifier<?> rootIdentifier) {
87         return rootIdentifier.firstKeyOf(Protocol.class).getName();
88     }
89
90     @Nullable
91     private static Integer getHoldTimer(final Timers timers) {
92         if (timers == null) {
93             return null;
94         }
95         final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.timers
96                 .Config config = timers.getConfig();
97         if (config != null && config.getHoldTime() != null) {
98             return config.getHoldTime().intValue();
99         }
100         return null;
101     }
102
103     @Nullable
104     private static AsNumber getRemotePeerAs(final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp
105             .rev151009.bgp.neighbor.group.Config config) {
106         if (config != null) {
107             final AsNumber peerAs = config.getPeerAs();
108             if (peerAs != null) {
109                 return peerAs;
110             }
111         }
112         return null;
113     }
114
115     @Nullable
116     private static Integer getRetryTimer(final Timers timers) {
117         if (timers == null) {
118             return null;
119         }
120         final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.timers
121                 .Config config = timers.getConfig();
122         if (config != null && config.getConnectRetry() != null) {
123             return config.getConnectRetry().intValue();
124         }
125         return null;
126     }
127
128     static KeyMapping getNeighborKey(final Neighbor neighbor) {
129         if (neighbor.getConfig() != null) {
130             final String authPassword = neighbor.getConfig().getAuthPassword();
131             if (authPassword != null) {
132                 return KeyMapping.getKeyMapping(INSTANCE.inetAddressFor(neighbor.getNeighborAddress()), authPassword);
133             }
134         }
135         return null;
136     }
137
138     static InstanceIdentifier<Neighbor> getNeighborInstanceIdentifier(
139             final InstanceIdentifier<Bgp> rootIdentifier,
140             final NeighborKey neighborKey) {
141         return rootIdentifier.child(Neighbors.class).child(Neighbor.class, neighborKey);
142     }
143
144     static String getNeighborInstanceName(final InstanceIdentifier<?> rootIdentifier) {
145         return Ipv4Util.toStringIP(rootIdentifier.firstKeyOf(Neighbor.class).getNeighborAddress());
146     }
147
148     @Nullable
149     private static <T extends TransportConfig & Augmentation<Config>> PortNumber getPort(
150             @Nullable final Transport transport, final Class<T> augment) {
151         if (transport != null) {
152             final Config config = transport.getConfig();
153             if (config != null) {
154                 final T peerTc = config.augmentation(augment);
155                 if (peerTc != null) {
156                     return peerTc.getRemotePort();
157                 }
158             }
159         }
160         return null;
161     }
162
163     //make sure IPv4 Unicast (RFC 4271) when required
164     static List<AfiSafi> getAfiSafiWithDefault(
165             final BgpCommonAfiSafiList afiSAfis, final boolean setDeafultIPv4) {
166         if (afiSAfis == null || afiSAfis.getAfiSafi() == null) {
167             return setDeafultIPv4 ? DEFAULT_AFISAFI : Collections.emptyList();
168         }
169         final List<AfiSafi> afiSafi = afiSAfis.getAfiSafi();
170         if (setDeafultIPv4) {
171             final boolean anyMatch = afiSafi.stream()
172                     .anyMatch(input -> input.getAfiSafiName().equals(IPV4UNICAST.class));
173             if (!anyMatch) {
174                 afiSafi.add(IPV4_AFISAFI);
175             }
176         }
177         return afiSafi;
178     }
179
180     static ClusterIdentifier getGlobalClusterIdentifier(final org.opendaylight.yang.gen.v1.http.openconfig.net
181             .yang.bgp.rev151009.bgp.global.base.Config globalConfig) {
182         final GlobalConfigAugmentation globalConfigAugmentation
183                 = globalConfig.augmentation(GlobalConfigAugmentation.class);
184         if (globalConfigAugmentation != null && globalConfigAugmentation.getRouteReflectorClusterId() != null) {
185             return new ClusterIdentifier(globalConfigAugmentation.getRouteReflectorClusterId().getIpv4Address());
186         }
187         return new ClusterIdentifier(globalConfig.getRouterId());
188     }
189
190     @Nullable
191     static ClusterIdentifier getNeighborClusterIdentifier(
192             @Nullable final RouteReflector routeReflector,
193             @Nullable final PeerGroup peerGroup) {
194         if (peerGroup != null) {
195             final ClusterIdentifier clusteriId = extractClusterId(peerGroup.getRouteReflector());
196             if (clusteriId != null) {
197                 return clusteriId;
198             }
199         }
200
201         return extractClusterId(routeReflector);
202     }
203
204     private static ClusterIdentifier extractClusterId(final RouteReflector routeReflector) {
205         if (routeReflector != null) {
206             final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.route
207                     .reflector.Config config = routeReflector.getConfig();
208             if (config != null && config.getRouteReflectorClusterId() != null) {
209                 return new ClusterIdentifier(config.getRouteReflectorClusterId().getIpv4Address());
210             }
211         }
212         return null;
213     }
214
215     static Map<BgpTableType, PathSelectionMode> toPathSelectionMode(final List<AfiSafi> afiSafis,
216             final BGPTableTypeRegistryConsumer tableTypeRegistry) {
217         final Map<BgpTableType, PathSelectionMode> pathSelectionModes = new HashMap<>();
218         for (final AfiSafi afiSafi : afiSafis) {
219             final BgpNeighborAddPathsConfig afiSafi2 = afiSafi.augmentation(GlobalAddPathsConfig.class);
220             if (afiSafi2 != null) {
221                 final Optional<BgpTableType> bgpTableType = tableTypeRegistry.getTableType(afiSafi.getAfiSafiName());
222                 if (bgpTableType.isPresent()) {
223                     final int sendMax = afiSafi2.getSendMax();
224                     final PathSelectionMode selectionMode;
225                     if (sendMax > 1) {
226                         selectionMode = new AddPathBestNPathSelection(sendMax);
227                     } else {
228                         selectionMode = new AllPathSelection();
229                     }
230                     pathSelectionModes.put(bgpTableType.get(), selectionMode);
231                 }
232             }
233         }
234         return pathSelectionModes;
235     }
236
237     static boolean isApplicationPeer(final Neighbor neighbor) {
238         final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group
239                 .Config config = neighbor.getConfig();
240         if (config != null) {
241             final NeighborPeerGroupConfig config1 = config.augmentation(NeighborPeerGroupConfig.class);
242             if (config1 != null) {
243                 final String peerGroup = config1.getPeerGroup();
244                 return peerGroup != null && peerGroup.equals(APPLICATION_PEER_GROUP_NAME);
245             }
246         }
247         return false;
248     }
249
250     static List<AddressFamilies> toAddPathCapability(final List<AfiSafi> afiSafis,
251             final BGPTableTypeRegistryConsumer tableTypeRegistry) {
252         final List<AddressFamilies> addPathCapability = new ArrayList<>();
253         for (final AfiSafi afiSafi : afiSafis) {
254             final BgpNeighborAddPathsConfig afiSafi1 = afiSafi.augmentation(NeighborAddPathsConfig.class);
255             final Optional<BgpTableType> bgpTableType = tableTypeRegistry.getTableType(afiSafi.getAfiSafiName());
256             if (afiSafi1 != null && bgpTableType.isPresent()) {
257                 final AddressFamiliesBuilder builder = new AddressFamiliesBuilder(bgpTableType.get());
258                 builder.setSendReceive(toSendReceiveMode(afiSafi1));
259                 addPathCapability.add(builder.build());
260             }
261         }
262         return addPathCapability;
263     }
264
265     private static SendReceive toSendReceiveMode(final BgpNeighborAddPathsConfig addPath) {
266         if (addPath.isReceive() && addPath.getSendMax() != null) {
267             return SendReceive.Both;
268         }
269         if (addPath.getSendMax() != null) {
270             return SendReceive.Send;
271         }
272         return SendReceive.Receive;
273     }
274
275     private static boolean isRrClient(final BgpNeighborGroup neighbor) {
276         final RouteReflector routeReflector = neighbor.getRouteReflector();
277         if (routeReflector != null && routeReflector.getConfig() != null) {
278             return routeReflector.getConfig().isRouteReflectorClient();
279         }
280         return false;
281     }
282
283     static List<BgpTableType> toTableTypes(final List<AfiSafi> afiSafis,
284             final BGPTableTypeRegistryConsumer tableTypeRegistry) {
285         return afiSafis.stream()
286                 .map(afiSafi -> tableTypeRegistry.getTableType(afiSafi.getAfiSafiName()))
287                 .filter(Optional::isPresent)
288                 .map(Optional::get)
289                 .collect(Collectors.toList());
290     }
291
292     static Set<TablesKey> toTableKey(final List<AfiSafi> afiSafis, final BGPTableTypeRegistryConsumer
293             tableTypeRegistry) {
294         return afiSafis.stream()
295                 .map(afiSafi -> tableTypeRegistry.getTableKey(afiSafi.getAfiSafiName()))
296                 .filter(Optional::isPresent)
297                 .map(Optional::get)
298                 .collect(Collectors.toSet());
299     }
300
301     static boolean isActive(final Neighbor neighbor, final PeerGroup peerGroup) {
302         Boolean activeConnection = null;
303         if (peerGroup != null) {
304             activeConnection = isActive(peerGroup.getTransport());
305         }
306
307         if (activeConnection == null) {
308             activeConnection = isActive(neighbor.getTransport());
309         }
310         if (activeConnection == null) {
311             return true;
312         }
313         return activeConnection;
314     }
315
316     @Nullable
317     private static Boolean isActive(final Transport transport) {
318         if (transport != null) {
319             final Config config = transport.getConfig();
320             if (config != null && config.isPassiveMode() != null) {
321                 return !config.isPassiveMode();
322             }
323         }
324         return null;
325     }
326
327     static PeerRole toPeerRole(final BgpNeighborGroup neighbor) {
328         if (isRrClient(neighbor)) {
329             return PeerRole.RrClient;
330         }
331
332         if (neighbor.getConfig() != null) {
333             final PeerType peerType = neighbor.getConfig().getPeerType();
334             if (peerType == PeerType.EXTERNAL) {
335                 return PeerRole.Ebgp;
336             } else if (peerType == PeerType.INTERNAL) {
337                 return PeerRole.Ibgp;
338             }
339         }
340         return null;
341     }
342
343     @Nonnull
344     static PeerRole toPeerRole(final Neighbor neighbor, final PeerGroup peerGroup) {
345         PeerRole role = null;
346         if (peerGroup != null) {
347             role = toPeerRole(peerGroup);
348         }
349
350         if (role == null) {
351             role = toPeerRole(neighbor);
352         }
353
354         if (role == null) {
355             return PeerRole.Ibgp;
356         }
357         return role;
358     }
359
360     static int getHoldTimer(final Neighbor neighbor, final PeerGroup peerGroup) {
361         Integer hold = null;
362         if (peerGroup != null) {
363             hold = getHoldTimer(peerGroup.getTimers());
364         }
365
366         if (hold == null) {
367             hold = getHoldTimer(neighbor.getTimers());
368         }
369
370         if (hold == null) {
371             return HOLDTIMER;
372         }
373
374         return hold;
375     }
376
377     static int getGracefulRestartTimer(final Neighbor neighbor, final PeerGroup peerGroup, final int holdTimer) {
378         Integer timer = null;
379         if (peerGroup != null) {
380             timer = getGracefulRestartTimer(peerGroup.getGracefulRestart());
381         }
382
383         if (timer == null) {
384             timer = getGracefulRestartTimer(neighbor.getGracefulRestart());
385         }
386
387         /*
388          * RFC4724: "A suggested default for the Restart Time is a value less than or
389          * equal to the HOLDTIME carried in the OPEN."
390          */
391         if (timer == null) {
392             timer = holdTimer;
393         }
394
395         return timer;
396     }
397
398     @Nullable
399     private static Integer getGracefulRestartTimer(final GracefulRestart gracefulRestart) {
400         if (gracefulRestart != null) {
401             final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.graceful.restart.graceful
402                     .restart.Config config = gracefulRestart.getConfig();
403             if (config != null) {
404                 return config.getRestartTime();
405             }
406         }
407         return null;
408     }
409
410     @Nonnull
411     static AsNumber getRemotePeerAs(final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009
412             .bgp.neighbor.group.Config config, final PeerGroup peerGroup, final AsNumber localAs) {
413         AsNumber neighborAs = null;
414         if (peerGroup != null) {
415             neighborAs = getRemotePeerAs(peerGroup.getConfig());
416         }
417
418         if (neighborAs == null) {
419             neighborAs = getRemotePeerAs(config);
420         }
421
422         if (neighborAs == null) {
423             return localAs;
424         }
425         return neighborAs;
426     }
427
428     @Nonnull
429     static AsNumber getLocalPeerAs(@Nullable final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp
430             .rev151009.bgp.neighbor.group.Config config, @Nonnull final AsNumber globalAs) {
431         if (config != null) {
432             final AsNumber peerAs = config.getLocalAs();
433             if (peerAs != null) {
434                 return peerAs;
435             }
436         }
437         return globalAs;
438     }
439
440     static int getRetryTimer(final Neighbor neighbor, final PeerGroup peerGroup) {
441         Integer retryTimer = null;
442         if (peerGroup != null) {
443             retryTimer = getRetryTimer(peerGroup.getTimers());
444         }
445
446         if (retryTimer == null) {
447             retryTimer = getRetryTimer(neighbor.getTimers());
448         }
449
450         if (retryTimer == null) {
451             return CONNECT_RETRY;
452         }
453
454         return retryTimer;
455     }
456
457     @Nonnull
458     static PortNumber getPort(final Neighbor neighbor, final PeerGroup peerGroup) {
459         PortNumber port = null;
460         if (peerGroup != null) {
461             port = getPort(peerGroup.getTransport(), PeerGroupTransportConfig.class);
462         }
463
464         if (port == null) {
465             port = getPort(neighbor.getTransport(), NeighborTransportConfig.class);
466         }
467
468         if (port == null) {
469             return PORT;
470         }
471
472         return port;
473     }
474
475     @Nullable
476     static IpAddress getLocalAddress(@Nullable final Transport transport) {
477         if (transport != null && transport.getConfig() != null) {
478             final BgpNeighborTransportConfig.LocalAddress localAddress = transport.getConfig().getLocalAddress();
479             if (localAddress != null) {
480                 return localAddress.getIpAddress();
481             }
482         }
483         return null;
484     }
485
486     @Nullable
487     static RevisedErrorHandlingSupport getRevisedErrorHandling(final PeerRole role,final PeerGroup peerGroup,
488             final Neighbor neighbor) {
489         Boolean enabled = getRevisedErrorHandling(neighbor);
490         if (enabled == null) {
491             enabled = getRevisedErrorHandling(peerGroup);
492         }
493         if (!Boolean.TRUE.equals(enabled)) {
494             return null;
495         }
496         switch (role) {
497             case Ebgp:
498                 return RevisedErrorHandlingSupportImpl.forExternalPeer();
499             case Ibgp:
500             case Internal:
501             case RrClient:
502                 return RevisedErrorHandlingSupportImpl.forInternalPeer();
503             default:
504                 throw new IllegalStateException("Unhandled role " + role);
505         }
506     }
507
508     @Nullable
509     private static @org.eclipse.jdt.annotation.Nullable Boolean getRevisedErrorHandling(final BgpNeighborGroup group) {
510         if (group == null) {
511             return null;
512         }
513         final ErrorHandling errorHandling = group.getErrorHandling();
514         if (errorHandling == null) {
515             return null;
516         }
517         final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.error.handling
518             .Config config = errorHandling.getConfig();
519         return config == null ? null : config.isTreatAsWithdraw();
520     }
521 }