Cleanup of Lisp in VPP renderer
[groupbasedpolicy.git] / renderers / vpp / src / main / java / org / opendaylight / groupbasedpolicy / renderer / vpp / lisp / util / ConfigManagerHelper.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.util;
10
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.ListenableFuture;
15
16 import java.util.List;
17
18 import javax.annotation.Nonnull;
19
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.groupbasedpolicy.renderer.vpp.config.ConfigUtil;
22 import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.VppPathMapper;
23 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.LispStateManager;
24 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.exception.LispNotFoundException;
25 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.info.container.HostRelatedInfoContainer;
26 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.info.container.states.PhysicalInterfaces;
27 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.GbpNetconfTransaction;
28 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.InterfaceUtil;
29 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.LispUtil;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
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;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.Address;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.address.subnet.PrefixLength;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.Ipv4Afi;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.network.containment.Containment;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.network.containment.containment.NetworkDomainContainment;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.LocationType;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCase;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.relative.location.relative.locations.ExternalLocation;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.ParentEndpointChoice;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.ParentEndpointCase;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.endpoint._case.ParentEndpoint;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.IpPrefixType;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.L3Context;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.MacAddressType;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev171013.HmacKeyType;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev171013.dp.subtable.grouping.local.mappings.local.mapping.Eid;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev171013.hmac.key.grouping.HmacKey;
58 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61
62 public class ConfigManagerHelper {
63     private static final Logger LOG = LoggerFactory.getLogger(ConfigManagerHelper.class);
64
65
66     public ConfigManagerHelper() {
67     }
68
69
70     public static ExternalLocationCase resolveAndValidateLocation(AddressEndpointWithLocation addrEpWithLoc) {
71         Preconditions.checkNotNull(addrEpWithLoc.getAbsoluteLocation(), "Absolute location for " +
72                 "AddressEndpointWithLocation missing: " + addrEpWithLoc.toString() );
73         LocationType locationType = addrEpWithLoc.getAbsoluteLocation().getLocationType();
74         if (!(locationType instanceof ExternalLocationCase)) {
75             throw new IllegalArgumentException("Endpoint does not have external location " + addrEpWithLoc);
76         }
77         ExternalLocationCase result = (ExternalLocationCase) locationType;
78         if (result.getExternalNodeMountPoint() == null || result.getExternalNodeConnector() == null) {
79             throw new IllegalArgumentException(
80                     "Endpoint does not have external-node-mount-point or external-node-connector " + addrEpWithLoc);
81         }
82         return result;
83     }
84
85     //This is almost identical to VBD's equivalent method
86     public ListenableFuture<String> getLispDataRlocInterfaceName(@Nonnull String hostName) {
87         Preconditions.checkNotNull(hostName, "Hostname is null!");
88
89         PhysicalInterfaces physicalInterfaces = HostRelatedInfoContainer.getInstance()
90                 .getPhysicalInterfaceState(hostName);
91
92         String publicInterfaceName = physicalInterfaces == null ? "" : physicalInterfaces
93                 .getName(PhysicalInterfaces.PhysicalInterfaceType.PUBLIC);
94
95         final Optional<InterfacesState> opInterfaceState =
96                 GbpNetconfTransaction.read(LispUtil.hostnameToIid(hostName), LogicalDatastoreType.OPERATIONAL,
97                         InstanceIdentifier.create(InterfacesState.class), GbpNetconfTransaction.RETRY_COUNT);
98
99         if (!opInterfaceState.isPresent()) {
100             LOG.debug("There appear to be no interfaces on node {}.", hostName);
101             return Futures.immediateFailedFuture(new LispNotFoundException("No interfaces found"));
102         }
103
104         String interfaceName = null;
105         for(Interface intf: opInterfaceState.get().getInterface()) {
106             if(!ipAddressPresent(intf)) {
107                 continue;
108             }
109             interfaceName = intf.getName();
110         }
111
112         final Optional<Interfaces> opInterfaces =
113                 GbpNetconfTransaction.read(LispUtil.hostnameToIid(hostName), LogicalDatastoreType.CONFIGURATION,
114                         InstanceIdentifier.create(Interfaces.class), GbpNetconfTransaction.RETRY_COUNT);
115
116
117         if (opInterfaces.isPresent()) {
118
119             List<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.
120                     interfaces.Interface> hostInterfaceFromOpDS = opInterfaces.get().getInterface();
121
122             for (org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.
123                     interfaces.Interface intf : hostInterfaceFromOpDS) {
124                 if (Constants.TENANT_INTERFACE.equals(intf.getDescription())
125                         && ipAddressPresent(intf)
126                         && intf.getType().equals(EthernetCsmacd.class)) {
127                     return Futures.immediateFuture(intf.getName());
128                 }
129             }
130
131             for (org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.
132                     interfaces.Interface intf : hostInterfaceFromOpDS) {
133                 if (ipAddressPresent(intf)
134                         && intf.getType().equals(EthernetCsmacd.class)
135                         && !intf.getName().equalsIgnoreCase(publicInterfaceName)) {
136                     return Futures.immediateFuture(intf.getName());
137                 }
138             }
139         }
140
141         if (interfaceName == null) {
142             LOG.warn("No interface with IP found for host {}", hostName);
143             return Futures.immediateFailedFuture(new LispNotFoundException("No interface with Ip address found!"));
144         }
145         return Futures.immediateFuture(interfaceName);
146     }
147
148     private boolean ipAddressPresent(Interface intf) {
149         Interface2 augIntf = intf.getAugmentation(Interface2.class);
150
151         if (augIntf == null) {
152             return false;
153         }
154
155         Ipv4 ipv4 = augIntf.getIpv4();
156
157         if (ipv4 == null) {
158             return false;
159         }
160
161         final List<Address> addresses = ipv4.getAddress();
162
163         if (addresses == null || addresses.isEmpty()) {
164             return false;
165         }
166
167         final Ipv4AddressNoZone ip = addresses.iterator().next().getIp();
168         return ip != null;
169     }
170
171     private String ipCidr(Interface intf) {
172         Interface2 augIntf = intf.getAugmentation(Interface2.class);
173
174         if (augIntf == null) {
175             return null;
176         }
177
178         Ipv4 ipv4 = augIntf.getIpv4();
179
180         if (ipv4 == null) {
181             return null;
182         }
183
184         final List<Address> addresses = ipv4.getAddress();
185
186         if (addresses == null || addresses.isEmpty()) {
187             return null;
188         }
189
190         Address firstAddress = addresses.get(0);
191         String ipString = firstAddress.getIp().getValue();
192         String length = "";
193         if (firstAddress.getSubnet().getImplementedInterface().equals(PrefixLength.class)) {
194             length = "" + ((PrefixLength)firstAddress.getSubnet()).getPrefixLength();
195         }
196
197         if (length.isEmpty()) {
198             return null;
199         }
200
201         return ipString + "/" + length;
202     }
203
204     private boolean ipAddressPresent(final org.opendaylight.yang.gen.v1.urn.ietf.
205             params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface intf) {
206         final Interface1 augIntf = intf.getAugmentation(Interface1.class);
207
208         if (augIntf == null) {
209             LOG.debug("Cannot get Interface1 augmentation for intf {}", intf);
210             return false;
211         }
212
213         final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4
214             ipv4 = augIntf.getIpv4();
215         if (ipv4 == null) {
216             return false;
217         }
218
219         final List<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address>
220             addresses = ipv4.getAddress();
221         if (addresses == null || addresses.isEmpty()) {
222             return false;
223         }
224
225         final Ipv4AddressNoZone ip = addresses.iterator().next().getIp();
226         return ip != null;
227     }
228
229     public String getLispCpRlocInterfaceName(@Nonnull String hostName) {
230         List<Interface> operationalInterfaceList =
231                 InterfaceUtil.getOperationalInterfaces(LispUtil.hostnameToIid(hostName));
232
233         if (operationalInterfaceList == null) {
234             return null;
235         } else {
236             int maxLen = -1;
237             String outgoingInterface = "";
238
239             for (Interface intf : operationalInterfaceList) {
240                 String ipCidr = ipCidr(intf);
241
242                 if (ipCidr == null) {
243                     continue;
244                 }
245
246                 if (IpAddressUtil.ipInRange(ConfigUtil.getInstance().getOdlIp().getIpv4Address(),
247                         IpAddressUtil.startIpOfSubnet(ipCidr), IpAddressUtil.endIpOfSubnet(ipCidr))) {
248                     int tmpLen = IpAddressUtil.maskLen(ipCidr);
249                     if (tmpLen > maxLen) {
250                         maxLen = tmpLen;
251                         outgoingInterface = intf.getName();
252                     }
253                 }
254             }
255             return outgoingInterface;
256         }
257     }
258
259     public String constructLocatorSetName(int locatorSetCount) {
260         return LispStateManager.DEFAULT_LOCATOR_SET_NAME_PREFIX + (locatorSetCount + 1);
261     }
262
263     public String constructLocatorSetNameForItrRloc() {
264         return LispStateManager.DEFAULT_LOCATOR_SET_NAME_PREFIX + "_itr_rloc";
265     }
266
267     public String constructEidMappingName(AddressEndpointWithLocation addressEp, String interfaceName) {
268         String ipAddress = getInterfaceIp(addressEp).getValue();
269         return LispStateManager.DEFAULT_MAPPING_RECORD_NAME_PREFIX + interfaceName + "_" + ipAddress;
270     }
271
272     public String getSubnet(AddressEndpointWithLocation addressEp) {
273         String subnetUuid = null;
274         Containment containment = addressEp.getNetworkContainment().getContainment();
275         if (containment instanceof NetworkDomainContainment) {
276             NetworkDomainContainment networkDomainContainment = (NetworkDomainContainment) containment;
277             subnetUuid = networkDomainContainment.getNetworkDomainId().getValue();
278         }
279         return subnetUuid;
280     }
281
282     public Eid getEid(AddressEndpointWithLocation addressEp, long vni) {
283         String ipPrefix = getIpWithPrefixOfEndpoint(addressEp);
284         return LispUtil.toEid(LispUtil.toIpv4(ipPrefix), vni, Ipv4Afi.class);
285     }
286
287     private static String getIpWithPrefixOfEndpoint(AddressEndpointWithLocation addressEp) {
288         String ipPrefix = null;
289         if (addressEp.getAddressType().equals(IpPrefixType.class)) {
290             ipPrefix = addressEp.getAddress();
291         } else if (addressEp.getAddressType().equals(MacAddressType.class)) {
292             ParentEndpointChoice parentEndpointChoice = addressEp.getParentEndpointChoice();
293             if (parentEndpointChoice instanceof ParentEndpointCase) {
294                 java.util.Optional<ParentEndpoint> endpointOptional =
295                     ((ParentEndpointCase) parentEndpointChoice).getParentEndpoint().stream()
296                         .filter(choice -> choice.getAddressType().equals(IpPrefixType.class))
297                         .filter(choice -> choice.getContextType().equals(L3Context.class)).findFirst();
298                 if (endpointOptional.isPresent()) {
299                     ipPrefix = endpointOptional.get().getAddress();
300                 }
301             }
302         }
303         return Preconditions.checkNotNull(ipPrefix, "No IP address found for Address Endpoint: {}", addressEp);
304     }
305
306     public static Ipv4Address getInterfaceIp(AddressEndpointWithLocation addressEp) {
307         String ipPrefix = getIpWithPrefixOfEndpoint(addressEp);
308         return LispUtil.toIpv4(ipPrefix).getIpv4();
309     }
310
311     public Ipv4Prefix getInterfaceIpAsPrefix(AddressEndpointWithLocation addressEp) {
312         if (getInterfaceIp(addressEp).getValue().contains("/")) {
313             return new Ipv4Prefix(getInterfaceIp(addressEp).getValue());
314         }
315         else {
316             return new Ipv4Prefix(getInterfaceIp(addressEp).getValue() + "/32");
317         }
318     }
319
320     public Optional<String> getInterfaceName(AddressEndpointWithLocation addedEp) {
321         ExternalLocationCase epLoc = resolveAndValidateLocation(addedEp);
322         String interfacePath = epLoc.getExternalNodeConnector();
323
324         return VppPathMapper.interfacePathToInterfaceName(interfacePath);
325     }
326
327     public Optional<String> getInterfaceName(ExternalLocation externalLocation) {
328         String interfacePath = externalLocation.getExternalNodeConnector();
329         return VppPathMapper.interfacePathToInterfaceName(interfacePath);
330     }
331
332
333     public HmacKey getDefaultHmacKey() {
334         return LispUtil.toHmacKey(HmacKeyType.Sha196Key, LispStateManager.DEFAULT_XTR_KEY);
335     }
336
337
338     public static boolean isMetadataPort(AddressEndpointWithLocation addressEp) {
339         return IpAddressUtil.isMetadataIp(getInterfaceIp(addressEp));
340     }
341 }