Simplify overlay information mappers and managers
[groupbasedpolicy.git] / renderers / vpp / src / main / java / org / opendaylight / groupbasedpolicy / renderer / vpp / lisp / loopback / LoopbackManager.java
1 /*
2  * Copyright (c) 2017 Cisco Systems. 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.groupbasedpolicy.renderer.vpp.lisp.loopback;
10
11 import com.google.common.base.Preconditions;
12 import org.apache.commons.lang3.tuple.Pair;
13 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
14 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.LoopbackCommand;
15 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.LoopbackCommandWrapper;
16 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.ProxyRangeCommand;
17 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.lisp.AbstractLispCommand;
18 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.lisp.LispCommandWrapper;
19 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.LispStateCommandExecutor;
20 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.exception.LispConfigCommandFailedException;
21 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.exception.LispHelperArgumentException;
22 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.info.container.EndpointHost;
23 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.info.container.HostRelatedInfoContainer;
24 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.info.container.states.SubnetState;
25 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.info.container.states.VrfHolder;
26 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.mappers.NeutronTenantToVniMapper;
27 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.mappers.SubnetUuidToGbpSubnetMapper;
28 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.util.ConfigManagerHelper;
29 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.util.Constants;
30 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.util.IpAddressUtil;
31 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.GbpNetconfTransaction;
32 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General;
33 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.LispUtil;
34 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;
35 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.Ipv4PrefixAfi;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.GbpSubnet;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.GpeEntry;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.RemoteEid;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.unnumbered.interfaces.rev170510.InterfaceUnnumberedAugmentation;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.unnumbered.interfaces.rev170510.InterfaceUnnumberedAugmentationBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.unnumbered.interfaces.rev170510.unnumbered.config.attributes.UnnumberedBuilder;
49 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 import javax.annotation.Nonnull;
54
55 /**
56  * Created by Shakib Ahmed on 4/26/17.
57  */
58 public class LoopbackManager {
59     private static final Logger LOG = LoggerFactory.getLogger(LoopbackManager.class);
60
61     private ConfigManagerHelper loopbackManagerHelper;
62
63     private HostRelatedInfoContainer hostRelatedInfoContainer = HostRelatedInfoContainer.getInstance();
64     private SubnetUuidToGbpSubnetMapper subnetUuidToGbpSubnetMapper = SubnetUuidToGbpSubnetMapper.getInstance();
65     private NeutronTenantToVniMapper neutronTenantToVniMapper = NeutronTenantToVniMapper.getInstance();
66
67     public LoopbackManager(@Nonnull MountedDataBrokerProvider mountedDataBrokerProvider) {
68         this.loopbackManagerHelper = new ConfigManagerHelper(mountedDataBrokerProvider);
69     }
70
71     public void createBviLoopbackIfNeeded(AddressEndpointWithLocation addressEp,
72                                           String bridgeDomainName) {
73         try {
74             EndpointHost endpointHost = loopbackManagerHelper.getEndpointHostInformation(addressEp);
75             long vni = getVni(addressEp.getTenant().getValue());
76             long vrfId = vni;
77             String subnetUuid = loopbackManagerHelper.getSubnet(addressEp);
78
79             VrfHolder hostVrfHolder = hostRelatedInfoContainer.getVrfStateOfHost(endpointHost.getHostName());
80
81             if (!hostVrfHolder.hasVrf(vrfId)) {
82                 //dummy init for bridge domain case
83                 hostVrfHolder.initializeVrfState(vrfId, Constants.DUMMY_PROTOCOL_BRIDGE_DOMAIN);
84             }
85
86             SubnetState subnetState = hostVrfHolder.getVrfState(vni)
87                                                                             .getSubnetHolder()
88                                                                             .getSubnetState(subnetUuid);
89
90             if (!subnetState.isGwConfigured()) {
91                 return;
92             }
93
94             GbpSubnet gbpSubnetInfo = Preconditions.checkNotNull(getSubnetInfo(subnetUuid),
95                     "Subnet UUID {} hasn't been created yet!", subnetUuid);
96
97             String gwInterfaceName = loopbackManagerHelper.getGatewayInterfaceName(Constants.GW_NAME_PREFIX, subnetUuid);
98
99             LoopbackCommand bviLoopbackCommand = LoopbackCommandWrapper
100                     .bviLoopbackPutCommand(gwInterfaceName, vni, gbpSubnetInfo.getGatewayIp(), gbpSubnetInfo.getCidr(),
101                             bridgeDomainName);
102             createLoopbackInterface(endpointHost.getHostDataBroker(), endpointHost.getHostName(),
103                     subnetState, bviLoopbackCommand);
104         } catch (LispConfigCommandFailedException e) {
105             LOG.warn("LISP couldn't be configured: {}", e.getMessage());
106         }
107     }
108
109     public void createSimpleLoopbackIfNeeded(AddressEndpointWithLocation addressEp) {
110         try {
111
112             if (loopbackManagerHelper.isMetadataPort(addressEp)) {
113                 return;
114             }
115
116             DataBroker vppDataBroker = loopbackManagerHelper.getPotentialExternalDataBroker(addressEp).get();
117             String hostName = loopbackManagerHelper.getHostName(addressEp).get();
118             long vni = getVni(addressEp.getTenant().getValue());
119             long vrfId = vni;
120             String subnetUuid = loopbackManagerHelper.getSubnet(addressEp);
121
122             SubnetState stateOfSubnetUuid = hostRelatedInfoContainer
123                                                             .getVrfStateOfHost(hostName)
124                                                             .getVrfState(vrfId).getSubnetHolder()
125                                                             .getSubnetState(subnetUuid);
126
127             GbpSubnet gbpSubnetInfo = Preconditions.checkNotNull(getSubnetInfo(subnetUuid),
128                     "Subnet UUID {} hasn't been created yet!", subnetUuid);
129
130             if (!stateOfSubnetUuid.isGwConfigured()) {
131                 String interfaceName = loopbackManagerHelper.getGatewayInterfaceName(Constants.GW_NAME_PREFIX,
132                         subnetUuid);
133                 LoopbackCommand simpleLoopbackCommand = LoopbackCommandWrapper
134                         .simpleLoopbackPutCommand(interfaceName, vrfId, gbpSubnetInfo.getGatewayIp(),
135                                 gbpSubnetInfo.getCidr());
136                 createLoopbackInterface(vppDataBroker, hostName, stateOfSubnetUuid, simpleLoopbackCommand);
137                 addProxyArpRange(vppDataBroker, hostName, vrfId, gbpSubnetInfo);
138                 addGpeEntry(vppDataBroker, gbpSubnetInfo, vni);
139             }
140
141             String gwInterfaceName = stateOfSubnetUuid.getGwInterfaceName();
142             addUnnumberedInterface(addressEp, gwInterfaceName);
143         } catch (LispConfigCommandFailedException e) {
144             LOG.warn("LISP couldn't be configured: {}", e.getMessage());
145         }
146     }
147
148     private void createLoopbackInterface(DataBroker vppDataBroker, String hostName,
149                                          SubnetState subnetState,
150                                          LoopbackCommand loopbackCommand) throws LispConfigCommandFailedException {
151
152         if (GbpNetconfTransaction.netconfSyncedWrite(vppDataBroker,
153                 loopbackCommand,
154                 GbpNetconfTransaction.RETRY_COUNT)) {
155             subnetState.setGwInterfaceName(loopbackCommand.getName());
156         } else {
157             throw new LispConfigCommandFailedException("BVI could not be created for "
158                     + hostName + " and bridge domain " + loopbackCommand.getBridgeDomain());
159         }
160     }
161
162     public void handleEndpointDelete(AddressEndpointWithLocation addressEp) {
163
164         if (loopbackManagerHelper.isMetadataPort(addressEp)) {
165             return;
166         }
167
168         DataBroker vppDataBroker = loopbackManagerHelper.getPotentialExternalDataBroker(addressEp).get();
169         String hostName = loopbackManagerHelper.getHostName(addressEp).get();
170         String portSubnetUuid = loopbackManagerHelper.getSubnet(addressEp);
171         long vrfId = getVni(addressEp.getTenant().getValue());
172         SubnetState subnetStateForSubnetUuid = hostRelatedInfoContainer
173                                                         .getVrfStateOfHost(hostName)
174                                                         .getVrfState(vrfId)
175                                                         .getSubnetHolder()
176                                                         .getSubnetState(portSubnetUuid);
177
178         if (!subnetStateForSubnetUuid.hasIpsInSubnet()) {
179             String gwInterfaceName = subnetStateForSubnetUuid.getGwInterfaceName();
180             GbpSubnet gbpSubnetInfo = Preconditions.checkNotNull(subnetUuidToGbpSubnetMapper.getSubnetInfo(portSubnetUuid),
181                     "Invalid port!");
182             long vni = getVni(addressEp.getTenant().getValue());
183             try {
184                 deleteSpecificLoopback(vppDataBroker, gwInterfaceName);
185                 deleteProxyArpRange(vppDataBroker, hostName, vni, gbpSubnetInfo);
186                 deleteGpeEntry(vppDataBroker, Constants.GPE_ENTRY_PREFIX + gbpSubnetInfo.getId() + "_1");
187                 deleteGpeEntry(vppDataBroker, Constants.GPE_ENTRY_PREFIX + gbpSubnetInfo.getId() + "_2");
188                 hostRelatedInfoContainer.getVrfStateOfHost(hostName)
189                         .getVrfState(vrfId)
190                         .getSubnetHolder()
191                         .removeSubnetState(portSubnetUuid);
192             } catch (LispConfigCommandFailedException e) {
193                 LOG.warn("Loopback not deleted properly: {}", e.getMessage());
194             }
195         }
196     }
197
198     private void deleteSpecificLoopback(DataBroker vppDataBroker, String interfaceName) throws LispConfigCommandFailedException {
199         if (!GbpNetconfTransaction.netconfSyncedDelete(vppDataBroker,
200                 VppIidFactory.getInterfaceIID(new InterfaceKey(interfaceName)), GbpNetconfTransaction.RETRY_COUNT)) {
201             throw new LispConfigCommandFailedException("Failed to delete Loopback interface!");
202         } else {
203             LOG.debug("Deleted loopback interface!");
204         }
205     }
206
207     private void addProxyArpRange(DataBroker vppDataBroker,
208                                   String hostName,
209                                   long vrf,
210                                   GbpSubnet gbpSubnetInfo) throws LispConfigCommandFailedException {
211         Ipv4Prefix subnetPrefix = gbpSubnetInfo.getCidr().getIpv4Prefix();
212
213         Preconditions.checkNotNull(subnetPrefix, "Subnet CIDR found to be null for "
214                 + "subnet uuid =" +  gbpSubnetInfo.getId() + "!");
215
216         Pair<Ipv4Address, Ipv4Address> startAndEndAddress = IpAddressUtil.getStartAndEndIp(subnetPrefix);
217
218         if (!putArpRangesCommand(vppDataBroker,
219                 vrf,
220                 startAndEndAddress.getLeft(),
221                 startAndEndAddress.getRight())) {
222             throw new LispConfigCommandFailedException("Proxy arp configuration failed for subnet uuid: " +
223                     gbpSubnetInfo.getId() + "!");
224         } else {
225             LOG.debug("Configured proxy arp for range {} to {} on node : {}!", startAndEndAddress.getLeft(),
226                     startAndEndAddress.getRight(), hostName);
227         }
228     }
229
230     private void deleteProxyArpRange(DataBroker vppDataBroker,
231                                      String hostName,
232                                      long vrf,
233                                      GbpSubnet gbpSubnetInfo) throws LispConfigCommandFailedException {
234         Ipv4Prefix subnetPrefix = gbpSubnetInfo.getCidr().getIpv4Prefix();
235
236         Preconditions.checkNotNull(subnetPrefix, "Subnet CIDR found to be null for "
237                 + "subnet uuid =" +  gbpSubnetInfo.getId() + "!");
238
239         Pair<Ipv4Address, Ipv4Address> startAndEndAddress = IpAddressUtil.getStartAndEndIp(subnetPrefix);
240
241         if (!deleteArpRangesCommand(vppDataBroker,
242                 vrf,
243                 startAndEndAddress.getLeft(),
244                 startAndEndAddress.getRight())) {
245             throw new LispConfigCommandFailedException("Proxy arp configuration failed for subnet uuid: " +
246                     gbpSubnetInfo.getId() + "!");
247         } else {
248             LOG.debug("Removed proxy arp for range {} to {} on node : {}!", startAndEndAddress.getLeft(),
249                     startAndEndAddress.getRight(), hostName);
250         }
251     }
252
253     private boolean putArpRangesCommand(DataBroker vppDataBroker, long vrf, Ipv4Address start, Ipv4Address end) {
254         ProxyRangeCommand.ProxyRangeCommandBuilder builder = new ProxyRangeCommand.ProxyRangeCommandBuilder();
255         builder.setOperation(General.Operations.PUT);
256         builder.setVrf(vrf);
257         builder.setStartAddress(start);
258         builder.setEndAddress(end);
259
260         return GbpNetconfTransaction.netconfSyncedWrite(vppDataBroker,
261                 builder.build(),
262                 GbpNetconfTransaction.RETRY_COUNT);
263     }
264
265     private boolean deleteArpRangesCommand(DataBroker vppDataBroker,
266                                            long vrf,
267                                            Ipv4Address start,
268                                            Ipv4Address end) {
269         ProxyRangeCommand.ProxyRangeCommandBuilder builder = new ProxyRangeCommand.ProxyRangeCommandBuilder();
270         builder.setOperation(General.Operations.DELETE);
271         builder.setVrf(vrf);
272         builder.setStartAddress(start);
273         builder.setEndAddress(end);
274
275         return GbpNetconfTransaction.netconfSyncedDelete(vppDataBroker,
276                 builder.build(),
277                 GbpNetconfTransaction.RETRY_COUNT);
278     }
279
280     private void addUnnumberedInterface(AddressEndpointWithLocation addressEp, String loopbackName) throws LispConfigCommandFailedException {
281         DataBroker vppDataBroker = loopbackManagerHelper.getPotentialExternalDataBroker(addressEp).get();
282         String neutronInterfaceName = loopbackManagerHelper.getInterfaceName(addressEp).get();
283
284         if (putUnnumberedInterface(vppDataBroker, neutronInterfaceName, loopbackName)) {
285             LOG.debug("Added Interface {} as unnumberd for {}", loopbackName, neutronInterfaceName);
286         } else {
287             throw new LispConfigCommandFailedException("Unnumbered configuration failed for " +
288                     neutronInterfaceName + " - " + loopbackName);
289         }
290     }
291
292     private boolean putUnnumberedInterface(DataBroker vppDataBroker, String interfaceFor, String interfaceWith) {
293         UnnumberedBuilder unnumberedBuilder = new UnnumberedBuilder();
294         unnumberedBuilder.setUse(interfaceWith);
295         InstanceIdentifier<Interface> interfaceIid = VppIidFactory.getInterfaceIID(new InterfaceKey(interfaceFor));
296         InterfaceUnnumberedAugmentationBuilder augBuilder = new InterfaceUnnumberedAugmentationBuilder();
297         augBuilder.setUnnumbered(unnumberedBuilder.build());
298         InterfaceBuilder interfaceBuilder = new InterfaceBuilder().setKey(new InterfaceKey(interfaceFor));
299         interfaceBuilder.addAugmentation(InterfaceUnnumberedAugmentation.class, augBuilder.build());
300         return GbpNetconfTransaction.netconfSyncedMerge(vppDataBroker,
301                 interfaceIid,
302                 interfaceBuilder.build(),
303                 GbpNetconfTransaction.RETRY_COUNT);
304     }
305
306     private void addGpeEntry(DataBroker vppDataBroker, GbpSubnet gbpSubnetInfo, long vni) {
307         try {
308             Pair<Ipv4Prefix, Ipv4Prefix> delegatingSubnets = IpAddressUtil
309                     .getSmallerSubnet(gbpSubnetInfo.getCidr().getIpv4Prefix());
310
311             RemoteEid firstREid = LispUtil.toRemoteEid(LispUtil.toLispIpv4Prefix(delegatingSubnets.getLeft()),
312                     vni,
313                     Ipv4PrefixAfi.class);
314             putGpeEntry(vppDataBroker, Constants.GPE_ENTRY_PREFIX + gbpSubnetInfo.getId() + "_1", firstREid, vni, vni);
315
316             if (delegatingSubnets.getLeft().equals(delegatingSubnets.getRight())) {
317                 return;
318             }
319
320             RemoteEid secondREid = LispUtil.toRemoteEid(LispUtil.toLispIpv4Prefix(delegatingSubnets.getRight()),
321                     vni,
322                     Ipv4PrefixAfi.class);
323
324             putGpeEntry(vppDataBroker, Constants.GPE_ENTRY_PREFIX + gbpSubnetInfo.getId() + "_2", secondREid, vni, vni);
325         } catch (LispHelperArgumentException e) {
326             e.printStackTrace();
327         }
328     }
329
330     private boolean putGpeEntry(DataBroker vppDataBroker, String id, RemoteEid rEid, long vni, long vrf) {
331         AbstractLispCommand<GpeEntry> gpeEntryCommand = LispCommandWrapper
332                 .addGpeSendMapregisterAction(id, rEid, vni, vrf);
333         return LispStateCommandExecutor.executePutCommand(vppDataBroker, gpeEntryCommand);
334     }
335
336     private boolean deleteGpeEntry(DataBroker vppDataBroker, String id) {
337         AbstractLispCommand<GpeEntry> gpeEntryDeletionCommand = LispCommandWrapper
338                 .deleteGpeEntry(id);
339         return LispStateCommandExecutor.executeDeleteCommand(vppDataBroker, gpeEntryDeletionCommand);
340     }
341
342     private long getVni(String tenantUuid) {
343         return neutronTenantToVniMapper.getVni(tenantUuid);
344     }
345
346     private GbpSubnet getSubnetInfo(String subnetUuid) {
347         return subnetUuidToGbpSubnetMapper.getSubnetInfo(subnetUuid);
348     }
349 }