Gracefully Handle IDManager failure in NAT
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / ExternalNetworkGroupInstaller.java
1 /*
2  * Copyright (c) 2016 Hewlett Packard Enterprise, Co. and others.  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.netvirt.natservice.internal;
10
11 import com.google.common.base.Strings;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.List;
18 import javax.inject.Inject;
19 import javax.inject.Singleton;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
23 import org.opendaylight.genius.mdsalutil.ActionInfo;
24 import org.opendaylight.genius.mdsalutil.BucketInfo;
25 import org.opendaylight.genius.mdsalutil.GroupEntity;
26 import org.opendaylight.genius.mdsalutil.MDSALUtil;
27 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
28 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetDestination;
29 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
30 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
31 import org.opendaylight.netvirt.elanmanager.api.IElanService;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 @Singleton
43 public class ExternalNetworkGroupInstaller {
44     private static final Logger LOG = LoggerFactory.getLogger(ExternalNetworkGroupInstaller.class);
45     private final DataBroker broker;
46     private final IMdsalApiManager mdsalManager;
47     private final IElanService elanService;
48     private final IdManagerService idManager;
49     private final OdlInterfaceRpcService odlInterfaceRpcService;
50     private final JobCoordinator coordinator;
51     private final ItmRpcService itmRpcService;
52     private final IInterfaceManager interfaceManager;
53     private final NatServiceCounters natServiceCounters;
54
55     @Inject
56     public ExternalNetworkGroupInstaller(final DataBroker broker, final IMdsalApiManager mdsalManager,
57                                          final IElanService elanService, final IdManagerService idManager,
58                                          final OdlInterfaceRpcService odlInterfaceRpcService,
59                                          final JobCoordinator coordinator, final ItmRpcService itmRpcService,
60                                          final IInterfaceManager interfaceManager,
61                                          NatServiceCounters natServiceCounters) {
62
63         this.broker = broker;
64         this.mdsalManager = mdsalManager;
65         this.elanService = elanService;
66         this.idManager = idManager;
67         this.odlInterfaceRpcService = odlInterfaceRpcService;
68         this.coordinator = coordinator;
69         this.itmRpcService = itmRpcService;
70         this.interfaceManager = interfaceManager;
71         this.natServiceCounters = natServiceCounters;
72     }
73
74     public void installExtNetGroupEntries(Subnetmap subnetMap) {
75         if (subnetMap == null) {
76             LOG.error("installExtNetGroupEntries : Subnetmap is null");
77             return;
78         }
79
80         if (NatUtil.isIPv6Subnet(subnetMap.getSubnetIp())) {
81             LOG.debug("installExtNetGroupEntries : Subnet id {} is not an IPv4 subnet, hence skipping.",
82                     subnetMap.getId());
83             return;
84         }
85
86         Uuid networkId = subnetMap.getNetworkId();
87         Uuid subnetId = subnetMap.getId();
88         if (networkId == null) {
89             LOG.error("installExtNetGroupEntries : No network associated subnet id {}", subnetId.getValue());
90             return;
91         }
92
93         String macAddress = NatUtil.getSubnetGwMac(broker, subnetId, networkId.getValue());
94         installExtNetGroupEntries(subnetMap, macAddress);
95     }
96
97     public void installExtNetGroupEntries(Uuid subnetId, String macAddress) {
98         Subnetmap subnetMap = NatUtil.getSubnetMap(broker, subnetId);
99         if (subnetMap == null) {
100             LOG.error("installExtNetGroupEntries : Subnetmap is null");
101             return;
102         }
103
104         if (NatUtil.isIPv6Subnet(subnetMap.getSubnetIp())) {
105             LOG.debug("installExtNetGroupEntries : Subnet-id {} is not an IPv4 subnet, hence skipping.",
106                     subnetMap.getId());
107             return;
108         }
109         installExtNetGroupEntries(subnetMap, macAddress);
110     }
111
112     public void installExtNetGroupEntries(Uuid networkId, BigInteger dpnId) {
113         if (networkId == null) {
114             return;
115         }
116
117         List<Uuid> subnetIds = NatUtil.getSubnetIdsFromNetworkId(broker, networkId);
118         if (subnetIds.isEmpty()) {
119             LOG.error("installExtNetGroupEntries : No subnet ids associated network id {}", networkId.getValue());
120             return;
121         }
122
123         for (Uuid subnetId : subnetIds) {
124             String macAddress = NatUtil.getSubnetGwMac(broker, subnetId, networkId.getValue());
125             installExtNetGroupEntry(networkId, subnetId, dpnId, macAddress);
126         }
127     }
128
129     private void installExtNetGroupEntries(Subnetmap subnetMap, String macAddress) {
130
131         String subnetName = subnetMap.getId().getValue();
132         Uuid networkId = subnetMap.getNetworkId();
133         if (networkId == null) {
134             LOG.error("installExtNetGroupEntries : No network associated subnet id {}", subnetName);
135             return;
136         }
137
138         Collection<String> extInterfaces = elanService.getExternalElanInterfaces(networkId.getValue());
139         if (extInterfaces == null || extInterfaces.isEmpty()) {
140             LOG.trace("installExtNetGroupEntries : No external ELAN interfaces attached to network:{},subnet {}",
141                     networkId, subnetName);
142             return;
143         }
144
145         long groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME,
146             NatUtil.getGroupIdKey(subnetName));
147         if (groupId != NatConstants.INVALID_ID) {
148             LOG.info("installExtNetGroupEntries : Installing ext-net group {} entry for subnet {} with macAddress {} "
149                     + "(extInterfaces: {})", groupId, subnetName, macAddress,
150                     Arrays.toString(extInterfaces.toArray()));
151             for (String extInterface : extInterfaces) {
152                 BigInteger dpId = NatUtil.getDpnForInterface(odlInterfaceRpcService, extInterface);
153                 if (BigInteger.ZERO.equals(dpId)) {
154                     LOG.info(
155                         "installExtNetGroupEntries: No DPN for interface {}. NAT ext-net flow will not be installed "
156                             + "for subnet {}", extInterface, subnetName);
157                     return;
158                 }
159                 installExtNetGroupEntry(groupId, subnetName, extInterface, macAddress, dpId);
160             }
161         } else {
162             LOG.error("installExtNetGroupEntries: Unable to get groupId for subnet:{}", subnetName);
163         }
164     }
165
166     public void installExtNetGroupEntry(Uuid networkId, Uuid subnetId, BigInteger dpnId, String macAddress) {
167         String subnetName = subnetId.getValue();
168         String extInterface = elanService.getExternalElanInterface(networkId.getValue(), dpnId);
169         if (extInterface == null) {
170             LOG.warn("installExtNetGroupEntry : No external ELAN interface attached to network {} subnet {} DPN id {}",
171                     networkId, subnetName, dpnId);
172             //return;
173         }
174         long groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME, NatUtil.getGroupIdKey(subnetName));
175         if (groupId != NatConstants.INVALID_ID) {
176             LOG.info(
177                 "installExtNetGroupEntry : Installing ext-net group {} entry for subnet {} with macAddress {} "
178                     + "(extInterface: {})", groupId, subnetName, macAddress, extInterface);
179             installExtNetGroupEntry(groupId, subnetName, extInterface, macAddress, dpnId);
180         } else {
181             LOG.error("installExtNetGroupEntry: Unable to get groupId for subnet:{}", subnetName);
182         }
183     }
184
185     private void installExtNetGroupEntry(long groupId, String subnetName, String extInterface,
186             String macAddress, BigInteger dpnId) {
187
188         coordinator.enqueueJob(NatUtil.getDefaultFibRouteToSNATForSubnetJobKey(subnetName, dpnId), () -> {
189             GroupEntity groupEntity = buildExtNetGroupEntity(macAddress, subnetName, groupId, extInterface, dpnId);
190             mdsalManager.syncInstallGroup(groupEntity);
191             return Collections.emptyList();
192         });
193     }
194
195     public void removeExtNetGroupEntries(Subnetmap subnetMap) {
196         if (subnetMap == null) {
197             return;
198         }
199
200         String subnetName = subnetMap.getId().getValue();
201         Uuid networkId = subnetMap.getNetworkId();
202         if (networkId == null) {
203             LOG.error("removeExtNetGroupEntries : No external network associated subnet id {}", subnetName);
204             return;
205         }
206
207         Collection<String> extInterfaces = elanService.getExternalElanInterfaces(networkId.getValue());
208         if (extInterfaces == null || extInterfaces.isEmpty()) {
209             LOG.debug("removeExtNetGroupEntries : No external ELAN interfaces attached to network {} subnet {}",
210                     networkId, subnetName);
211             return;
212         }
213
214         long groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME, NatUtil.getGroupIdKey(subnetName));
215         if (groupId != NatConstants.INVALID_ID) {
216             for (String extInterface : extInterfaces) {
217                 GroupEntity groupEntity = buildEmptyExtNetGroupEntity(subnetName, groupId,
218                     extInterface);
219                 if (groupEntity != null) {
220                     LOG.info("removeExtNetGroupEntries : Remove ext-net Group: id {}, subnet id {}",
221                         groupId, subnetName);
222                     natServiceCounters.removeExternalNetworkGroup();
223                     mdsalManager.syncRemoveGroup(groupEntity);
224                 }
225             }
226         } else {
227             LOG.error("removeExtNetGroupEntries: Unable to get groupId for subnet:{}", subnetName);
228         }
229     }
230
231     private GroupEntity buildExtNetGroupEntity(String macAddress, String subnetName,
232                                                long groupId, String extInterface, BigInteger dpnId) {
233
234         List<ActionInfo> actionList = new ArrayList<>();
235         final int setFieldEthDestActionPos = 0;
236         List<ActionInfo> egressActionList = new ArrayList<>();
237         if (extInterface != null) {
238             egressActionList = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmRpcService,
239                     interfaceManager, extInterface, null, setFieldEthDestActionPos + 1, false);
240         }
241         if (Strings.isNullOrEmpty(macAddress) || egressActionList.isEmpty()) {
242             if (Strings.isNullOrEmpty(macAddress)) {
243                 LOG.trace("buildExtNetGroupEntity : Building ext-net group {} entry with drop action since "
244                         + "GW mac has not been resolved for subnet {} extInterface {}",
245                         groupId, subnetName, extInterface);
246             } else {
247                 LOG.warn("buildExtNetGroupEntity : Building ext-net group {} entry with drop action since "
248                         + "no egress actions were found for subnet {} extInterface {}",
249                         groupId, subnetName, extInterface);
250             }
251             actionList.add(new ActionDrop());
252         } else {
253             LOG.trace("Building ext-net group {} entry for subnet {} extInterface {} macAddress {}",
254                       groupId, subnetName, extInterface, macAddress);
255             actionList.add(new ActionSetFieldEthernetDestination(setFieldEthDestActionPos, new MacAddress(macAddress)));
256             actionList.addAll(egressActionList);
257         }
258
259         List<BucketInfo> listBucketInfo = new ArrayList<>();
260         listBucketInfo.add(new BucketInfo(actionList));
261         return MDSALUtil.buildGroupEntity(dpnId, groupId, subnetName, GroupTypes.GroupAll, listBucketInfo);
262     }
263
264     @Nullable
265     private GroupEntity buildEmptyExtNetGroupEntity(String subnetName, long groupId, String extInterface) {
266         BigInteger dpId = NatUtil.getDpnForInterface(odlInterfaceRpcService, extInterface);
267         if (BigInteger.ZERO.equals(dpId)) {
268             LOG.error("buildEmptyExtNetGroupEntity: No DPN for interface {}. NAT ext-net flow will not be installed "
269                     + "for subnet {}", extInterface, subnetName);
270             return null;
271         }
272
273         return MDSALUtil.buildGroupEntity(dpId, groupId, subnetName, GroupTypes.GroupAll, new ArrayList<>());
274     }
275 }