Merge "Bug 6690 - when mixing dpdk & non-dpdk OVS with the same ODL no way to configu...
[netvirt.git] / vpnservice / natservice / natservice-impl / src / main / java / org / opendaylight / netvirt / natservice / internal / VpnFloatingIpHandler.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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 package org.opendaylight.netvirt.natservice.internal;
9
10 import com.google.common.util.concurrent.AsyncFunction;
11 import com.google.common.util.concurrent.FutureCallback;
12 import com.google.common.util.concurrent.Futures;
13 import com.google.common.util.concurrent.JdkFutureAdapters;
14 import com.google.common.util.concurrent.ListenableFuture;
15
16 import java.math.BigInteger;
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.concurrent.Future;
20
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
23 import org.opendaylight.genius.mdsalutil.ActionInfo;
24 import org.opendaylight.genius.mdsalutil.ActionType;
25 import org.opendaylight.genius.mdsalutil.InstructionInfo;
26 import org.opendaylight.genius.mdsalutil.InstructionType;
27 import org.opendaylight.genius.mdsalutil.MDSALUtil;
28 import org.opendaylight.genius.mdsalutil.MatchFieldType;
29 import org.opendaylight.genius.mdsalutil.MatchInfo;
30 import org.opendaylight.genius.mdsalutil.NwConstants;
31 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
32 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
33 import org.opendaylight.netvirt.elanmanager.api.IElanService;
34 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
35 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
36 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
41 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInput;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInputBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddress;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddressBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInput;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInputBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelOutput;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInput;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInputBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
62 import org.opendaylight.yangtools.yang.common.RpcResult;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65
66 public class VpnFloatingIpHandler implements FloatingIPHandler {
67     private static final Logger LOG = LoggerFactory.getLogger(VpnFloatingIpHandler.class);
68     private final DataBroker dataBroker;
69     private final IMdsalApiManager mdsalManager;
70     private final VpnRpcService vpnService;
71     private final IBgpManager bgpManager;
72     private final FibRpcService fibService;
73     private final FloatingIPListener floatingIPListener;
74     private final IVpnManager vpnManager;
75     private final IFibManager fibManager;
76     private final OdlArputilService arpUtilService;
77     private final IElanService elanService;
78
79     static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
80     static final String FLOWID_PREFIX = "NAT.";
81
82     public VpnFloatingIpHandler(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
83                                 final VpnRpcService vpnService,
84                                 final IBgpManager bgpManager,
85                                 final FibRpcService fibService,
86                                 final FloatingIPListener floatingIPListener,
87                                 final IFibManager fibManager,
88                                 final OdlArputilService arputilService,
89                                 final IVpnManager vpnManager,
90                                 final IElanService elanService) {
91         this.dataBroker = dataBroker;
92         this.mdsalManager = mdsalManager;
93         this.vpnService = vpnService;
94         this.bgpManager = bgpManager;
95         this.fibService = fibService;
96         this.floatingIPListener = floatingIPListener;
97         this.fibManager = fibManager;
98         this.arpUtilService = arputilService;
99         this.vpnManager = vpnManager;
100         this.elanService = elanService;
101     }
102
103     @Override
104     public void onAddFloatingIp(final BigInteger dpnId, final String routerId,
105                                 Uuid networkId, final String interfaceName, final String externalIp,
106                                 final String internalIp) {
107         final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
108         if (vpnName == null) {
109             LOG.info("No VPN associated with ext nw {} to handle add floating ip configuration {} in router {}",
110                     networkId, externalIp, routerId);
111             return;
112         }
113
114         GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName)
115                 .setIpPrefix(externalIp).build();
116         Future<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
117
118         ListenableFuture<RpcResult<Void>> future = Futures.transform(JdkFutureAdapters.listenInPoolThread(labelFuture),
119                 new AsyncFunction<RpcResult<GenerateVpnLabelOutput>, RpcResult<Void>>() {
120
121             @Override
122             public ListenableFuture<RpcResult<Void>> apply(RpcResult<GenerateVpnLabelOutput> result) throws Exception {
123                 if(result.isSuccessful()) {
124                     GenerateVpnLabelOutput output = result.getResult();
125                     long label = output.getLabel();
126                     LOG.debug("Generated label {} for prefix {}", label, externalIp);
127                     floatingIPListener.updateOperationalDS(routerId, interfaceName, label, internalIp, externalIp);
128
129                     //Inform BGP
130                     String rd = NatUtil.getVpnRd(dataBroker, vpnName);
131                     String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
132                     LOG.debug("Nexthop ip for prefix {} is {}", externalIp, nextHopIp);
133                     NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, rd, externalIp + "/32", nextHopIp,
134                             label, LOG, RouteOrigin.STATIC);
135
136                     List<Instruction> instructions = new ArrayList<>();
137                     List<ActionInfo> actionsInfos = new ArrayList<>();
138                     actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[] { Integer.toString(NwConstants.PDNAT_TABLE) }));
139                     instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos).buildInstruction(0));
140                     makeTunnelTableEntry(dpnId, label, instructions);
141
142                     //Install custom FIB routes
143                     List<Instruction> customInstructions = new ArrayList<>();
144                     customInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.PDNAT_TABLE }).buildInstruction(0));
145                     makeLFibTableEntry(dpnId, label, NwConstants.PDNAT_TABLE);
146                     CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId).setInstruction(customInstructions)
147                             .setIpAddress(externalIp + "/32").setServiceId(label).setInstruction(customInstructions).build();
148                     //Future<RpcResult<java.lang.Void>> createFibEntry(CreateFibEntryInput input);
149                     Future<RpcResult<Void>> future = fibService.createFibEntry(input);
150                     WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
151                     IpAddress externalIpAddress = new IpAddress(new Ipv4Address(externalIp));
152                     Port neutronPort = NatUtil.getNeutronPortForFloatingIp(dataBroker, externalIpAddress);
153                     if (neutronPort != null && neutronPort.getMacAddress() != null) {
154                         vpnManager.setupSubnetMacIntoVpnInstance(vpnName, neutronPort.getMacAddress().getValue(), writeTx, NwConstants.ADD_FLOW);
155                     }
156                     writeTx.submit();
157                     return JdkFutureAdapters.listenInPoolThread(future);
158                 } else {
159                     String errMsg = String.format("Could not retrieve the label for prefix %s in VPN %s, %s", externalIp, vpnName, result.getErrors());
160                     LOG.error(errMsg);
161                     return Futures.immediateFailedFuture(new RuntimeException(errMsg));
162                 }
163             }
164         });
165
166         Futures.addCallback(future, new FutureCallback<RpcResult<Void>>() {
167
168             @Override
169             public void onFailure(Throwable error) {
170                 LOG.error("Error in generate label or fib install process", error);
171             }
172
173             @Override
174             public void onSuccess(RpcResult<Void> result) {
175                 if(result.isSuccessful()) {
176                     LOG.info("Successfully installed custom FIB routes for prefix {}", externalIp);
177                 } else {
178                     LOG.error("Error in rpc call to create custom Fib entries for prefix {} in DPN {}, {}", externalIp, dpnId, result.getErrors());
179                 }
180             }
181         });
182
183         // Handle GARP transmission
184         final IpAddress extrenalAddress = IpAddressBuilder.getDefaultInstance(externalIp);
185         sendGarpOnInterface(dpnId, networkId,  routerId, extrenalAddress);
186
187     }
188
189     @Override
190     public void onRemoveFloatingIp(final BigInteger dpnId, String routerId, Uuid networkId, final String externalIp,
191                                    String internalIp, final long label) {
192         final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
193         if (vpnName == null) {
194             LOG.info("No VPN associated with ext nw {} to handle remove floating ip configuration {} in router {}",
195                     networkId, externalIp, routerId);
196             return;
197         }
198         //Remove floating mac from mymac table
199         WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
200         IpAddress externalIpAddress = new IpAddress(new Ipv4Address(externalIp));
201         Port neutronPort = NatUtil.getNeutronPortForFloatingIp(dataBroker, externalIpAddress);
202         if (neutronPort != null && neutronPort.getMacAddress() != null) {
203             vpnManager.setupSubnetMacIntoVpnInstance(vpnName, neutronPort.getMacAddress().getValue(), writeTx, NwConstants.DEL_FLOW);
204         }
205         writeTx.submit();
206         //Remove Prefix from BGP
207         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
208         NatUtil.removePrefixFromBGP(dataBroker, bgpManager, fibManager, rd, externalIp + "/32", LOG);
209
210         //Remove custom FIB routes
211         //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
212         RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp + "/32").setServiceId(label).build();
213         Future<RpcResult<Void>> future = fibService.removeFibEntry(input);
214
215         ListenableFuture<RpcResult<Void>> labelFuture = Futures.transform(JdkFutureAdapters.listenInPoolThread(future), new AsyncFunction<RpcResult<Void>, RpcResult<Void>>() {
216
217             @Override
218             public ListenableFuture<RpcResult<Void>> apply(RpcResult<Void> result) throws Exception {
219                 //Release label
220                 if(result.isSuccessful()) {
221                     removeTunnelTableEntry(dpnId, label);
222                     removeLFibTableEntry(dpnId, label);
223                     RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
224                     Future<RpcResult<Void>> labelFuture = vpnService.removeVpnLabel(labelInput);
225                     return JdkFutureAdapters.listenInPoolThread(labelFuture);
226                 } else {
227                     String errMsg = String.format("RPC call to remove custom FIB entries on dpn %s for prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
228                     LOG.error(errMsg);
229                     return Futures.immediateFailedFuture(new RuntimeException(errMsg));
230                 }
231             }
232         });
233
234         Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {
235
236             @Override
237             public void onFailure(Throwable error) {
238                 LOG.error("Error in removing the label or custom fib entries", error);
239             }
240
241             @Override
242             public void onSuccess(RpcResult<Void> result) {
243                 if(result.isSuccessful()) {
244                     LOG.debug("Successfully removed the label for the prefix {} from VPN {}", externalIp, vpnName);
245                 } else {
246                     LOG.error("Error in removing the label for prefix {} from VPN {}, {}", externalIp, vpnName, result.getErrors());
247                 }
248             }
249         });
250     }
251
252     void cleanupFibEntries(final BigInteger dpnId, final String vpnName, final String externalIp, final long label ) {
253         //Remove Prefix from BGP
254         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
255         NatUtil.removePrefixFromBGP(dataBroker, bgpManager, fibManager, rd, externalIp + "/32", LOG);
256
257         //Remove custom FIB routes
258
259         //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
260         RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp + "/32").setServiceId(label).build();
261         Future<RpcResult<Void>> future = fibService.removeFibEntry(input);
262
263         ListenableFuture<RpcResult<Void>> labelFuture = Futures.transform(JdkFutureAdapters.listenInPoolThread(future),
264             new AsyncFunction<RpcResult<Void>, RpcResult<Void>>() {
265
266             @Override
267             public ListenableFuture<RpcResult<Void>> apply(RpcResult<Void> result) throws Exception {
268                 //Release label
269                 if(result.isSuccessful()) {
270                     removeTunnelTableEntry(dpnId, label);
271                     removeLFibTableEntry(dpnId, label);
272                     RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
273                     Future<RpcResult<Void>> labelFuture = vpnService.removeVpnLabel(labelInput);
274                     return JdkFutureAdapters.listenInPoolThread(labelFuture);
275                 } else {
276                     String errMsg = String.format("RPC call to remove custom FIB entries on dpn %s for prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
277                     LOG.error(errMsg);
278                     return Futures.immediateFailedFuture(new RuntimeException(errMsg));
279                 }
280             }
281         });
282
283         Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {
284
285             @Override
286             public void onFailure(Throwable error) {
287                 LOG.error("Error in removing the label or custom fib entries", error);
288             }
289
290             @Override
291             public void onSuccess(RpcResult<Void> result) {
292                 if(result.isSuccessful()) {
293                     LOG.debug("Successfully removed the label for the prefix {} from VPN {}", externalIp, vpnName);
294                 } else {
295                     LOG.error("Error in removing the label for prefix {} from VPN {}, {}", externalIp, vpnName, result.getErrors());
296                 }
297             }
298         });
299     }
300
301     private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
302         return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
303                 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
304                 .append(id).append(NwConstants.FLOWID_SEPARATOR).append(ipAddress).toString();
305     }
306
307     private void removeTunnelTableEntry(BigInteger dpnId, long serviceId) {
308         LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpnId , serviceId);
309         List<MatchInfo> mkMatches = new ArrayList<>();
310         // Matching metadata
311         mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
312         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
313                 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
314                 5, String.format("%s:%d","TST Flow Entry ",serviceId), 0, 0,
315                 COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null);
316         mdsalManager.removeFlow(dpnId, flowEntity);
317         LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully {}",dpnId, serviceId);
318     }
319
320     private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, List<Instruction> customInstructions) {
321         List<MatchInfo> mkMatches = new ArrayList<>();
322
323         LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", dpnId , serviceId);
324
325         mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
326
327         Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
328                 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5, String.format("%s:%d","TST Flow Entry ",serviceId),
329                 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)),mkMatches, customInstructions);
330
331         mdsalManager.installFlow(dpnId, terminatingServiceTableFlowEntity);
332     }
333
334     private void makeLFibTableEntry(BigInteger dpId, long serviceId, long tableId) {
335         List<MatchInfo> matches = new ArrayList<>();
336         matches.add(new MatchInfo(MatchFieldType.eth_type,
337                 new long[] { 0x8847L }));
338         matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
339
340         List<Instruction> instructions = new ArrayList<>();
341         List<ActionInfo> actionsInfos = new ArrayList<>();
342         actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
343         Instruction writeInstruction = new InstructionInfo(InstructionType.apply_actions, actionsInfos).buildInstruction(0);
344         instructions.add(writeInstruction);
345         instructions.add(new InstructionInfo(InstructionType.goto_table, new long[]{tableId}).buildInstruction(1));
346
347         // Install the flow entry in L3_LFIB_TABLE
348         String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
349
350         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
351                 10, flowRef, 0, 0,
352                 NwConstants.COOKIE_VM_LFIB_TABLE, matches, instructions);
353
354         mdsalManager.installFlow(dpId, flowEntity);
355
356         LOG.debug("LFIB Entry for dpID {} : label : {} modified successfully {}",dpId, serviceId );
357     }
358
359     private void removeLFibTableEntry(BigInteger dpnId, long serviceId) {
360         List<MatchInfo> matches = new ArrayList<>();
361         matches.add(new MatchInfo(MatchFieldType.eth_type,
362                                   new long[] { 0x8847L }));
363         matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
364
365         String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
366
367         LOG.debug("removing LFib entry with flow ref {}", flowRef);
368
369         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
370                                                10, flowRef, 0, 0,
371                                                NwConstants.COOKIE_VM_LFIB_TABLE, matches, null);
372
373         mdsalManager.removeFlow(dpnId, flowEntity);
374
375         LOG.debug("LFIB Entry for dpID : {} label : {} removed successfully {}",dpnId, serviceId);
376     }
377
378     private void sendGarpOnInterface(final BigInteger dpnId, Uuid networkId, final String routerId,
379             final IpAddress floatingIpAddress) {
380         if (floatingIpAddress.getIpv4Address() == null) {
381             LOG.info("Failed to send GARP for IP. recieved IPv6.");
382             NatServiceCounters.garp_failed_ipv6.inc();
383             return;
384         }
385
386         String interfaceName = elanService.getExternalElanInterface(networkId.getValue(), dpnId);
387         if (interfaceName == null) {
388             LOG.warn("Failed to send GARP for IP. Failed to retrieve interface name from network {} and dpn id {}.",
389                     networkId.getValue(), dpnId);
390             NatServiceCounters.garp_failed_missing_interface.inc();
391         }
392
393         try {
394             // find the external network interface name for dpn
395             Port floatingPort = NatUtil.getNeutronPortForFloatingIp(dataBroker, floatingIpAddress);
396             PhysAddress floatingPortMac = new PhysAddress(floatingPort.getMacAddress().getValue());
397             List<InterfaceAddress> interfaceAddresses = new ArrayList<>();
398             interfaceAddresses.add(new InterfaceAddressBuilder()
399                     .setInterface(interfaceName)
400                     .setIpAddress(floatingIpAddress)
401                     .setMacaddress(floatingPortMac).build());
402
403             SendArpRequestInput sendArpRequestInput = new SendArpRequestInputBuilder().setIpaddress(floatingIpAddress)
404                     .setInterfaceAddress(interfaceAddresses).build();
405             arpUtilService.sendArpRequest(sendArpRequestInput);
406             NatServiceCounters.garp_sent.inc();
407         } catch (Exception e) {
408             LOG.error("Failed to send GARP request for floating ip {} from interface {}",
409                     floatingIpAddress.getIpv4Address().getValue(), interfaceName, e);
410             NatServiceCounters.garp_failed_send.inc();
411         }
412     }
413
414 }