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