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