Policy exclusions & parallel netconf transactions
[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 javax.annotation.Nonnull;
12
13 import org.apache.commons.lang3.tuple.Pair;
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.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCase;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.GbpSubnet;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.GpeEntry;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.RemoteEid;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.unnumbered.interfaces.rev170510.InterfaceUnnumberedAugmentation;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.unnumbered.interfaces.rev170510.InterfaceUnnumberedAugmentationBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.unnumbered.interfaces.rev170510.unnumbered.config.attributes.UnnumberedBuilder;
50 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
51 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
52 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 import com.google.common.base.Preconditions;
57
58 /**
59  * Created by Shakib Ahmed on 4/26/17.
60  */
61 public class LoopbackManager {
62     private static final Logger LOG = LoggerFactory.getLogger(LoopbackManager.class);
63
64     private ConfigManagerHelper loopbackManagerHelper;
65
66     private HostRelatedInfoContainer hostRelatedInfoContainer = HostRelatedInfoContainer.getInstance();
67     private SubnetUuidToGbpSubnetMapper subnetUuidToGbpSubnetMapper = SubnetUuidToGbpSubnetMapper.getInstance();
68     private NeutronTenantToVniMapper neutronTenantToVniMapper = NeutronTenantToVniMapper.getInstance();
69
70     public LoopbackManager(@Nonnull MountedDataBrokerProvider mountedDataBrokerProvider) {
71         this.loopbackManagerHelper = new ConfigManagerHelper(mountedDataBrokerProvider);
72     }
73
74     public void createBviLoopbackIfNeeded(AddressEndpointWithLocation addressEp,
75                                           String bridgeDomainName) {
76         try {
77             EndpointHost endpointHost = loopbackManagerHelper.getEndpointHostInformation(addressEp);
78             long vni = getVni(addressEp.getTenant().getValue());
79             long vrfId = vni;
80             String subnetUuid = loopbackManagerHelper.getSubnet(addressEp);
81
82             VrfHolder hostVrfHolder = hostRelatedInfoContainer.getVrfStateOfHost(endpointHost.getHostName());
83
84             if (!hostVrfHolder.hasVrf(vrfId)) {
85                 //dummy init for bridge domain case
86                 hostVrfHolder.initializeVrfState(vrfId, Constants.DUMMY_PROTOCOL_BRIDGE_DOMAIN);
87             }
88
89             SubnetState subnetState = hostVrfHolder.getVrfState(vni)
90                                                                             .getSubnetHolder()
91                                                                             .getSubnetState(subnetUuid);
92
93             if (!subnetState.isGwConfigured()) {
94                 return;
95             }
96
97             GbpSubnet gbpSubnetInfo = Preconditions.checkNotNull(getSubnetInfo(subnetUuid),
98                     "Subnet UUID {} hasn't been created yet!", subnetUuid);
99
100             String gwInterfaceName = loopbackManagerHelper.getGatewayInterfaceName(Constants.GW_NAME_PREFIX, subnetUuid);
101
102             LoopbackCommand bviLoopbackCommand = LoopbackCommandWrapper
103                     .bviLoopbackPutCommand(gwInterfaceName, vni, gbpSubnetInfo.getGatewayIp(), gbpSubnetInfo.getCidr(),
104                             bridgeDomainName);
105             createLoopbackInterface(endpointHost.getHostName(), subnetState, bviLoopbackCommand);
106         } catch (LispConfigCommandFailedException e) {
107             LOG.warn("LISP couldn't be configured: {}", e.getMessage());
108         }
109     }
110
111     public void createSimpleLoopbackIfNeeded(AddressEndpointWithLocation addressEp) {
112         try {
113
114             if (loopbackManagerHelper.isMetadataPort(addressEp)) {
115                 return;
116             }
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(hostName, stateOfSubnetUuid, simpleLoopbackCommand);
137                 addProxyArpRange(hostName, vrfId, gbpSubnetInfo);
138                 addGpeEntry(VppIidFactory.getNetconfNodeIid(new NodeId(hostName)), 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(String hostName,
149                                          SubnetState subnetState,
150                                          LoopbackCommand loopbackCommand) throws LispConfigCommandFailedException {
151
152         if (GbpNetconfTransaction.netconfSyncedWrite(VppIidFactory.getNetconfNodeIid(new NodeId(hostName)),
153                 loopbackCommand, GbpNetconfTransaction.RETRY_COUNT)) {
154             subnetState.setGwInterfaceName(loopbackCommand.getName());
155         } else {
156             throw new LispConfigCommandFailedException("BVI could not be created for "
157                     + hostName + " and bridge domain " + loopbackCommand.getBridgeDomain());
158         }
159     }
160
161     public void handleEndpointDelete(AddressEndpointWithLocation addressEp) {
162
163         if (loopbackManagerHelper.isMetadataPort(addressEp)) {
164             return;
165         }
166         String hostName = loopbackManagerHelper.getHostName(addressEp).get();
167         String portSubnetUuid = loopbackManagerHelper.getSubnet(addressEp);
168         long vrfId = getVni(addressEp.getTenant().getValue());
169         SubnetState subnetStateForSubnetUuid = hostRelatedInfoContainer
170                                                         .getVrfStateOfHost(hostName)
171                                                         .getVrfState(vrfId)
172                                                         .getSubnetHolder()
173                                                         .getSubnetState(portSubnetUuid);
174
175         if (!subnetStateForSubnetUuid.hasIpsInSubnet()) {
176             String gwInterfaceName = subnetStateForSubnetUuid.getGwInterfaceName();
177             GbpSubnet gbpSubnetInfo = Preconditions.checkNotNull(subnetUuidToGbpSubnetMapper.getSubnetInfo(portSubnetUuid),
178                     "Invalid port!");
179             long vni = getVni(addressEp.getTenant().getValue());
180             try {
181                 InstanceIdentifier<Node> iid = VppIidFactory.getNetconfNodeIid(new NodeId(hostName));
182                 deleteSpecificLoopback(iid, gwInterfaceName);
183                 deleteProxyArpRange(hostName, vni, gbpSubnetInfo);
184                 deleteGpeEntry(iid, Constants.GPE_ENTRY_PREFIX + gbpSubnetInfo.getId() + "_1");
185                 deleteGpeEntry(iid, Constants.GPE_ENTRY_PREFIX + gbpSubnetInfo.getId() + "_2");
186                 hostRelatedInfoContainer.getVrfStateOfHost(hostName)
187                         .getVrfState(vrfId)
188                         .getSubnetHolder()
189                         .removeSubnetState(portSubnetUuid);
190             } catch (LispConfigCommandFailedException e) {
191                 LOG.warn("Loopback not deleted properly: {}", e.getMessage());
192             }
193         }
194     }
195
196     private void deleteSpecificLoopback(InstanceIdentifier<Node> nodeIid, String interfaceName) throws LispConfigCommandFailedException {
197         if (!GbpNetconfTransaction.netconfSyncedDelete(nodeIid,
198                 VppIidFactory.getInterfaceIID(new InterfaceKey(interfaceName)), GbpNetconfTransaction.RETRY_COUNT)) {
199             throw new LispConfigCommandFailedException("Failed to delete Loopback interface!");
200         } else {
201             LOG.debug("Deleted loopback interface!");
202         }
203     }
204
205     private void addProxyArpRange(String hostName,
206                                   long vrf,
207                                   GbpSubnet gbpSubnetInfo) throws LispConfigCommandFailedException {
208         Ipv4Prefix subnetPrefix = gbpSubnetInfo.getCidr().getIpv4Prefix();
209
210         Preconditions.checkNotNull(subnetPrefix, "Subnet CIDR found to be null for "
211                 + "subnet uuid =" +  gbpSubnetInfo.getId() + "!");
212
213         Pair<Ipv4Address, Ipv4Address> startAndEndAddress = IpAddressUtil.getStartAndEndIp(subnetPrefix);
214
215         if (!putArpRangesCommand(VppIidFactory.getNetconfNodeIid(new NodeId(hostName)),
216                 vrf,
217                 startAndEndAddress.getLeft(),
218                 startAndEndAddress.getRight())) {
219             throw new LispConfigCommandFailedException("Proxy arp configuration failed for subnet uuid: " +
220                     gbpSubnetInfo.getId() + "!");
221         } else {
222             LOG.debug("Configured proxy arp for range {} to {} on node : {}!", startAndEndAddress.getLeft(),
223                     startAndEndAddress.getRight(), hostName);
224         }
225     }
226
227     private void deleteProxyArpRange(String hostName,
228                                      long vrf,
229                                      GbpSubnet gbpSubnetInfo) 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(VppIidFactory.getNetconfNodeIid(new NodeId(hostName)),
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(InstanceIdentifier<Node> iid, 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         return GbpNetconfTransaction.netconfSyncedWrite(iid, builder.build(), GbpNetconfTransaction.RETRY_COUNT);
256     }
257
258     private boolean deleteArpRangesCommand(InstanceIdentifier<Node> iid,
259                                            long vrf,
260                                            Ipv4Address start,
261                                            Ipv4Address end) {
262         ProxyRangeCommand.ProxyRangeCommandBuilder builder = new ProxyRangeCommand.ProxyRangeCommandBuilder();
263         builder.setOperation(General.Operations.DELETE);
264         builder.setVrf(vrf);
265         builder.setStartAddress(start);
266         builder.setEndAddress(end);
267         return GbpNetconfTransaction.netconfSyncedDelete(iid, builder.build(), GbpNetconfTransaction.RETRY_COUNT);
268     }
269
270     private void addUnnumberedInterface(AddressEndpointWithLocation addressEp, String loopbackName) throws LispConfigCommandFailedException {
271         ExternalLocationCase loc = ConfigManagerHelper.resolveAndValidateLocation(addressEp);
272         InstanceIdentifier<Node> nodeIid = (InstanceIdentifier<Node>) loc.getExternalNodeMountPoint();
273         String neutronInterfaceName = loopbackManagerHelper.getInterfaceName(addressEp).get();
274         if (putUnnumberedInterface(nodeIid, neutronInterfaceName, loopbackName)) {
275             LOG.debug("Added Interface {} as unnumberd for {}", loopbackName, neutronInterfaceName);
276         } else {
277             throw new LispConfigCommandFailedException("Unnumbered configuration failed for " +
278                     neutronInterfaceName + " - " + loopbackName);
279         }
280     }
281
282     private boolean putUnnumberedInterface(InstanceIdentifier<Node> iid, String interfaceFor, String interfaceWith) {
283         UnnumberedBuilder unnumberedBuilder = new UnnumberedBuilder();
284         unnumberedBuilder.setUse(interfaceWith);
285         InstanceIdentifier<Interface> interfaceIid = VppIidFactory.getInterfaceIID(new InterfaceKey(interfaceFor));
286         InterfaceUnnumberedAugmentationBuilder augBuilder = new InterfaceUnnumberedAugmentationBuilder();
287         augBuilder.setUnnumbered(unnumberedBuilder.build());
288         InterfaceBuilder interfaceBuilder = new InterfaceBuilder().setKey(new InterfaceKey(interfaceFor));
289         interfaceBuilder.addAugmentation(InterfaceUnnumberedAugmentation.class, augBuilder.build());
290         return GbpNetconfTransaction.netconfSyncedMerge(iid, interfaceIid, interfaceBuilder.build(),
291                 GbpNetconfTransaction.RETRY_COUNT);
292     }
293
294     private void addGpeEntry(InstanceIdentifier<Node> iid, GbpSubnet gbpSubnetInfo, long vni) {
295         try {
296             Pair<Ipv4Prefix, Ipv4Prefix> delegatingSubnets = IpAddressUtil
297                     .getSmallerSubnet(gbpSubnetInfo.getCidr().getIpv4Prefix());
298
299             RemoteEid firstREid = LispUtil.toRemoteEid(LispUtil.toLispIpv4Prefix(delegatingSubnets.getLeft()),
300                     vni,
301                     Ipv4PrefixAfi.class);
302             putGpeEntry(iid, Constants.GPE_ENTRY_PREFIX + gbpSubnetInfo.getId() + "_1", firstREid, vni, vni);
303
304             if (delegatingSubnets.getLeft().equals(delegatingSubnets.getRight())) {
305                 return;
306             }
307
308             RemoteEid secondREid = LispUtil.toRemoteEid(LispUtil.toLispIpv4Prefix(delegatingSubnets.getRight()),
309                     vni,
310                     Ipv4PrefixAfi.class);
311
312             putGpeEntry(iid, Constants.GPE_ENTRY_PREFIX + gbpSubnetInfo.getId() + "_2", secondREid, vni, vni);
313         } catch (LispHelperArgumentException e) {
314             e.printStackTrace();
315         }
316     }
317
318     private boolean putGpeEntry(InstanceIdentifier<Node> iid, String id, RemoteEid rEid, long vni, long vrf) {
319         AbstractLispCommand<GpeEntry> gpeEntryCommand = LispCommandWrapper
320                 .addGpeSendMapregisterAction(id, rEid, vni, vrf);
321         return LispStateCommandExecutor.executePutCommand(iid, gpeEntryCommand);
322     }
323
324     private boolean deleteGpeEntry(InstanceIdentifier<Node> iid, String id) {
325         AbstractLispCommand<GpeEntry> gpeEntryDeletionCommand = LispCommandWrapper
326                 .deleteGpeEntry(id);
327         return LispStateCommandExecutor.executeDeleteCommand(iid, gpeEntryDeletionCommand);
328     }
329
330     private long getVni(String tenantUuid) {
331         return neutronTenantToVniMapper.getVni(tenantUuid);
332     }
333
334     private GbpSubnet getSubnetInfo(String subnetUuid) {
335         return subnetUuidToGbpSubnetMapper.getSubnetInfo(subnetUuid);
336     }
337 }