2 * Copyright (c) 2017 Cisco Systems. All rights reserved.
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
9 package org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.loopback;
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;
49 import javax.annotation.Nonnull;
50 import java.util.List;
53 * Created by Shakib Ahmed on 4/26/17.
55 public class LoopbackManager {
56 private static final Logger LOG = LoggerFactory.getLogger(LoopbackManager.class);
58 private ConfigManagerHelper loopbackManagerHelper;
60 private LoopbackHostSpecificInfoMapper subnetHostSpecificInfo;
61 private NeutronTenantToVniMapper neutronTenantToVniMapper;
62 private SubnetUuidToGbpSubnetMapper subnetUuidToGbpSubnetMapper;
64 private static final String LOOP_NAME_PREFIX = "loop-";
65 private static final String GPE_ENTRY_PREFIX = "gpe-entry-";
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();
74 public void createBviLoopbackIfNeeded(AddressEndpointWithLocation addressEp,
75 String bridgeDomainName) {
77 DataBroker vppDataBroker = loopbackManagerHelper.getPotentialExternalDataBroker(addressEp).get();
78 String hostName = loopbackManagerHelper.getHostName(addressEp).get();
79 String subnetUuid = loopbackManagerHelper.getSubnet(addressEp);
81 if (subnetHostSpecificInfo.loopbackAlreadyExists(hostName, subnetUuid)) {
82 subnetHostSpecificInfo.addNewPortInHostSubnet(hostName, subnetUuid);
86 GbpSubnet gbpSubnetInfo = Preconditions.checkNotNull(getSubnetInfo(subnetUuid),
87 "Subnet UUID {} hasn't been created yet!", subnetUuid);
89 String interfaceName = LOOP_NAME_PREFIX + subnetHostSpecificInfo.getLoopbackCount(hostName);
90 long vni = getVni(addressEp.getTenant().getValue());
92 LoopbackCommand bviLoopbackCommand = LoopbackCommandWrapper
93 .bviLoopbackPutCommand(interfaceName, vni, gbpSubnetInfo.getGatewayIp(), gbpSubnetInfo.getCidr(),
95 createLoopbackInterface(hostName, subnetUuid, vppDataBroker, bviLoopbackCommand);
96 } catch (LispConfigCommandFailedException e) {
97 LOG.warn("LISP couldn't be configured: {}", e.getMessage());
101 public void createSimpleLoopbackIfNeeded(AddressEndpointWithLocation addressEp) {
104 if (loopbackManagerHelper.isMetadataPort(addressEp)) {
105 // if the address endpoint is a metadataport, no proxy arp range needed.
109 DataBroker vppDataBroker = loopbackManagerHelper.getPotentialExternalDataBroker(addressEp).get();
110 String hostName = loopbackManagerHelper.getHostName(addressEp).get();
111 String subnetUuid = loopbackManagerHelper.getSubnet(addressEp);
113 if (subnetHostSpecificInfo.loopbackAlreadyExists(hostName, subnetUuid)) {
114 subnetHostSpecificInfo.addNewPortInHostSubnet(hostName, subnetUuid);
115 String loopbackInterfaceName = subnetHostSpecificInfo
116 .getInterfaceNameForLoopbackInHost(hostName, subnetUuid);
117 addUnnumberedInterface(addressEp, loopbackInterfaceName);
121 String interfaceName = LOOP_NAME_PREFIX + subnetHostSpecificInfo.getLoopbackCount(hostName);
122 long vni = getVni(addressEp.getTenant().getValue());
125 GbpSubnet gbpSubnetInfo = Preconditions.checkNotNull(getSubnetInfo(subnetUuid),
126 "Subnet UUID {} hasn't been created yet!", subnetUuid);
128 LoopbackCommand simpleLoopbackCommand = LoopbackCommandWrapper
129 .simpleLoopbackPutCommand(interfaceName, vrf, gbpSubnetInfo.getGatewayIp(),
130 gbpSubnetInfo.getCidr());
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());
141 private void createLoopbackInterface(String hostName, String subnetUuid, DataBroker vppDataBroker,
142 LoopbackCommand loopbackCommand) throws LispConfigCommandFailedException {
144 if (GbpNetconfTransaction.netconfSyncedWrite(vppDataBroker,
146 GbpNetconfTransaction.RETRY_COUNT)) {
147 subnetHostSpecificInfo.addLoopbackForHost(hostName, subnetUuid, loopbackCommand.getName(),
148 loopbackCommand.getVrfId());
149 subnetHostSpecificInfo.addNewPortInHostSubnet(hostName, subnetUuid);
151 throw new LispConfigCommandFailedException("BVI could not be created for "
152 + hostName + " and bridge domain " + loopbackCommand.getBridgeDomain());
156 public void deleteLoopbackIfExists(String subnetUuid) {
158 List<String> hostsWithSubnet = subnetHostSpecificInfo.getHostsWithSubnet(subnetUuid);
160 hostsWithSubnet.forEach(host -> {
161 DataBroker vppDataBroker = loopbackManagerHelper.getPotentialExternalDataBroker(host).get();
162 String interfaceName = subnetHostSpecificInfo.getInterfaceNameForLoopbackInHost(host, subnetUuid);
165 deleteSpecificLoopback(vppDataBroker, interfaceName);
166 } catch (LispConfigCommandFailedException e) {
171 subnetHostSpecificInfo.clearSubnet(subnetUuid);
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),
182 long vni = getVni(addressEp.getTenant().getValue());
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());
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!");
199 LOG.debug("Deleted loopback interface!");
203 private void addProxyArpRange(DataBroker vppDataBroker,
205 GbpSubnet gbpSubnetInfo,
206 String hostName) throws LispConfigCommandFailedException {
207 Ipv4Prefix subnetPrefix = gbpSubnetInfo.getCidr().getIpv4Prefix();
209 Preconditions.checkNotNull(subnetPrefix, "Subnet CIDR found to be null for "
210 + "subnet uuid =" + gbpSubnetInfo.getId() + "!");
212 Pair<Ipv4Address, Ipv4Address> startAndEndAddress = IpAddressUtil.getStartAndEndIp(subnetPrefix);
214 if (!putArpRangesCommand(vppDataBroker,
216 startAndEndAddress.getLeft(),
217 startAndEndAddress.getRight())) {
218 throw new LispConfigCommandFailedException("Proxy arp configuration failed for subnet uuid: " +
219 gbpSubnetInfo.getId() + "!");
221 LOG.debug("Configured proxy arp for range {} to {} on node : {}!", startAndEndAddress.getLeft(),
222 startAndEndAddress.getRight(), hostName);
226 private void deleteProxyArpRange(DataBroker vppDataBroker,
228 GbpSubnet gbpSubnetInfo,
229 String hostName) throws LispConfigCommandFailedException {
230 Ipv4Prefix subnetPrefix = gbpSubnetInfo.getCidr().getIpv4Prefix();
232 Preconditions.checkNotNull(subnetPrefix, "Subnet CIDR found to be null for "
233 + "subnet uuid =" + gbpSubnetInfo.getId() + "!");
235 Pair<Ipv4Address, Ipv4Address> startAndEndAddress = IpAddressUtil.getStartAndEndIp(subnetPrefix);
237 if (!deleteArpRangesCommand(vppDataBroker,
239 startAndEndAddress.getLeft(),
240 startAndEndAddress.getRight())) {
241 throw new LispConfigCommandFailedException("Proxy arp configuration failed for subnet uuid: " +
242 gbpSubnetInfo.getId() + "!");
244 LOG.debug("Removed proxy arp for range {} to {} on node : {}!", startAndEndAddress.getLeft(),
245 startAndEndAddress.getRight(), hostName);
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);
253 builder.setStartAddress(start);
254 builder.setEndAddress(end);
256 return GbpNetconfTransaction.netconfSyncedWrite(vppDataBroker,
258 GbpNetconfTransaction.RETRY_COUNT);
261 private boolean deleteArpRangesCommand(DataBroker vppDataBroker,
265 ProxyRangeCommand.ProxyRangeCommandBuilder builder = new ProxyRangeCommand.ProxyRangeCommandBuilder();
266 builder.setOperation(General.Operations.DELETE);
268 builder.setStartAddress(start);
269 builder.setEndAddress(end);
271 return GbpNetconfTransaction.netconfSyncedDelete(vppDataBroker,
273 GbpNetconfTransaction.RETRY_COUNT);
276 private void addUnnumberedInterface(AddressEndpointWithLocation addressEp, String loopbackName) throws LispConfigCommandFailedException {
277 DataBroker vppDataBroker = loopbackManagerHelper.getPotentialExternalDataBroker(addressEp).get();
278 String neutronInterfaceName = loopbackManagerHelper.getInterfaceName(addressEp).get();
280 if (putUnnumberedInterface(vppDataBroker, neutronInterfaceName, loopbackName)) {
281 LOG.debug("Added Interface {} as unnumberd for {}", loopbackName, neutronInterfaceName);
283 throw new LispConfigCommandFailedException("Unnumbered configuration failed for " +
284 neutronInterfaceName + " - " + loopbackName);
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,
298 interfaceBuilder.build(),
299 GbpNetconfTransaction.RETRY_COUNT);
302 private void addGpeEntry(DataBroker vppDataBroker, GbpSubnet gbpSubnetInfo, long vni) {
304 Pair<Ipv4Prefix, Ipv4Prefix> delegatingSubnets = IpAddressUtil
305 .getSmallerSubnet(gbpSubnetInfo.getCidr().getIpv4Prefix());
307 RemoteEid firstREid = LispUtil.toRemoteEid(LispUtil.toLispIpv4Prefix(delegatingSubnets.getLeft()),
309 Ipv4PrefixAfi.class);
310 putGpeEntry(vppDataBroker, GPE_ENTRY_PREFIX + gbpSubnetInfo.getId() + "_1", firstREid, vni, vni);
312 if (delegatingSubnets.getLeft().equals(delegatingSubnets.getRight())) {
316 RemoteEid secondREid = LispUtil.toRemoteEid(LispUtil.toLispIpv4Prefix(delegatingSubnets.getRight()),
318 Ipv4PrefixAfi.class);
320 putGpeEntry(vppDataBroker, GPE_ENTRY_PREFIX + gbpSubnetInfo.getId() + "_2", secondREid, vni, vni);
321 } catch (LispHelperArgumentException e) {
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);
332 private boolean deleteGpeEntry(DataBroker vppDataBroker, String id) {
333 AbstractLispCommand<GpeEntry> gpeEntryDeletionCommand = LispCommandWrapper
335 return LispStateCommandExecutor.executeDeleteCommand(vppDataBroker, gpeEntryDeletionCommand);
338 private long getVni(String tenantUuid) {
339 return neutronTenantToVniMapper.getVni(tenantUuid);
342 private GbpSubnet getSubnetInfo(String subnetUuid) {
343 return subnetUuidToGbpSubnetMapper.getSubnetInfo(subnetUuid);