Fix metadata for route, arp and overlay
[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.mappers.HostIdToMetadataInterfaceMapper;
18 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.mappers.HostVrfRoutingInformationMapper;
19 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.mappers.InterfaceNameToStaticInfoMapper;
20 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.mappers.NeutronTenantToVniMapper;
21 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.util.ConfigManagerHelper;
22 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.GbpNetconfTransaction;
23 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General;
24 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;
25 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
26 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.TapCase;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170607.interfaces._interface.Routing;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170607.interfaces._interface.RoutingBuilder;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 import javax.annotation.Nonnull;
43
44 /**
45  * Created by Shakib Ahmed on 5/2/17.
46  */
47 public class FlatOverlayManager {
48     private static final Logger LOG = LoggerFactory.getLogger(FlatOverlayManager.class);
49
50     private ConfigManagerHelper overlayHelper;
51     private DataBroker dataBroker;
52
53     private NeutronTenantToVniMapper neutronTenantToVniMapper = NeutronTenantToVniMapper.getInstance();
54     private HostVrfRoutingInformationMapper hostVrfInfo = HostVrfRoutingInformationMapper.getInstance();
55     private HostIdToMetadataInterfaceMapper
56             hostIdToMetadataInterfaceMapper = HostIdToMetadataInterfaceMapper.getInstance();
57
58     private InterfaceNameToStaticInfoMapper interfaceNameToStaticInfoMapper;
59
60     private StaticRoutingHelper staticRoutingHelper;
61
62     public FlatOverlayManager(@Nonnull DataBroker dataBroker, @Nonnull MountedDataBrokerProvider mountedDataBrokerProvider) {
63         this.overlayHelper = new ConfigManagerHelper(mountedDataBrokerProvider);
64         this.interfaceNameToStaticInfoMapper = InterfaceNameToStaticInfoMapper.getInstance();
65         staticRoutingHelper = new StaticRoutingHelper(interfaceNameToStaticInfoMapper);
66         this.dataBroker = dataBroker;
67     }
68
69     public void configureEndpointForFlatOverlay(AddressEndpointWithLocation addressEp) {
70         if (!overlayHelper.isMetadataPort(addressEp)) {
71             configureInterfaceForFlatOverlay(addressEp);
72             addStaticArp(addressEp);
73             addStaticRoute(addressEp);
74         } else {
75             Ipv4Address metadataIp = overlayHelper.getInterfaceIp(addressEp);
76             Ipv4Prefix metadataIpPrefix = overlayHelper.getInterfaceIpAsPrefix(addressEp);
77             addressEp.getRelativeLocations().getExternalLocation().forEach(externalLocation -> {
78                 String hostName = overlayHelper.getHostName(externalLocation).get();
79                 String metadataInterfaceName = overlayHelper.getInterfaceName(externalLocation).get();
80
81                 long vrf = getVni(addressEp.getTenant().getValue());
82
83                 if (!hostIdToMetadataInterfaceMapper.isMetadataInterfaceConfigured(hostName, metadataInterfaceName)) {
84                     DataBroker vppDataBroker = overlayHelper.getPotentialExternalDataBroker(externalLocation).get();
85                     addInterfaceInVrf(vppDataBroker, metadataInterfaceName, vrf);
86                     String physicalAddress = resolvePhysicalAddress(hostName, metadataInterfaceName);
87                     addStaticArp(vppDataBroker, hostName, metadataInterfaceName, physicalAddress, metadataIp);
88                     addStaticRoute(vppDataBroker, hostName, vrf, metadataIp, metadataIpPrefix, metadataInterfaceName);
89                     hostIdToMetadataInterfaceMapper.addMetadataInterfaceInHost(hostName, metadataInterfaceName);
90                 }
91             });
92         }
93     }
94
95     private String resolvePhysicalAddress(String hostName, String metadataInterfaceName) {
96         String physAddress = null;
97         Optional<Config> configOptional =
98             DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, VppIidFactory.getVppRendererConfig(),
99                 dataBroker.newReadOnlyTransaction());
100         if (configOptional.isPresent() && configOptional.get().getVppEndpoint() != null) {
101             java.util.Optional<VppEndpoint> vppEndpointOptional = configOptional.get().getVppEndpoint().stream()
102                     .filter(vppEndpoint -> vppEndpoint.getVppNodeId().getValue().equals(hostName))
103                     .filter(vppEndpoint -> vppEndpoint.getVppInterfaceName().equals(metadataInterfaceName))
104                     .findFirst();
105             if (vppEndpointOptional.isPresent() && vppEndpointOptional.get()
106                 .getInterfaceTypeChoice() instanceof TapCase) {
107                 TapCase tapCase = (TapCase) vppEndpointOptional.get().getInterfaceTypeChoice();
108                 physAddress = tapCase.getPhysicalAddress().getValue();
109                 LOG.trace("Resolved PhysicalAddress : {} for metadataInterfaceName: {}, on node: {}", physAddress
110                     , metadataInterfaceName, hostName);
111             } else {
112                 LOG.warn("PhysicalAddress was not resolved for metadataInterfaceName: {}, on node: {}",
113                     metadataInterfaceName, hostName);
114             }
115         }
116
117         return physAddress;
118     }
119
120     public void handleEndpointDeleteForFlatOverlay(AddressEndpointWithLocation addressEp) {
121         deleteStaticRoute(addressEp);
122     }
123
124     private void configureInterfaceForFlatOverlay(AddressEndpointWithLocation addressEp) {
125         addInterfaceInVrf(addressEp);
126     }
127
128     private void addInterfaceInVrf(AddressEndpointWithLocation addressEp) {
129         DataBroker vppDataBroker = overlayHelper.getPotentialExternalDataBroker(addressEp).get();
130         long vni = getVni(addressEp.getTenant().getValue());
131         long vrf = vni;
132         Optional<String> interfaceNameOptional = overlayHelper.getInterfaceName(addressEp);
133
134         Preconditions.checkArgument(interfaceNameOptional.isPresent());
135
136         addInterfaceInVrf(vppDataBroker, interfaceNameOptional.get(), vrf);
137     }
138
139     private void addInterfaceInVrf(DataBroker vppDataBroker, String interfaceName, long vrf) {
140         if (!putVrfInInterface(vppDataBroker, interfaceName, vrf)) {
141             LOG.warn("Failed to put interface {} to vrf {}", interfaceName, vrf);
142         } else {
143             LOG.debug("Added interface {} to vrf {}", interfaceName, vrf);
144         }
145     }
146
147     private boolean putVrfInInterface(DataBroker vppDataBroker,
148                                   String interfaceName,
149                                   Long vrf) {
150         InstanceIdentifier<Routing> iid = VppIidFactory.getRoutingIid(new InterfaceKey(interfaceName));
151         RoutingBuilder builder = new RoutingBuilder();
152         builder.setIpv4VrfId(vrf);
153         return GbpNetconfTransaction.netconfSyncedWrite(vppDataBroker, iid, builder.build(), GbpNetconfTransaction.RETRY_COUNT);
154     }
155
156     private void addStaticArp(AddressEndpointWithLocation addressEp) {
157         DataBroker vppDataBroker = overlayHelper.getPotentialExternalDataBroker(addressEp).get();
158         String hostName = overlayHelper.getHostName(addressEp).get();
159         String physicalAddress = overlayHelper.getPhysicalAddress(addressEp);
160         Optional<String> interfaceNameOptional = overlayHelper.getInterfaceName(addressEp);
161
162         Preconditions.checkArgument(interfaceNameOptional.isPresent());
163
164         String interfaceName = interfaceNameOptional.get();
165
166         addStaticArp(vppDataBroker, hostName, interfaceName, physicalAddress, overlayHelper.getInterfaceIp(addressEp));
167     }
168
169     private void addStaticArp(DataBroker vppDataBroker,
170                               String hostName,
171                               String interfaceName,
172                               String physicalAddress,
173                               Ipv4Address ipv4Address) {
174         Ipv4AddressNoZone ip = new Ipv4AddressNoZone(ipv4Address);
175         InterfaceKey interfaceKey = new InterfaceKey(interfaceName);
176         if (!putStaticArp(vppDataBroker,
177                              interfaceKey,
178                              new PhysAddress(physicalAddress),
179                              ip)) {
180             LOG.warn("Failed to put static arp with interface {} for ip={} and physical-address={}",
181                     interfaceName, ip, physicalAddress);
182         } else {
183             LOG.debug("Added Static arp ({} {}) in host {} for interface {}", ip, physicalAddress, hostName,
184                     interfaceName);
185         }
186     }
187
188     private boolean putStaticArp(DataBroker vppDataBroker,
189                                  InterfaceKey interfaceKey,
190                                  PhysAddress physAddress,
191                                  Ipv4AddressNoZone ip) {
192         StaticArpCommand.StaticArpCommandBuilder staticArpCommandBuilder = new StaticArpCommand.StaticArpCommandBuilder();
193
194         staticArpCommandBuilder.setOperation(General.Operations.PUT);
195         staticArpCommandBuilder.setInterfaceKey(interfaceKey);
196         staticArpCommandBuilder.setIp(ip);
197         staticArpCommandBuilder.setLinkLayerAddress(physAddress);
198
199         return GbpNetconfTransaction.netconfSyncedWrite(vppDataBroker,
200                 staticArpCommandBuilder.build(), GbpNetconfTransaction.RETRY_COUNT);
201     }
202
203     private void addStaticRoute(AddressEndpointWithLocation addressEp) {
204         DataBroker vppDataBroker = overlayHelper.getPotentialExternalDataBroker(addressEp).get();
205         String hostName = overlayHelper.getHostName(addressEp).get();
206
207         long vni = getVni(addressEp.getTenant().getValue());
208         long vrf = vni;
209
210         String outgoingInterfaceName = overlayHelper.getInterfaceName(addressEp).get();
211         Ipv4Address ipWithoutPrefix = overlayHelper.getInterfaceIp(addressEp);
212         Ipv4Prefix ipv4Prefix = overlayHelper.getInterfaceIpAsPrefix(addressEp);
213
214         addStaticRoute(vppDataBroker, hostName, vrf, ipWithoutPrefix, ipv4Prefix, outgoingInterfaceName);
215     }
216
217     private void addStaticRoute(DataBroker vppDataBroker, String hostName, long vrf, Ipv4Address ipWithoutPrefix,
218                                 Ipv4Prefix ipv4Prefix, String outgoingInterfaceName) {
219
220         if (!hostVrfInfo.vrfExists(hostName, vrf)) {
221             if (!staticRoutingHelper.addRoutingProtocolForVrf(vppDataBroker, hostName, vrf)) {
222                 LOG.warn("Failed to add Routing protocol for host {} and vrf {}!", hostName, vrf);
223             }
224         }
225
226         if (staticRoutingHelper.endPointRoutingExists(outgoingInterfaceName, ipWithoutPrefix)) {
227             return;
228         }
229
230         if (staticRoutingHelper.routeAlreadyExistsInHostVrf(hostName, vrf, ipWithoutPrefix)) {
231             LOG.warn("Ip already exists in host {} vrf {} ip {}", hostName, vrf, ipWithoutPrefix);
232             return;
233         }
234
235         if (!staticRoutingHelper.addSingleStaticRouteInRoutingProtocol(vppDataBroker,
236                 hostName,
237                 vrf,
238                 ipWithoutPrefix,
239                 ipv4Prefix,
240                 outgoingInterfaceName)) {
241             LOG.warn("Failed to add routing ({} via {}) in vrf {} in compute host {}!",
242                     ipv4Prefix, outgoingInterfaceName, vrf, hostName);
243         } else {
244             LOG.debug("Added route ({} via {}) in vrf {} in compute host {}",
245                     ipv4Prefix, outgoingInterfaceName, vrf, hostName);
246         }
247     }
248
249     private void deleteStaticRoute(AddressEndpointWithLocation addressEp) {
250         DataBroker vppDataBroker = overlayHelper.getPotentialExternalDataBroker(addressEp).get();
251         String hostName = overlayHelper.getHostName(addressEp).get();
252         String interfaceName = overlayHelper.getInterfaceName(addressEp).get();
253
254         long vni = getVni(addressEp.getTenant().getValue());
255         long vrf = vni;
256
257         Ipv4Address ipWithoutPrefix = overlayHelper.getInterfaceIp(addressEp);
258
259         if (!staticRoutingHelper.deleteSingleStaticRouteFromRoutingProtocol(vppDataBroker,
260                                                                        hostName,
261                                                                        vrf,
262                                                                        interfaceName)) {
263             LOG.warn("Failed to delete route ({} via {}) from vrf {} from host{}",
264                     ipWithoutPrefix, interfaceName, vrf, hostName);
265
266         } else {
267             LOG.debug("Delete Static Route ({} via {}) from vrf {} from host {}",
268                     ipWithoutPrefix, interfaceName, vrf, hostName);
269         }
270     }
271
272     private long getVni(String tenantUuid) {
273         return neutronTenantToVniMapper.getVni(tenantUuid);
274     }
275 }