Add implementation for flat L3 overlay
[groupbasedpolicy.git] / renderers / vpp / src / main / java / org / opendaylight / groupbasedpolicy / renderer / vpp / lisp / loopback / LoopbackManager.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.loopback;
10
11 import com.google.common.base.Preconditions;
12 import org.apache.commons.lang3.tuple.Pair;
13 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
14 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.LoopbackCommand;
15 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.LoopbackCommandWrapper;
16 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.ProxyRangeCommand;
17 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.exception.LispConfigCommandFailedException;
18 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.mappers.LoopbackHostSpecificInfoMapper;
19 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.mappers.NeutronTenantToVniMapper;
20 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.mappers.SubnetUuidToGbpSubnetMapper;
21 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.util.ConfigManagerHelper;
22 import org.opendaylight.groupbasedpolicy.renderer.vpp.lisp.util.IpAddressUtil;
23 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.GbpNetconfTransaction;
24 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General;
25 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;
26 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
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.Ipv4Prefix;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.GbpSubnet;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 import javax.annotation.Nonnull;
36 import java.util.List;
37
38 /**
39  * Created by Shakib Ahmed on 4/26/17.
40  */
41 public class LoopbackManager {
42     private static final Logger LOG = LoggerFactory.getLogger(LoopbackManager.class);
43
44     private ConfigManagerHelper loopbackManagerHelper;
45
46     private LoopbackHostSpecificInfoMapper subnetHostSpecificInfo;
47     private NeutronTenantToVniMapper neutronTenantToVniMapper;
48     private SubnetUuidToGbpSubnetMapper subnetUuidToGbpSubnetMapper;
49
50     private static final String LOOP_NAME_PREFIX = "loop-";
51
52     public LoopbackManager(@Nonnull MountedDataBrokerProvider mountedDataBrokerProvider) {
53         this.loopbackManagerHelper = new ConfigManagerHelper(mountedDataBrokerProvider);
54         this.subnetHostSpecificInfo = new LoopbackHostSpecificInfoMapper();
55         this.neutronTenantToVniMapper = NeutronTenantToVniMapper.getInstance();
56         this.subnetUuidToGbpSubnetMapper = SubnetUuidToGbpSubnetMapper.getInstance();
57     }
58
59     public void createBviLoopbackIfNeeded(AddressEndpointWithLocation addressEp,
60                                           String bridgeDomainName) {
61         try {
62             DataBroker vppDataBroker = loopbackManagerHelper.getPotentialExternalDataBroker(addressEp).get();
63             String hostName = loopbackManagerHelper.getHostName(addressEp).get();
64             String subnetUuid = loopbackManagerHelper.getSubnet(addressEp);
65
66             if (subnetHostSpecificInfo.loopbackAlreadyExists(hostName, subnetUuid)) {
67                 subnetHostSpecificInfo.addNewPortInHostSubnet(hostName, subnetUuid);
68                 return;
69             }
70
71             GbpSubnet gbpSubnetInfo = Preconditions.checkNotNull(getSubnetInfo(subnetUuid),
72                     "Subnet UUID {} hasn't been created yet!", subnetUuid);
73
74             String interfaceName = LOOP_NAME_PREFIX + subnetHostSpecificInfo.getLoopbackCount(hostName);
75             long vni = getVni(addressEp.getTenant().getValue());
76
77             LoopbackCommand bviLoopbackCommand = LoopbackCommandWrapper
78                     .bviLoopbackPutCommand(interfaceName, vni, gbpSubnetInfo.getGatewayIp(), gbpSubnetInfo.getCidr(),
79                             bridgeDomainName);
80             createLoopbackInterface(hostName, subnetUuid, vppDataBroker, bviLoopbackCommand);
81         } catch (LispConfigCommandFailedException e) {
82             LOG.warn("LISP couldn't be configured: {}", e.getMessage());
83         }
84     }
85
86     public void createSimpleLoopbackIfNeeded(AddressEndpointWithLocation addressEp) {
87         try {
88             DataBroker vppDataBroker = loopbackManagerHelper.getPotentialExternalDataBroker(addressEp).get();
89             String hostName = loopbackManagerHelper.getHostName(addressEp).get();
90             String subnetUuid = loopbackManagerHelper.getSubnet(addressEp);
91
92             if (subnetHostSpecificInfo.loopbackAlreadyExists(hostName, subnetUuid)) {
93                 return;
94             }
95
96             String interfaceName = LOOP_NAME_PREFIX + subnetHostSpecificInfo.getLoopbackCount(hostName);
97             long vni = getVni(addressEp.getTenant().getValue());
98             long vrf = vni;
99
100             GbpSubnet gbpSubnetInfo = Preconditions.checkNotNull(getSubnetInfo(subnetUuid),
101                     "Subnet UUID {} hasn't been created yet!", subnetUuid);
102
103             LoopbackCommand simpleLoopbackCommand = LoopbackCommandWrapper
104                     .simpleLoopbackPutCommand(interfaceName, vrf, gbpSubnetInfo.getGatewayIp(),
105                             gbpSubnetInfo.getCidr());
106
107             createLoopbackInterface(hostName, subnetUuid, vppDataBroker, simpleLoopbackCommand);
108             addProxyArpRange(vppDataBroker, vrf, gbpSubnetInfo, hostName);
109         } catch (LispConfigCommandFailedException e) {
110             LOG.warn("LISP couldn't be configured: {}", e.getMessage());
111         }
112     }
113
114     private void createLoopbackInterface(String hostName, String subnetUuid, DataBroker vppDataBroker,
115                                         LoopbackCommand loopbackCommand) throws LispConfigCommandFailedException {
116
117         if (GbpNetconfTransaction.netconfSyncedWrite(vppDataBroker,
118                                                      loopbackCommand,
119                                                      GbpNetconfTransaction.RETRY_COUNT)) {
120             subnetHostSpecificInfo.addLoopbackForHost(hostName, subnetUuid, loopbackCommand.getName(),
121                     loopbackCommand.getVrfId());
122             subnetHostSpecificInfo.addNewPortInHostSubnet(hostName, subnetUuid);
123         } else {
124             throw new LispConfigCommandFailedException("BVI could not be created for "
125                     + hostName + " and bridge domain " + loopbackCommand.getBridgeDomain());
126         }
127     }
128
129     public void deleteLoopbackIfExists(String subnetUuid) {
130
131         List<String> hostsWithSubnet = subnetHostSpecificInfo.getHostsWithSubnet(subnetUuid);
132
133         hostsWithSubnet.forEach(host -> {
134             DataBroker vppDataBroker = loopbackManagerHelper.getPotentialExternalDataBroker(host).get();
135             String interfaceName = subnetHostSpecificInfo.getInterfaceNameForLoopbackInHost(host, subnetUuid);
136
137             try {
138                 deleteSpecificLoopback(vppDataBroker, interfaceName);
139             } catch (LispConfigCommandFailedException e) {
140                 e.printStackTrace();
141             }
142         });
143
144         subnetHostSpecificInfo.clearSubnet(subnetUuid);
145     }
146
147     public void handleEndpointDelete(AddressEndpointWithLocation addressEp) {
148         DataBroker vppDataBroker = loopbackManagerHelper.getPotentialExternalDataBroker(addressEp).get();
149         String hostId = loopbackManagerHelper.getHostName(addressEp).get();
150         String portSubnetUuid = loopbackManagerHelper.getSubnet(addressEp);
151         String interfaceName = subnetHostSpecificInfo.getInterfaceNameForLoopbackInHost(hostId, portSubnetUuid);
152         if (subnetHostSpecificInfo.deletePortFromHostSubnetAndTriggerLoopbackDelete(hostId, portSubnetUuid)) {
153             GbpSubnet gbpSubnetInfo = Preconditions.checkNotNull(subnetUuidToGbpSubnetMapper.getSubnetInfo(portSubnetUuid),
154                     "Invalid port!");
155             long vni = getVni(addressEp.getTenant().getValue());
156             try {
157                 deleteSpecificLoopback(vppDataBroker, interfaceName);
158                 deleteProxyArpRange(vppDataBroker, vni, gbpSubnetInfo, hostId);
159             } catch (LispConfigCommandFailedException e) {
160                 LOG.warn("Loopback not deleted properly: {}", e.getMessage());
161             }
162         }
163     }
164
165     private void deleteSpecificLoopback(DataBroker vppDataBroker, String interfaceName) throws LispConfigCommandFailedException {
166         if (!GbpNetconfTransaction.netconfSyncedDelete(vppDataBroker,
167                 VppIidFactory.getInterfaceIID(new InterfaceKey(interfaceName)), GbpNetconfTransaction.RETRY_COUNT)) {
168             throw new LispConfigCommandFailedException("Failed to delete Loopback interface!");
169         } else {
170             LOG.debug("Deleted loopback interface!");
171         }
172     }
173
174     private void addProxyArpRange(DataBroker vppDataBroker,
175                                   long vrf,
176                                   GbpSubnet gbpSubnetInfo,
177                                   String hostName) throws LispConfigCommandFailedException {
178         Ipv4Prefix subnetPrefix = gbpSubnetInfo.getCidr().getIpv4Prefix();
179
180         Preconditions.checkNotNull(subnetPrefix, "Subnet CIDR found to be null for "
181         + "subnet uuid =" +  gbpSubnetInfo.getId() + "!");
182
183         Pair<Ipv4Address, Ipv4Address> startAndEndAddress = IpAddressUtil.getStartAndEndIp(subnetPrefix);
184
185         if (!putArpRangesCommand(vppDataBroker,
186                                  vrf,
187                                  startAndEndAddress.getLeft(),
188                                  startAndEndAddress.getRight())) {
189             throw new LispConfigCommandFailedException("Proxy arp configuration failed for subnet uuid: " +
190             gbpSubnetInfo.getId() + "!");
191         } else {
192             LOG.debug("Configured proxy arp for range {} to {} on node : {}!", startAndEndAddress.getLeft(),
193                     startAndEndAddress.getRight(), hostName);
194         }
195     }
196
197     private void deleteProxyArpRange(DataBroker vppDataBroker,
198                                 long vrf,
199                                 GbpSubnet gbpSubnetInfo,
200                                 String hostName) throws LispConfigCommandFailedException {
201         Ipv4Prefix subnetPrefix = gbpSubnetInfo.getCidr().getIpv4Prefix();
202
203         Preconditions.checkNotNull(subnetPrefix, "Subnet CIDR found to be null for "
204                 + "subnet uuid =" +  gbpSubnetInfo.getId() + "!");
205
206         Pair<Ipv4Address, Ipv4Address> startAndEndAddress = IpAddressUtil.getStartAndEndIp(subnetPrefix);
207
208         if (!deleteArpRangesCommand(vppDataBroker,
209                                     vrf,
210                                     startAndEndAddress.getLeft(),
211                                     startAndEndAddress.getRight())) {
212             throw new LispConfigCommandFailedException("Proxy arp configuration failed for subnet uuid: " +
213                     gbpSubnetInfo.getId() + "!");
214         } else {
215             LOG.debug("Removed proxy arp for range {} to {} on node : {}!", startAndEndAddress.getLeft(),
216                     startAndEndAddress.getRight(), hostName);
217         }
218     }
219
220     private boolean putArpRangesCommand(DataBroker vppDataBroker, long vrf, Ipv4Address start, Ipv4Address end) {
221         ProxyRangeCommand.ProxyRangeCommandBuilder builder = new ProxyRangeCommand.ProxyRangeCommandBuilder();
222         builder.setOperation(General.Operations.PUT);
223         builder.setVrf(vrf);
224         builder.setStartAddress(start);
225         builder.setEndAddress(end);
226
227         return GbpNetconfTransaction.netconfSyncedWrite(vppDataBroker,
228                                                         builder.build(),
229                                                         GbpNetconfTransaction.RETRY_COUNT);
230     }
231
232     private boolean deleteArpRangesCommand(DataBroker vppDataBroker,
233                                            long vrf,
234                                            Ipv4Address start,
235                                            Ipv4Address end) {
236         ProxyRangeCommand.ProxyRangeCommandBuilder builder = new ProxyRangeCommand.ProxyRangeCommandBuilder();
237         builder.setOperation(General.Operations.DELETE);
238         builder.setVrf(vrf);
239         builder.setStartAddress(start);
240         builder.setEndAddress(end);
241
242         return GbpNetconfTransaction.netconfSyncedDelete(vppDataBroker,
243                                                          builder.build(),
244                                                          GbpNetconfTransaction.RETRY_COUNT);
245     }
246
247     private long getVni(String tenantUuid) {
248         return neutronTenantToVniMapper.getVni(tenantUuid);
249     }
250
251     private GbpSubnet getSubnetInfo(String subnetUuid) {
252         return subnetUuidToGbpSubnetMapper.getSubnetInfo(subnetUuid);
253     }
254 }