Add implementation for GPE native forwarding
[groupbasedpolicy.git] / renderers / vpp / src / main / java / org / opendaylight / groupbasedpolicy / renderer / vpp / lisp / flat / overlay / FlatOverlayManager.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.flat.overlay;
10
11
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
16 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.StaticArpCommand;
17 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.info.container.EndpointHost;
18 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.info.container.HostRelatedInfoContainer;
19 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.info.container.states.PhysicalInterfaces;
20 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.info.container.states.PortInterfaces;
21 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.info.container.states.PortRouteState;
22 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.info.container.states.SubnetState;
23 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.info.container.states.VrfHolder;
24 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.info.container.states.VrfState;
25 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.mappers.NeutronTenantToVniMapper;
26 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.util.ConfigManagerHelper;
27 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.util.Constants;
28 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.util.IpAddressUtil;
29 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.GbpNetconfTransaction;
30 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General;
31 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;
32 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
33 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.TapCase;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170607.interfaces._interface.Routing;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170607.interfaces._interface.RoutingBuilder;
45 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 import javax.annotation.Nonnull;
50
51 /**
52  * Created by Shakib Ahmed on 5/2/17.
53  */
54 public class FlatOverlayManager {
55     private static final Logger LOG = LoggerFactory.getLogger(FlatOverlayManager.class);
56
57     private ConfigManagerHelper overlayHelper;
58     private DataBroker dataBroker;
59
60     private NeutronTenantToVniMapper neutronTenantToVniMapper = NeutronTenantToVniMapper.getInstance();
61     private HostRelatedInfoContainer hostRelatedInfoContainer = HostRelatedInfoContainer.getInstance();
62
63     private StaticRoutingHelper staticRoutingHelper;
64
65     public FlatOverlayManager(@Nonnull DataBroker dataBroker,
66                               @Nonnull MountedDataBrokerProvider mountedDataBrokerProvider) {
67         this.overlayHelper = new ConfigManagerHelper(mountedDataBrokerProvider);
68         staticRoutingHelper = new StaticRoutingHelper();
69         this.dataBroker = dataBroker;
70     }
71
72     public void configureEndpointForFlatOverlay(AddressEndpointWithLocation addressEp) {
73         if (!overlayHelper.hasRelativeLocations(addressEp)) {
74             configureInterfaceForFlatOverlay(addressEp);
75             addStaticArp(addressEp);
76             addStaticRoute(addressEp);
77         } else {
78             Ipv4Address metadataIp = overlayHelper.getInterfaceIp(addressEp);
79             Ipv4Prefix metadataIpPrefix = overlayHelper.getInterfaceIpAsPrefix(addressEp);
80             addressEp.getRelativeLocations().getExternalLocation().forEach(externalLocation -> {
81                 String hostName = overlayHelper.getHostName(externalLocation).get();
82                 String metadataInterfaceName = overlayHelper.getInterfaceName(externalLocation).get();
83
84                 long vrf = getVni(addressEp.getTenant().getValue());
85
86                 String metadataSubnetUuid = Constants.METADATA_SUBNET_UUID;
87
88                 PortInterfaces portInterfacesOfHost = hostRelatedInfoContainer.getPortInterfaceStateOfHost(hostName);
89
90                 if (!portInterfacesOfHost.isInterfaceConfiguredForMetadata(metadataInterfaceName)) {
91                     DataBroker vppDataBroker = overlayHelper.getPotentialExternalDataBroker(externalLocation).get();
92                     addInterfaceInVrf(new EndpointHost(vppDataBroker, hostName), metadataInterfaceName, vrf);
93                     String physicalAddress = resolvePhysicalAddress(hostName, metadataInterfaceName);
94                     addStaticArp(vppDataBroker, hostName, metadataInterfaceName, physicalAddress, metadataIp);
95                     addStaticRoute(vppDataBroker, hostName, vrf, metadataSubnetUuid, metadataIp,
96                             metadataIpPrefix, metadataInterfaceName);
97                     portInterfacesOfHost.addInterfaceInMetadataInterfaceSet(metadataInterfaceName);
98                 }
99             });
100         }
101     }
102
103     private String resolvePhysicalAddress(String hostName, String metadataInterfaceName) {
104         String physAddress = null;
105         Optional<Config> configOptional =
106             DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, VppIidFactory.getVppRendererConfig(),
107                 dataBroker.newReadOnlyTransaction());
108         if (configOptional.isPresent() && configOptional.get().getVppEndpoint() != null) {
109             java.util.Optional<VppEndpoint> vppEndpointOptional = configOptional.get().getVppEndpoint().stream()
110                     .filter(vppEndpoint -> vppEndpoint.getVppNodeId().getValue().equals(hostName))
111                     .filter(vppEndpoint -> vppEndpoint.getVppInterfaceName().equals(metadataInterfaceName))
112                     .findFirst();
113             if (vppEndpointOptional.isPresent() && vppEndpointOptional.get()
114                 .getInterfaceTypeChoice() instanceof TapCase) {
115                 TapCase tapCase = (TapCase) vppEndpointOptional.get().getInterfaceTypeChoice();
116                 physAddress = tapCase.getPhysicalAddress().getValue();
117                 LOG.trace("Resolved PhysicalAddress : {} for metadataInterfaceName: {}, on node: {}", physAddress
118                     , metadataInterfaceName, hostName);
119             } else {
120                 LOG.warn("PhysicalAddress was not resolved for metadataInterfaceName: {}, on node: {}",
121                     metadataInterfaceName, hostName);
122             }
123         }
124
125         return physAddress;
126     }
127
128     public void handleEndpointDeleteForFlatOverlay(AddressEndpointWithLocation addressEp) {
129         if (overlayHelper.hasRelativeLocations(addressEp)) {
130             // okay to ignore
131             // routes will be deleted on interface delete
132             return;
133         }
134         deleteStaticRoute(addressEp);
135     }
136
137     public void handleInterfaceDeleteForFlatOverlay(DataBroker vppDataBroker, VppEndpoint vppEndpoint) {
138         String hostName = vppEndpoint.getVppNodeId().getValue();
139         String interfaceName = vppEndpoint.getVppInterfaceName();
140
141         staticRoutingHelper.deleteAllRoutesThroughInterface(vppDataBroker, hostName, interfaceName);
142
143         PortInterfaces portInterfaces = hostRelatedInfoContainer.getPortInterfaceStateOfHost(hostName);
144         portInterfaces.removePortInterface(interfaceName);
145     }
146
147     private void configureInterfaceForFlatOverlay(AddressEndpointWithLocation addressEp) {
148         addInterfaceInVrf(addressEp);
149     }
150
151     private void addInterfaceInVrf(AddressEndpointWithLocation addressEp) {
152         EndpointHost endpointHost = overlayHelper.getEndpointHostInformation(addressEp);
153         long vni = getVni(addressEp.getTenant().getValue());
154         long vrf = vni;
155         Optional<String> interfaceNameOptional = overlayHelper.getInterfaceName(addressEp);
156
157         Preconditions.checkArgument(interfaceNameOptional.isPresent());
158
159         addInterfaceInVrf(endpointHost, interfaceNameOptional.get(), vrf);
160     }
161
162     private void addInterfaceInVrf(EndpointHost endpointHost, String interfaceName, long vrf) {
163         if (hostRelatedInfoContainer.getPortInterfaceStateOfHost(endpointHost.getHostName())
164                 .isVrfConfiguredForInterface(interfaceName)) {
165             return;
166         }
167
168         if (!putVrfInInterface(endpointHost.getHostDataBroker(), interfaceName, vrf)) {
169             LOG.warn("Failed to put interface {} to vrf {}", interfaceName, vrf);
170         } else {
171             hostRelatedInfoContainer
172                     .getPortInterfaceStateOfHost(endpointHost.getHostName())
173                     .initializeRoutingContextForInterface(interfaceName, vrf);
174             LOG.debug("Added interface {} to vrf {}", interfaceName, vrf);
175         }
176     }
177
178     private boolean putVrfInInterface(DataBroker vppDataBroker,
179                                   String interfaceName,
180                                   Long vrf) {
181         InstanceIdentifier<Routing> iid = VppIidFactory.getRoutingIid(new InterfaceKey(interfaceName));
182         RoutingBuilder builder = new RoutingBuilder();
183         builder.setIpv4VrfId(vrf);
184         return GbpNetconfTransaction.netconfSyncedWrite(vppDataBroker, iid, builder.build(), GbpNetconfTransaction.RETRY_COUNT);
185     }
186
187     private void addStaticArp(AddressEndpointWithLocation addressEp) {
188         DataBroker vppDataBroker = overlayHelper.getPotentialExternalDataBroker(addressEp).get();
189         String hostName = overlayHelper.getHostName(addressEp).get();
190         String physicalAddress = overlayHelper.getPhysicalAddress(addressEp);
191         Optional<String> interfaceNameOptional = overlayHelper.getInterfaceName(addressEp);
192
193         Preconditions.checkArgument(interfaceNameOptional.isPresent());
194
195         String interfaceName = interfaceNameOptional.get();
196
197         addStaticArp(vppDataBroker, hostName, interfaceName, physicalAddress, overlayHelper.getInterfaceIp(addressEp));
198     }
199
200     private void addStaticArp(DataBroker vppDataBroker,
201                               String hostName,
202                               String interfaceName,
203                               String physicalAddress,
204                               Ipv4Address ipv4Address) {
205         Ipv4AddressNoZone ip = new Ipv4AddressNoZone(ipv4Address);
206         InterfaceKey interfaceKey = new InterfaceKey(interfaceName);
207         if (!putStaticArp(vppDataBroker,
208                              interfaceKey,
209                              new PhysAddress(physicalAddress),
210                              ip)) {
211             LOG.warn("Failed to put static arp with interface {} for ip={} and physical-address={}",
212                     interfaceName, ip, physicalAddress);
213         } else {
214             LOG.debug("Added Static arp ({} {}) in host {} for interface {}", ip, physicalAddress, hostName,
215                     interfaceName);
216         }
217     }
218
219     private boolean putStaticArp(DataBroker vppDataBroker,
220                                  InterfaceKey interfaceKey,
221                                  PhysAddress physAddress,
222                                  Ipv4AddressNoZone ip) {
223         StaticArpCommand.StaticArpCommandBuilder staticArpCommandBuilder = new StaticArpCommand.StaticArpCommandBuilder();
224
225         staticArpCommandBuilder.setOperation(General.Operations.PUT);
226         staticArpCommandBuilder.setInterfaceKey(interfaceKey);
227         staticArpCommandBuilder.setIp(ip);
228         staticArpCommandBuilder.setLinkLayerAddress(physAddress);
229
230         return GbpNetconfTransaction.netconfSyncedWrite(vppDataBroker,
231                 staticArpCommandBuilder.build(), GbpNetconfTransaction.RETRY_COUNT);
232     }
233
234     private void addStaticRoute(AddressEndpointWithLocation addressEp) {
235         DataBroker vppDataBroker = overlayHelper.getPotentialExternalDataBroker(addressEp).get();
236         String hostName = overlayHelper.getHostName(addressEp).get();
237
238         long vni = getVni(addressEp.getTenant().getValue());
239         long vrf = vni;
240
241         String portSubnetUuid = overlayHelper.getSubnet(addressEp);
242
243         String outgoingInterfaceName = overlayHelper.getInterfaceName(addressEp).get();
244         Ipv4Address ipWithoutPrefix = overlayHelper.getInterfaceIp(addressEp);
245
246         if (overlayHelper.isMetadataPort(addressEp)) {
247             //override original port subnet to handle the Absolute location case of address endpoint
248             portSubnetUuid = Constants.METADATA_SUBNET_UUID;
249         }
250
251         Ipv4Prefix ipv4Prefix = overlayHelper.getInterfaceIpAsPrefix(addressEp);
252
253         addStaticRoute(vppDataBroker, hostName, vrf, portSubnetUuid, ipWithoutPrefix, ipv4Prefix, outgoingInterfaceName);
254     }
255
256     private void addStaticRoute(DataBroker vppDataBroker, String hostName, long vrfId, String hostIpSubnetUuid,
257                                 Ipv4Address ipWithoutPrefix, Ipv4Prefix ipv4Prefix, String outgoingInterfaceName) {
258
259         VrfHolder vrfHolderOfHost = hostRelatedInfoContainer.getVrfStateOfHost(hostName);
260
261         if (!vrfHolderOfHost.hasVrf(vrfId)) {
262             if (!staticRoutingHelper.addRoutingProtocolForVrf(vppDataBroker, vrfId, vrfHolderOfHost)) {
263                 addStaticRouteToPublicInterface(vppDataBroker, hostName, vrfId);
264                 LOG.warn("Failed to add Routing protocol for host {} and vrf {}!", hostName, vrfId);
265             }
266         }
267
268         VrfState vrfStateOfVrfId = vrfHolderOfHost.getVrfState(vrfId);
269
270         if (vrfStateOfVrfId.getSubnetHolder().getSubnetState(hostIpSubnetUuid).isIpPresent(ipWithoutPrefix)) {
271             LOG.info("Ip already exists in host {} vrf {} ip {}", hostName, vrfId, ipWithoutPrefix);
272             return;
273         }
274
275         if (!staticRoutingHelper.addSingleStaticRouteInRoutingProtocol(vppDataBroker, hostName, vrfId, hostIpSubnetUuid,
276                 ipWithoutPrefix, ipv4Prefix, outgoingInterfaceName)) {
277             LOG.warn("Failed to add routing ({} via {}) in vrf {} in compute host {}!",
278                     ipv4Prefix, outgoingInterfaceName, vrfId, hostName);
279         } else {
280             LOG.debug("Added route ({} via {}) in vrf {} in compute host {}",
281                     ipv4Prefix, outgoingInterfaceName, vrfId, hostName);
282         }
283     }
284
285     private void addStaticRouteToPublicInterface(DataBroker vppDataBroker, String hostName, long vrfId) {
286         Ipv4Address physicalInterfaceIp = hostRelatedInfoContainer
287                 .getPhysicalInterfaceState(hostName)
288                 .getIp(PhysicalInterfaces.PhysicalInterfaceType.PUBLIC).getIpv4Address();
289         String physicalInterfaceName = hostRelatedInfoContainer
290                 .getPhysicalInterfaceState(hostName)
291                 .getName(PhysicalInterfaces.PhysicalInterfaceType.PUBLIC);
292         if (physicalInterfaceName != null && !physicalInterfaceName.isEmpty()) {
293             if (!staticRoutingHelper.addSingleStaticRouteInRoutingProtocol(vppDataBroker,
294                     hostName, vrfId, Constants.PUBLIC_SUBNET_UUID, physicalInterfaceIp,
295                     IpAddressUtil.toIpV4Prefix(physicalInterfaceIp), physicalInterfaceName)) {
296                 LOG.warn("Failed to add route for physical interface in vrf {} compute host {}", vrfId, hostName);
297             } else {
298                 LOG.debug("Added route for physical interface {} in vrf {}", physicalInterfaceName, vrfId);
299             }
300         }
301     }
302
303     private void deleteStaticRoute(AddressEndpointWithLocation addressEp) {
304         DataBroker vppDataBroker = overlayHelper.getPotentialExternalDataBroker(addressEp).get();
305         String hostName = overlayHelper.getHostName(addressEp).get();
306         String interfaceName = overlayHelper.getInterfaceName(addressEp).get();
307
308         long vni = getVni(addressEp.getTenant().getValue());
309         long vrfId = vni;
310
311         String ipSubnetUuid = overlayHelper.getSubnet(addressEp);
312
313         if (overlayHelper.isMetadataPort(addressEp)) {
314             //override original port subnet to handle the Absolute location case of address endpoint
315             ipSubnetUuid = Constants.METADATA_SUBNET_UUID;
316         }
317
318         Ipv4Address ipWithoutPrefix = overlayHelper.getInterfaceIp(addressEp);
319
320         PortRouteState portRouteState = hostRelatedInfoContainer
321                                             .getPortInterfaceStateOfHost(hostName)
322                                             .getPortRouteState(interfaceName);
323
324         SubnetState subnetState = hostRelatedInfoContainer
325                                     .getVrfStateOfHost(hostName)
326                                     .getVrfState(vrfId)
327                                     .getSubnetHolder()
328                                     .getSubnetState(ipSubnetUuid);
329
330         if (!subnetState.isIpPresent(ipWithoutPrefix)) {
331             LOG.debug("Route {} already deleted from vrf {} of host {}", ipWithoutPrefix, vrfId, hostName);
332             return;
333         }
334
335         long targetRouteId = portRouteState.getRouteIdOfIp(ipWithoutPrefix);
336
337         if (!staticRoutingHelper.deleteSingleStaticRouteFromRoutingProtocol(vppDataBroker,
338                                                                             hostName,
339                                                                             vrfId,
340                                                                             interfaceName,
341                                                                             targetRouteId)) {
342             LOG.warn("Failed to delete route ({} via {}) from vrf {} from host{}",
343                     ipWithoutPrefix, interfaceName, vrfId, hostName);
344
345         } else {
346             portRouteState.removeIp(ipWithoutPrefix);
347             subnetState.removeIp(ipWithoutPrefix);
348             LOG.debug("Delete Static Route ({} via {}) from vrf {} from host {}",
349                     ipWithoutPrefix, interfaceName, vrfId, hostName);
350         }
351     }
352
353     private long getVni(String tenantUuid) {
354         return neutronTenantToVniMapper.getVni(tenantUuid);
355     }
356 }