Adjust to RPC method signature update
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / EvpnSnatFlowProgrammer.java
1 /*
2  * Copyright (c) 2017 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
9 package org.opendaylight.netvirt.natservice.internal;
10
11 import com.google.common.util.concurrent.FutureCallback;
12 import com.google.common.util.concurrent.Futures;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import com.google.common.util.concurrent.MoreExecutors;
15 import java.math.BigInteger;
16 import java.util.ArrayList;
17 import java.util.List;
18 import javax.annotation.Nonnull;
19 import javax.inject.Inject;
20 import javax.inject.Singleton;
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.MDSALUtil;
24 import org.opendaylight.genius.mdsalutil.MatchInfo;
25 import org.opendaylight.genius.mdsalutil.NwConstants;
26 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
27 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
28 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
29 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
30 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
31 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryOutput;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryOutput;
42 import org.opendaylight.yangtools.yang.common.RpcResult;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 @Singleton
47 public class EvpnSnatFlowProgrammer {
48     private static final Logger LOG = LoggerFactory.getLogger(EvpnSnatFlowProgrammer.class);
49
50     private static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
51
52     private final DataBroker dataBroker;
53     private final IMdsalApiManager mdsalManager;
54     private final IBgpManager bgpManager;
55     private final IFibManager fibManager;
56     private final FibRpcService fibService;
57     private final IdManagerService idManager;
58
59     @Inject
60     public EvpnSnatFlowProgrammer(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
61                            final IBgpManager bgpManager,
62                            final IFibManager fibManager,
63                            final FibRpcService fibService,
64                            final IdManagerService idManager) {
65         this.dataBroker = dataBroker;
66         this.mdsalManager = mdsalManager;
67         this.bgpManager = bgpManager;
68         this.fibManager = fibManager;
69         this.fibService = fibService;
70         this.idManager = idManager;
71     }
72
73     public void evpnAdvToBgpAndInstallFibAndTsFlows(final BigInteger dpnId, final short tableId,
74                                                     final String externalIp, final String vpnName, final String rd,
75                                                     final String nextHopIp, final WriteTransaction writeTx,
76                                                     final long routerId, final String routerName,
77                                                     WriteTransaction writeFlowInvTx) {
78      /*
79       * 1) Install the flow INTERNAL_TUNNEL_TABLE (table=36)-> INBOUND_NAPT_TABLE (table=44)
80       *    (FIP VM on DPN1 is responding back to external fixed IP on DPN2) {DNAT to SNAT traffic on
81       *     different Hypervisor}
82       *
83       * 2) Install the flow L3_GW_MAC_TABLE (table=19)-> INBOUND_NAPT_TABLE (table=44)
84       *    (FIP VM on DPN1 is responding back to external fixed IP on beyond DC-GW VM){DNAT to SNAT Inter DC traffic}
85       *
86       * 3) Install the flow PDNAT_TABLE (table=25)-> INBOUND_NAPT_TABLE (table=44)
87       *    (If there is no FIP Match on table 25 (PDNAT_TABLE) then default flow to INBOUND_NAPT_TABLE (table=44))
88       *
89       * 4) Install the flow L3_FIB_TABLE (table=21)-> INBOUND_NAPT_TABLE (table=44)
90       *    (FIP VM on DPN1 is responding back to external fixed Ip on DPN1 itself. ie. same Hypervisor)
91       *    {DNAT to SNAT Intra DC traffic}
92       */
93         LOG.info("evpnAdvToBgpAndInstallFibAndTsFlows : Handling SNAT Reverse Traffic for External Fixed IP {} for "
94                 + "RouterId {}", externalIp, routerId);
95         // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
96         String gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
97         if (gwMacAddress == null) {
98             LOG.error("evpnAdvToBgpAndInstallFibAndTsFlows : Unable to Retrieve External Gateway MAC address "
99                     + "from Router ID {}", routerId);
100             return;
101         }
102         //get l3Vni value for external VPN
103         long l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
104         if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
105             LOG.debug("evpnAdvToBgpAndInstallFibAndTsFlows : L3VNI value is not configured in Internet VPN {}"
106                     + " and RD {} Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue with "
107                     + "installing SNAT flows for External Fixed IP {}", vpnName, rd, externalIp);
108             l3Vni = NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, routerId).longValue();
109         }
110
111         long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
112         if (vpnId == NatConstants.INVALID_ID) {
113             LOG.error("evpnAdvToBgpAndInstallFibAndTsFlows : Invalid Vpn Id is found for Vpn Name {}",
114                     vpnName);
115             return;
116         }
117         /* As of now neither SNAT nor DNAT will use mac-address while advertising to FIB and BGP instead
118          * use only gwMacAddress. Hence default value of macAddress is null
119          */
120         //Inform to BGP
121         NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, vpnName, rd, externalIp,
122                 nextHopIp, l3Vni, null /*InterfaceName*/, gwMacAddress, writeTx, RouteOrigin.STATIC, dpnId);
123
124         //Install custom FIB routes - FIB table.
125         List<Instruction> customInstructions = new ArrayList<>();
126         customInstructions.add(new InstructionGotoTable(tableId).buildInstruction(0));
127         final String externalFixedIp = NatUtil.validateAndAddNetworkMask(externalIp);
128
129         CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
130                 .setSourceDpid(dpnId).setIpAddress(externalFixedIp)
131                 .setServiceId(l3Vni).setIpAddressSource(CreateFibEntryInput.IpAddressSource.ExternalFixedIP)
132                 .setInstruction(customInstructions).build();
133         LOG.debug("evpnAdvToBgpAndInstallFibAndTsFlows : Installing custom FIB table {} --> table {} flow on "
134                 + "NAPT Switch {} with l3Vni {}, ExternalFixedIp {}, ExternalVpnName {} for RouterId {}",
135                 NwConstants.L3_FIB_TABLE, tableId, dpnId, l3Vni, externalIp, vpnName, routerId);
136
137         ListenableFuture<RpcResult<CreateFibEntryOutput>> futureVxlan = fibService.createFibEntry(input);
138
139         final long finalL3Vni = l3Vni;
140         Futures.addCallback(futureVxlan, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
141             @Override
142             public void onFailure(@Nonnull Throwable error) {
143                 LOG.error("evpnAdvToBgpAndInstallFibAndTsFlows : Error in custom fib routes install process for "
144                         + "External Fixed IP {} on DPN {} with l3Vni {}, ExternalVpnName {} for RouterId {}",
145                         externalIp, dpnId, finalL3Vni, vpnName, routerId, error);
146             }
147
148             @Override
149             public void onSuccess(@Nonnull RpcResult<CreateFibEntryOutput> result) {
150                 if (result.isSuccessful()) {
151                     LOG.info("evpnAdvToBgpAndInstallFibAndTsFlows : Successfully installed custom FIB routes for "
152                             + "External Fixed IP {} on DPN {} with l3Vni {}, ExternalVpnName {} for RouterId {}",
153                             externalIp, dpnId, finalL3Vni, vpnName, routerId);
154
155                  /* Install the flow INTERNAL_TUNNEL_TABLE (table=36)-> INBOUND_NAPT_TABLE (table=44)
156                   * (SNAT to DNAT reverse Traffic: If traffic is Initiated from NAPT to FIP VM on different Hypervisor)
157                   */
158                     makeTunnelTableEntry(dpnId, finalL3Vni, customInstructions, tableId, writeFlowInvTx);
159                  /* Install the flow L3_GW_MAC_TABLE (table=19)-> INBOUND_NAPT_TABLE (table=44)
160                   * (SNAT reverse traffic: If the traffic is Initiated from DC-GW to VM (SNAT Reverse traffic))
161                   */
162                     NatEvpnUtil.makeL3GwMacTableEntry(dpnId, vpnId, gwMacAddress, customInstructions, mdsalManager,
163                             writeFlowInvTx);
164
165                  /* Install the flow PDNAT_TABLE (table=25)-> INBOUND_NAPT_TABLE (table=44)
166                   * If there is no FIP Match on table 25 (PDNAT_TABLE)
167                   */
168                     NatUtil.makePreDnatToSnatTableEntry(mdsalManager, dpnId, tableId, writeFlowInvTx);
169                 }
170             }
171         }, MoreExecutors.directExecutor());
172     }
173
174     public void evpnDelFibTsAndReverseTraffic(final BigInteger dpnId, final long routerId, final String externalIp,
175                                               final String vpnName, String extGwMacAddress,
176                                               WriteTransaction removeFlowInvTx) {
177      /*
178       * 1) Remove the flow INTERNAL_TUNNEL_TABLE (table=36)-> INBOUND_NAPT_TABLE (table=44)
179       *    (FIP VM on DPN1 is responding back to external fixed IP on DPN2) {DNAT to SNAT traffic on
180       *     different Hypervisor}
181       *
182       * 2) Remove the flow L3_GW_MAC_TABLE (table=19)-> INBOUND_NAPT_TABLE (table=44)
183       *    (FIP VM on DPN1 is responding back to external fixed IP on DPN1 itself){DNAT to SNAT traffic on
184       *     Same Hypervisor}
185       *
186       * 3) Remove the flow PDNAT_TABLE (table=25)-> INBOUND_NAPT_TABLE (table=44)
187       *    (If there is no FIP Match on table 25 (PDNAT_TABLE) then default flow to INBOUND_NAPT_TABLE (table=44))
188       *
189       * 4) Remove the flow L3_FIB_TABLE (table=21)-> INBOUND_NAPT_TABLE (table=44)
190       *    (FIP VM on DPN1 is responding back to external fixed Ip on DPN1 itself. ie. same Hypervisor)
191       *    {DNAT to SNAT Intra DC traffic}
192       */
193         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
194         if (rd == null) {
195             LOG.error("evpnDelFibTsAndReverseTraffic : Could not retrieve RD value from VPN Name {}", vpnName);
196             return;
197         }
198         long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
199         if (vpnId == NatConstants.INVALID_ID) {
200             LOG.error("evpnDelFibTsAndReverseTraffic : Invalid Vpn Id is found for Vpn Name {}", vpnName);
201             return;
202         }
203         if (extGwMacAddress == null) {
204             LOG.error("evpnDelFibTsAndReverseTraffic : Unable to Get External Gateway MAC address for "
205                     + "External Router ID {} ", routerId);
206             return;
207         }
208         long l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
209         if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
210             LOG.debug("evpnDelFibTsAndReverseTraffic : L3VNI value is not configured in Internet VPN {} and RD {} "
211                     + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue with installing "
212                     + "SNAT flows for External Fixed IP {}", vpnName, rd, externalIp);
213             l3Vni = NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, routerId).longValue();
214         }
215
216         final String externalFixedIp = NatUtil.validateAndAddNetworkMask(externalIp);
217         RemoveFibEntryInput input = new RemoveFibEntryInputBuilder()
218                 .setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalFixedIp)
219                 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.ExternalFixedIP).setServiceId(l3Vni).build();
220         LOG.debug("evpnDelFibTsAndReverseTraffic : Removing custom FIB table {} --> table {} flow on "
221                         + "NAPT Switch {} with l3Vni {}, ExternalFixedIp {}, ExternalVpnName {} for RouterId {}",
222                 NwConstants.L3_FIB_TABLE, NwConstants.INBOUND_NAPT_TABLE, dpnId, l3Vni, externalIp, vpnName, routerId);
223
224         ListenableFuture<RpcResult<RemoveFibEntryOutput>> futureVxlan = fibService.removeFibEntry(input);
225         final long finalL3Vni = l3Vni;
226         Futures.addCallback(futureVxlan, new FutureCallback<RpcResult<RemoveFibEntryOutput>>() {
227             @Override
228             public void onFailure(@Nonnull Throwable error) {
229                 LOG.error("evpnDelFibTsAndReverseTraffic : Error in custom fib routes remove process for "
230                         + "External Fixed IP {} on DPN {} with l3Vni {}, ExternalVpnName {} for RouterId {}",
231                         externalIp, dpnId, finalL3Vni, vpnName, routerId, error);
232             }
233
234             @Override
235             public void onSuccess(@Nonnull RpcResult<RemoveFibEntryOutput> result) {
236                 if (result.isSuccessful()) {
237                     LOG.info("evpnDelFibTsAndReverseTraffic : Successfully removed custom FIB routes for "
238                             + "External Fixed IP {} on DPN {} with l3Vni {}, ExternalVpnName {} for "
239                             + "RouterId {}", externalIp, dpnId, finalL3Vni, vpnName, routerId);
240
241                     //remove INTERNAL_TUNNEL_TABLE (table=36)-> INBOUND_NAPT_TABLE (table=44) flow
242                     removeTunnelTableEntry(dpnId, finalL3Vni, removeFlowInvTx);
243                     //remove L3_GW_MAC_TABLE (table=19)-> INBOUND_NAPT_TABLE (table=44) flow
244                     NatUtil.removePreDnatToSnatTableEntry(mdsalManager, dpnId, removeFlowInvTx);
245                     //remove PDNAT_TABLE (table=25)-> INBOUND_NAPT_TABLE (table=44) flow
246                     NatEvpnUtil.removeL3GwMacTableEntry(dpnId, vpnId, extGwMacAddress, mdsalManager, removeFlowInvTx);
247                 }
248             }
249         }, MoreExecutors.directExecutor());
250     }
251
252     public void makeTunnelTableEntry(BigInteger dpnId, long l3Vni, List<Instruction> customInstructions,
253                                      short tableId, WriteTransaction writeFlowTx) {
254         LOG.debug("makeTunnelTableEntry : Create terminating service table {} --> table {} flow on NAPT DpnId {} "
255                 + "with l3Vni {} as matching parameter", NwConstants.INTERNAL_TUNNEL_TABLE, tableId, dpnId, l3Vni);
256         List<MatchInfo> mkMatches = new ArrayList<>();
257         mkMatches.add(new MatchTunnelId(BigInteger.valueOf(l3Vni)));
258
259         Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
260                 NatEvpnUtil.getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, l3Vni, NatConstants.SNAT_FLOW_NAME), 5,
261                 String.format("%s:%d", "TST Flow Entry ", l3Vni),
262                 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(l3Vni)), mkMatches, customInstructions);
263         mdsalManager.addFlowToTx(dpnId, terminatingServiceTableFlowEntity, writeFlowTx);
264         LOG.debug("makeTunnelTableEntry : Successfully installed terminating service table flow {} on DpnId {}",
265                 terminatingServiceTableFlowEntity, dpnId);
266     }
267
268     public void removeTunnelTableEntry(BigInteger dpnId, long l3Vni, WriteTransaction removeFlowInvTx) {
269         LOG.debug("removeTunnelTableEntry : Remove terminating service table {} --> table {} flow on NAPT DpnId {} "
270                 + "with l3Vni {} as matching parameter", NwConstants.INTERNAL_TUNNEL_TABLE,
271                 NwConstants.INBOUND_NAPT_TABLE, dpnId, l3Vni);
272         List<MatchInfo> mkMatches = new ArrayList<>();
273         // Matching metadata
274         mkMatches.add(new MatchTunnelId(BigInteger.valueOf(l3Vni)));
275         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
276                 NatEvpnUtil.getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, l3Vni, NatConstants.SNAT_FLOW_NAME),
277                 5, String.format("%s:%d", "TST Flow Entry ", l3Vni), 0, 0,
278                 COOKIE_TUNNEL.add(BigInteger.valueOf(l3Vni)), mkMatches, null);
279         mdsalManager.removeFlowToTx(dpnId, flowEntity, removeFlowInvTx);
280         LOG.debug("removeTunnelTableEntry : Successfully removed terminating service table flow {} on DpnId {}",
281                 flowEntity, dpnId);
282     }
283 }