To fix errors seen in CSIT run 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
13 import java.math.BigInteger;
14 import java.util.ArrayList;
15 import java.util.Arrays;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.List;
19 import javax.inject.Inject;
20 import javax.inject.Singleton;
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.createGroupId(NatUtil.getGroupIdKey(subnetName), idManager);
146
147         LOG.info("installExtNetGroupEntries : Installing ext-net group {} entry for subnet {} with macAddress {} "
148                 + "(extInterfaces: {})", groupId, subnetName, macAddress, Arrays.toString(extInterfaces.toArray()));
149         for (String extInterface : extInterfaces) {
150             BigInteger dpId = NatUtil.getDpnForInterface(odlInterfaceRpcService, extInterface);
151             if (BigInteger.ZERO.equals(dpId)) {
152                 LOG.info("installExtNetGroupEntries: No DPN for interface {}. NAT ext-net flow will not be installed "
153                     + "for subnet {}", extInterface, subnetName);
154                 return;
155             }
156             installExtNetGroupEntry(groupId, subnetName, extInterface, macAddress, dpId);
157         }
158     }
159
160     public void installExtNetGroupEntry(Uuid networkId, Uuid subnetId, BigInteger dpnId, String macAddress) {
161         String subnetName = subnetId.getValue();
162         String extInterface = elanService.getExternalElanInterface(networkId.getValue(), dpnId);
163         if (extInterface == null) {
164             LOG.warn("installExtNetGroupEntry : No external ELAN interface attached to network {} subnet {} DPN id {}",
165                     networkId, subnetName, dpnId);
166             //return;
167         }
168
169         long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(subnetName), idManager);
170         LOG.info("installExtNetGroupEntry : Installing ext-net group {} entry for subnet {} with macAddress {} "
171                 + "(extInterface: {})", groupId, subnetName, macAddress, extInterface);
172         installExtNetGroupEntry(groupId, subnetName, extInterface, macAddress, dpnId);
173     }
174
175     private void installExtNetGroupEntry(long groupId, String subnetName, String extInterface,
176             String macAddress, BigInteger dpnId) {
177
178         coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + subnetName + extInterface, () -> {
179             GroupEntity groupEntity = buildExtNetGroupEntity(macAddress, subnetName, groupId, extInterface, dpnId);
180             if (groupEntity != null) {
181                 mdsalManager.syncInstallGroup(groupEntity);
182             }
183             return Collections.emptyList();
184         });
185     }
186
187     public void removeExtNetGroupEntries(Subnetmap subnetMap) {
188         if (subnetMap == null) {
189             return;
190         }
191
192         String subnetName = subnetMap.getId().getValue();
193         Uuid networkId = subnetMap.getNetworkId();
194         if (networkId == null) {
195             LOG.error("removeExtNetGroupEntries : No external network associated subnet id {}", subnetName);
196             return;
197         }
198
199         Collection<String> extInterfaces = elanService.getExternalElanInterfaces(networkId.getValue());
200         if (extInterfaces == null || extInterfaces.isEmpty()) {
201             LOG.debug("removeExtNetGroupEntries : No external ELAN interfaces attached to network {} subnet {}",
202                     networkId, subnetName);
203             return;
204         }
205
206         long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(subnetName), idManager);
207
208         for (String extInterface : extInterfaces) {
209             GroupEntity groupEntity = buildEmptyExtNetGroupEntity(subnetName, groupId, extInterface);
210             if (groupEntity != null) {
211                 LOG.info("removeExtNetGroupEntries : Remove ext-net Group: id {}, subnet id {}", groupId, subnetName);
212                 natServiceCounters.removeExternalNetworkGroup();
213                 mdsalManager.syncRemoveGroup(groupEntity);
214             }
215         }
216     }
217
218     private GroupEntity buildExtNetGroupEntity(String macAddress, String subnetName,
219                                                long groupId, String extInterface, BigInteger dpnId) {
220
221         List<ActionInfo> actionList = new ArrayList<>();
222         final int setFieldEthDestActionPos = 0;
223         List<ActionInfo> egressActionList = new ArrayList<>();
224         if (extInterface != null) {
225             egressActionList = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmRpcService,
226                     interfaceManager, extInterface, null, setFieldEthDestActionPos + 1, false);
227         }
228         if (Strings.isNullOrEmpty(macAddress) || egressActionList.isEmpty()) {
229             if (Strings.isNullOrEmpty(macAddress)) {
230                 LOG.trace("buildExtNetGroupEntity : Building ext-net group {} entry with drop action since "
231                         + "GW mac has not been resolved for subnet {} extInterface {}",
232                         groupId, subnetName, extInterface);
233             } else {
234                 LOG.warn("buildExtNetGroupEntity : Building ext-net group {} entry with drop action since "
235                         + "no egress actions were found for subnet {} extInterface {}",
236                         groupId, subnetName, extInterface);
237             }
238             actionList.add(new ActionDrop());
239         } else {
240             LOG.trace("Building ext-net group {} entry for subnet {} extInterface {} macAddress {}",
241                       groupId, subnetName, extInterface, macAddress);
242             actionList.add(new ActionSetFieldEthernetDestination(setFieldEthDestActionPos, new MacAddress(macAddress)));
243             actionList.addAll(egressActionList);
244         }
245
246         List<BucketInfo> listBucketInfo = new ArrayList<>();
247         listBucketInfo.add(new BucketInfo(actionList));
248         return MDSALUtil.buildGroupEntity(dpnId, groupId, subnetName, GroupTypes.GroupAll, listBucketInfo);
249     }
250
251     private GroupEntity buildEmptyExtNetGroupEntity(String subnetName, long groupId, String extInterface) {
252         BigInteger dpId = NatUtil.getDpnForInterface(odlInterfaceRpcService, extInterface);
253         if (BigInteger.ZERO.equals(dpId)) {
254             LOG.error("buildEmptyExtNetGroupEntity: No DPN for interface {}. NAT ext-net flow will not be installed "
255                     + "for subnet {}", extInterface, subnetName);
256             return null;
257         }
258
259         return MDSALUtil.buildGroupEntity(dpId, groupId, subnetName, GroupTypes.GroupAll, new ArrayList<>());
260     }
261 }