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.Optional;
12 import com.google.common.base.Preconditions;
13 import com.google.common.collect.HashBasedTable;
14 import com.google.common.collect.Lists;
15 import com.google.common.collect.Table;
17 import java.util.HashMap;
18 import java.util.List;
21 import org.apache.commons.lang3.tuple.Pair;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.LoopbackCommand;
24 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.LoopbackCommandWrapper;
25 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.ProxyRangeCommand;
26 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.UnnumberedInterfaceCommand;
27 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.lisp.AbstractLispCommand;
28 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.lisp.LispCommandWrapper;
29 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.LispStateCommandExecutor;
30 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.exception.LispConfigCommandFailedException;
31 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.exception.LispArgumentException;
32 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.flat.overlay.FlatOverlayManager;
33 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.mappers.NeutronTenantToVniMapper;
34 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.util.ConfigManagerHelper;
35 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.util.Constants;
36 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.util.IpAddressUtil;
37 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.GbpNetconfTransaction;
38 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General;
39 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.LispUtil;
40 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.Ipv4PrefixAfi;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.IpPrefixType;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.GbpSubnet;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170801.gpe.entry.table.grouping.gpe.entry.table.GpeEntry;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170801.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.RemoteEid;
51 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
52 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
53 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
54 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
59 * Created by Shakib Ahmed on 4/26/17.
61 public class LoopbackManager {
62 private static final Logger LOG = LoggerFactory.getLogger(LoopbackManager.class);
64 private ConfigManagerHelper configManagerHelper;
65 private Table<NodeKey, String, List<String>> unnumberedCache = HashBasedTable.create();
67 private NeutronTenantToVniMapper neutronTenantToVniMapper = NeutronTenantToVniMapper.getInstance();
70 private Map<String, GbpSubnet> GbpSubnetCache = new HashMap<>();
71 private Map<String, List<LoopBackDetails>> loopBackHostnames = new HashMap<>();
73 private class LoopBackDetails {
74 private LoopbackCommand loopbackCommand;
75 private String hostName;
77 LoopbackCommand getLoopbackCommand() {
78 return loopbackCommand;
81 void setLoopbackCommand(LoopbackCommand loopbackCommand) {
82 this.loopbackCommand = loopbackCommand;
85 String getHostName() {
89 void setHostName(String hostName) {
90 this.hostName = hostName;
95 public LoopbackManager() {
96 this.configManagerHelper = new ConfigManagerHelper();
99 public void createSimpleLoopbackIfNeeded(AddressEndpointWithLocation addressEp) {
100 if (!addressEp.getAddressType().equals(IpPrefixType.class)) {
103 Map<String, String> intfcsByHostname = FlatOverlayManager.resolveIntfcsByHosts(addressEp);
105 intfcsByHostname.forEach((hostname, interfaceName) -> {
107 long vni = getVni(addressEp.getTenant().getValue());
109 String subnetUuid = configManagerHelper.getSubnet(addressEp);
110 GbpSubnet gbpSubnetInfo = GbpSubnetCache.get(subnetUuid);
111 String loopIntfcName = Constants.GW_NAME_PREFIX + subnetUuid;
113 if (gbpSubnetInfo != null) {
114 Optional<Interface> optionalLoopback =
115 GbpNetconfTransaction.read(VppIidFactory.getNetconfNodeIid(new NodeId(hostname)),
116 LogicalDatastoreType.CONFIGURATION,
117 VppIidFactory.getInterfaceIID(new InterfaceKey(loopIntfcName)),
118 GbpNetconfTransaction.RETRY_COUNT);
119 if (!optionalLoopback.isPresent()) {
120 LoopbackCommand simpleLoopbackCommand =
121 LoopbackCommandWrapper.simpleLoopbackPutCommand(loopIntfcName, vrfId,
122 gbpSubnetInfo.getGatewayIp(), gbpSubnetInfo.getCidr());
123 if (createLoopbackInterface(hostname, simpleLoopbackCommand)) {
124 addGpeEntry(VppIidFactory.getNetconfNodeIid(new NodeId(hostname)), gbpSubnetInfo, vni);
125 addProxyArpRange(hostname, vrfId, gbpSubnetInfo);
126 if(loopBackHostnames.get(loopIntfcName) == null) {
127 LoopBackDetails loopBackDetails = new LoopBackDetails();
128 loopBackDetails.setHostName(hostname);
129 loopBackDetails.setLoopbackCommand(simpleLoopbackCommand);
130 loopBackHostnames.put(loopIntfcName, Lists.newArrayList(loopBackDetails));
132 LoopBackDetails loopBackDetails = new LoopBackDetails();
133 loopBackDetails.setHostName(hostname);
134 loopBackDetails.setLoopbackCommand(simpleLoopbackCommand);
135 loopBackHostnames.get(loopIntfcName).add(loopBackDetails);
139 LOG.trace("Loopback already present on host: {} skip update for: {} - {} in vrf: {}", hostname,
140 loopIntfcName, gbpSubnetInfo.getGatewayIp(), vrfId);
145 if (!addUnnumberedInterface(hostname, interfaceName, loopIntfcName)){
146 LOG.warn("Failed to add unnumbered for addressEp : {}", addressEp);
148 } catch (LispConfigCommandFailedException e) {
149 LOG.warn("LISP couldn't be configured: {}", e.getMessage());
157 private boolean createLoopbackInterface(String hostName, LoopbackCommand loopbackCommand){
159 return GbpNetconfTransaction.netconfSyncedWrite(VppIidFactory.getNetconfNodeIid(new NodeId(hostName)),
160 loopbackCommand, GbpNetconfTransaction.RETRY_COUNT);
163 private boolean deleteSpecificLoopback(InstanceIdentifier<Node> nodeIid, String loopbackName) {
164 LOG.trace("deleteSpecificLoopback -> nodeiid: {}, loopbackInterface: {}", nodeIid, loopbackName);
165 if (unnumberedCache.get(new NodeKey(nodeIid.firstKeyOf(Node.class)), loopbackName) != null) {
166 unnumberedCache.get(new NodeKey(nodeIid.firstKeyOf(Node.class)), loopbackName).forEach(intfc -> {
167 if (GbpNetconfTransaction.netconfSyncedDelete(nodeIid,
168 VppIidFactory.getUnnumberedIid(new InterfaceKey(intfc)), GbpNetconfTransaction.RETRY_COUNT)) {
169 unnumberedCache.remove(new NodeKey(nodeIid.firstKeyOf(Node.class)), loopbackName);
173 return GbpNetconfTransaction.netconfSyncedDelete(nodeIid,
174 VppIidFactory.getInterfaceIID(new InterfaceKey(loopbackName)), GbpNetconfTransaction.RETRY_COUNT);
177 private void addProxyArpRange(String hostName,
179 GbpSubnet gbpSubnetInfo) throws LispConfigCommandFailedException {
180 Ipv4Prefix subnetPrefix = gbpSubnetInfo.getCidr().getIpv4Prefix();
182 Preconditions.checkNotNull(subnetPrefix, "Subnet CIDR found to be null for "
183 + "subnet uuid =" + gbpSubnetInfo.getId() + "!");
185 Pair<Ipv4Address, Ipv4Address> startAndEndAddress = IpAddressUtil.getStartAndEndIp(subnetPrefix);
187 if (!putArpRangesCommand(VppIidFactory.getNetconfNodeIid(new NodeId(hostName)), vrf,
188 startAndEndAddress.getLeft(), startAndEndAddress.getRight())) {
189 throw new LispConfigCommandFailedException("Proxy arp configuration failed for subnet uuid: " +
190 gbpSubnetInfo.getId() + "!");
192 LOG.debug("Configured proxy arp for range {} to {} on node : {}!", startAndEndAddress.getLeft(),
193 startAndEndAddress.getRight(), hostName);
197 private boolean deleteProxyArpRange(String hostName, long vrf, GbpSubnet gbpSubnetInfo) {
198 Ipv4Prefix subnetPrefix = gbpSubnetInfo.getCidr().getIpv4Prefix();
200 Preconditions.checkNotNull(subnetPrefix, "Subnet CIDR found to be null for "
201 + "subnet uuid =" + gbpSubnetInfo.getId() + "!");
203 Pair<Ipv4Address, Ipv4Address> startAndEndAddress = IpAddressUtil.getStartAndEndIp(subnetPrefix);
205 return (deleteArpRangesCommand(VppIidFactory.getNetconfNodeIid(new NodeId(hostName)), vrf,
206 startAndEndAddress.getLeft(), startAndEndAddress.getRight()));
209 private boolean putArpRangesCommand(InstanceIdentifier<Node> iid, long vrf, Ipv4Address start, Ipv4Address end) {
210 ProxyRangeCommand.ProxyRangeCommandBuilder builder = new ProxyRangeCommand.ProxyRangeCommandBuilder();
211 builder.setOperation(General.Operations.PUT);
213 builder.setStartAddress(start);
214 builder.setEndAddress(end);
215 return GbpNetconfTransaction.netconfSyncedWrite(iid, builder.build(), GbpNetconfTransaction.RETRY_COUNT);
218 private boolean deleteArpRangesCommand(InstanceIdentifier<Node> iid,
222 ProxyRangeCommand.ProxyRangeCommandBuilder builder = new ProxyRangeCommand.ProxyRangeCommandBuilder();
223 builder.setOperation(General.Operations.DELETE);
225 builder.setStartAddress(start);
226 builder.setEndAddress(end);
227 return GbpNetconfTransaction.netconfSyncedDelete(iid, builder.build(), GbpNetconfTransaction.RETRY_COUNT);
230 private boolean addUnnumberedInterface(String hostname, String neutronInterfaceName, String loopbackName) {
231 InstanceIdentifier<Node> nodeIid = VppIidFactory.getNetconfNodeIid(new NodeId(hostname));
232 if (neutronInterfaceName.equalsIgnoreCase(loopbackName)) {
233 LOG.trace("No need to configure unnumbered for loopback: {} on host: {}. skip processing.", loopbackName,
234 neutronInterfaceName);
237 LOG.trace("Adding unnumbered configuration hostname: {}, interface: {} use : {}", hostname,
238 neutronInterfaceName, loopbackName);
239 boolean unnumberWritten = putUnnumberedInterface(nodeIid, neutronInterfaceName, loopbackName);
240 if (unnumberWritten) {
241 if (unnumberedCache.get(nodeIid.firstKeyOf(Node.class), loopbackName) != null) {
242 unnumberedCache.get(nodeIid.firstKeyOf(Node.class), loopbackName).add(neutronInterfaceName);
244 unnumberedCache.put(nodeIid.firstKeyOf(Node.class), loopbackName,
245 Lists.newArrayList(neutronInterfaceName));
247 LOG.debug("Added Interface {} as unnumbered for {}", loopbackName, neutronInterfaceName);
249 return unnumberWritten;
252 private boolean putUnnumberedInterface(InstanceIdentifier<Node> iid, String interfaceName, String useInterface) {
253 UnnumberedInterfaceCommand unnumberedCommand =
254 UnnumberedInterfaceCommand.builder()
255 .setOperation(General.Operations.MERGE)
256 .setUseInterface(useInterface)
257 .setInterfaceName(interfaceName)
259 return GbpNetconfTransaction.netconfSyncedWrite(iid, unnumberedCommand, GbpNetconfTransaction.RETRY_COUNT);
262 private void addGpeEntry(InstanceIdentifier<Node> iid, GbpSubnet gbpSubnetInfo, long vni) {
263 LOG.trace("addGpeEntry called. iid: {}, GbpSubnet: {}, vni: {}", iid, gbpSubnetInfo, vni);
265 Pair<Ipv4Prefix, Ipv4Prefix> delegatingSubnets =
266 IpAddressUtil.getSmallerSubnet(gbpSubnetInfo.getCidr().getIpv4Prefix());
268 RemoteEid firstREid =
269 LispUtil.toRemoteEid(LispUtil.toLispIpv4Prefix(delegatingSubnets.getLeft()), vni, Ipv4PrefixAfi.class);
270 if (!putGpeEntry(iid, Constants.GPE_ENTRY_PREFIX + gbpSubnetInfo.getId() + "_1", firstREid, vni, vni)) {
271 LOG.warn("Failed to write GPE entry: {}", Constants.GPE_ENTRY_PREFIX + gbpSubnetInfo.getId() + "_1");
274 if (delegatingSubnets.getLeft().equals(delegatingSubnets.getRight())) {
278 RemoteEid secondREid =
279 LispUtil.toRemoteEid(LispUtil.toLispIpv4Prefix(delegatingSubnets.getRight()), vni, Ipv4PrefixAfi.class);
281 if (!putGpeEntry(iid, Constants.GPE_ENTRY_PREFIX + gbpSubnetInfo.getId() + "_2", secondREid, vni, vni)) {
282 LOG.warn("Failed to write GPE entry: {}", Constants.GPE_ENTRY_PREFIX + gbpSubnetInfo.getId() + "_2");
284 } catch (LispArgumentException e) {
289 private boolean putGpeEntry(InstanceIdentifier<Node> iid, String id, RemoteEid rEid, long vni, long vrf) {
290 AbstractLispCommand<GpeEntry> gpeEntryCommand = LispCommandWrapper
291 .addGpeSendMapregisterAction(id, rEid, vni, vrf);
292 return LispStateCommandExecutor.executePutCommand(iid, gpeEntryCommand);
295 private boolean deleteGpeEntry(InstanceIdentifier<Node> iid, String id) {
296 AbstractLispCommand<GpeEntry> gpeEntryDeletionCommand = LispCommandWrapper
298 return LispStateCommandExecutor.executeDeleteCommand(iid, gpeEntryDeletionCommand);
301 private long getVni(String tenantUuid) {
302 return neutronTenantToVniMapper.getVni(tenantUuid);
306 public void gbpSubnetCreated(String subnetUuid, GbpSubnet subnetInfo) {
307 GbpSubnetCache.put(subnetUuid, subnetInfo);
310 public void gbpSubnetdeleted(String subnetUuid) {
311 LOG.trace("gbpSubnetdeleted -> subnetUuid:{}", subnetUuid);
312 GbpSubnet gbpSubnet = GbpSubnetCache.get(subnetUuid);
313 String loopIntfcName = Constants.GW_NAME_PREFIX + subnetUuid;
314 List<LoopBackDetails> loopBackDetails = loopBackHostnames.get(loopIntfcName);
315 if (loopBackDetails != null) {
316 loopBackDetails.forEach(loopbackDetail -> {
318 InstanceIdentifier<Node> iid =
319 VppIidFactory.getNetconfNodeIid(new NodeId(loopbackDetail.getHostName()));
321 if (deleteSpecificLoopback(iid, loopIntfcName)) {
322 if (!deleteProxyArpRange(loopbackDetail.getHostName(),
323 loopbackDetail.getLoopbackCommand().getVrfId(), gbpSubnet)) {
324 LOG.warn("Failed to delete ProxyArpRange: {} on host: {}", gbpSubnet.getAllocationPools(),
325 loopbackDetail.getHostName());
328 if (!deleteGpeEntry(iid, Constants.GPE_ENTRY_PREFIX + gbpSubnet.getId() + "_1")) {
329 LOG.warn("Failed to delete gpeEntry: {} on host: {}",
330 Constants.GPE_ENTRY_PREFIX + gbpSubnet.getId() + "_1", loopbackDetail.getHostName());
332 if (!deleteGpeEntry(iid, Constants.GPE_ENTRY_PREFIX + gbpSubnet.getId() + "_2")) {
333 LOG.warn("Failed to delete gpeEntry: {} on host: {}",
334 Constants.GPE_ENTRY_PREFIX + gbpSubnet.getId() + "_2", loopbackDetail.getHostName());
336 if (!deleteGpeFeatureData(loopbackDetail.getHostName())) {
337 LOG.warn("Failed to delete gpe configuration: {} on host: {}", loopbackDetail.getHostName());
341 LOG.warn("Failed to delete loopback: {} on host: {}", loopIntfcName, loopbackDetail.getHostName());
345 GbpSubnetCache.remove(subnetUuid);
348 private boolean deleteGpeFeatureData(String hostname) {
349 return GbpNetconfTransaction.netconfSyncedDelete(VppIidFactory.getNetconfNodeIid(new NodeId(hostname)),
350 VppIidFactory.getGpeFeatureDataIid(), GbpNetconfTransaction.RETRY_COUNT);