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