itm-direct tunnel related changes for scaling
[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
54     @Inject
55     public ExternalNetworkGroupInstaller(final DataBroker broker, final IMdsalApiManager mdsalManager,
56                                          final IElanService elanService, final IdManagerService idManager,
57                                          final OdlInterfaceRpcService odlInterfaceRpcService,
58                                          final JobCoordinator coordinator, final ItmRpcService itmRpcService,
59                                          final IInterfaceManager interfaceManager) {
60
61         this.broker = broker;
62         this.mdsalManager = mdsalManager;
63         this.elanService = elanService;
64         this.idManager = idManager;
65         this.odlInterfaceRpcService = odlInterfaceRpcService;
66         this.coordinator = coordinator;
67         this.itmRpcService = itmRpcService;
68         this.interfaceManager = interfaceManager;
69     }
70
71     public void installExtNetGroupEntries(Subnetmap subnetMap) {
72         if (subnetMap == null) {
73             LOG.error("installExtNetGroupEntries : Subnetmap is null");
74             return;
75         }
76
77         if (NatUtil.isIPv6Subnet(subnetMap.getSubnetIp())) {
78             LOG.debug("installExtNetGroupEntries : Subnet id {} is not an IPv4 subnet, hence skipping.",
79                     subnetMap.getId());
80             return;
81         }
82
83         Uuid networkId = subnetMap.getNetworkId();
84         Uuid subnetId = subnetMap.getId();
85         if (networkId == null) {
86             LOG.error("installExtNetGroupEntries : No network associated subnet id {}", subnetId.getValue());
87             return;
88         }
89
90         String macAddress = NatUtil.getSubnetGwMac(broker, subnetId, networkId.getValue());
91         installExtNetGroupEntries(subnetMap, macAddress);
92     }
93
94     public void installExtNetGroupEntries(Uuid subnetId, String macAddress) {
95         Subnetmap subnetMap = NatUtil.getSubnetMap(broker, subnetId);
96         if (subnetMap == null) {
97             LOG.error("installExtNetGroupEntries : Subnetmap is null");
98             return;
99         }
100
101         if (NatUtil.isIPv6Subnet(subnetMap.getSubnetIp())) {
102             LOG.debug("installExtNetGroupEntries : Subnet-id {} is not an IPv4 subnet, hence skipping.",
103                     subnetMap.getId());
104             return;
105         }
106         installExtNetGroupEntries(subnetMap, macAddress);
107     }
108
109     public void installExtNetGroupEntries(Uuid networkId, BigInteger dpnId) {
110         if (networkId == null) {
111             return;
112         }
113
114         List<Uuid> subnetIds = NatUtil.getSubnetIdsFromNetworkId(broker, networkId);
115         if (subnetIds.isEmpty()) {
116             LOG.error("installExtNetGroupEntries : No subnet ids associated network id {}", networkId.getValue());
117             return;
118         }
119
120         for (Uuid subnetId : subnetIds) {
121             String macAddress = NatUtil.getSubnetGwMac(broker, subnetId, networkId.getValue());
122             installExtNetGroupEntry(networkId, subnetId, dpnId, macAddress);
123         }
124     }
125
126     private void installExtNetGroupEntries(Subnetmap subnetMap, String macAddress) {
127
128         String subnetName = subnetMap.getId().getValue();
129         Uuid networkId = subnetMap.getNetworkId();
130         if (networkId == null) {
131             LOG.error("installExtNetGroupEntries : No network associated subnet id {}", subnetName);
132             return;
133         }
134
135         Collection<String> extInterfaces = elanService.getExternalElanInterfaces(networkId.getValue());
136         if (extInterfaces == null || extInterfaces.isEmpty()) {
137             LOG.trace("installExtNetGroupEntries : No external ELAN interfaces attached to network:{},subnet {}",
138                     networkId, subnetName);
139             return;
140         }
141
142         long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(subnetName), idManager);
143
144         LOG.info("installExtNetGroupEntries : Installing ext-net group {} entry for subnet {} with macAddress {} "
145                 + "(extInterfaces: {})", groupId, subnetName, macAddress, Arrays.toString(extInterfaces.toArray()));
146         for (String extInterface : extInterfaces) {
147             BigInteger dpId = NatUtil.getDpnForInterface(odlInterfaceRpcService, extInterface);
148             if (BigInteger.ZERO.equals(dpId)) {
149                 LOG.info("installExtNetGroupEntries: No DPN for interface {}. NAT ext-net flow will not be installed "
150                     + "for subnet {}", extInterface, subnetName);
151                 return;
152             }
153             installExtNetGroupEntry(groupId, subnetName, extInterface, macAddress, dpId);
154         }
155     }
156
157     public void installExtNetGroupEntry(Uuid networkId, Uuid subnetId, BigInteger dpnId, String macAddress) {
158         String subnetName = subnetId.getValue();
159         String extInterface = elanService.getExternalElanInterface(networkId.getValue(), dpnId);
160         if (extInterface == null) {
161             LOG.warn("installExtNetGroupEntry : No external ELAN interface attached to network {} subnet {} DPN id {}",
162                     networkId, subnetName, dpnId);
163             //return;
164         }
165
166         long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(subnetName), idManager);
167         LOG.info("installExtNetGroupEntry : Installing ext-net group {} entry for subnet {} with macAddress {} "
168                 + "(extInterface: {})", groupId, subnetName, macAddress, extInterface);
169         installExtNetGroupEntry(groupId, subnetName, extInterface, macAddress, dpnId);
170     }
171
172     private void installExtNetGroupEntry(long groupId, String subnetName, String extInterface,
173             String macAddress, BigInteger dpnId) {
174
175         coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + subnetName + extInterface, () -> {
176             GroupEntity groupEntity = buildExtNetGroupEntity(macAddress, subnetName, groupId, extInterface, dpnId);
177             if (groupEntity != null) {
178                 mdsalManager.syncInstallGroup(groupEntity);
179             }
180             return Collections.emptyList();
181         });
182     }
183
184     public void removeExtNetGroupEntries(Subnetmap subnetMap) {
185         if (subnetMap == null) {
186             return;
187         }
188
189         String subnetName = subnetMap.getId().getValue();
190         Uuid networkId = subnetMap.getNetworkId();
191         if (networkId == null) {
192             LOG.error("removeExtNetGroupEntries : No external network associated subnet id {}", subnetName);
193             return;
194         }
195
196         Collection<String> extInterfaces = elanService.getExternalElanInterfaces(networkId.getValue());
197         if (extInterfaces == null || extInterfaces.isEmpty()) {
198             LOG.debug("removeExtNetGroupEntries : No external ELAN interfaces attached to network {} subnet {}",
199                     networkId, subnetName);
200             return;
201         }
202
203         long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(subnetName), idManager);
204
205         for (String extInterface : extInterfaces) {
206             GroupEntity groupEntity = buildEmptyExtNetGroupEntity(subnetName, groupId, extInterface);
207             if (groupEntity != null) {
208                 LOG.info("removeExtNetGroupEntries : Remove ext-net Group: id {}, subnet id {}", groupId, subnetName);
209                 NatServiceCounters.remove_external_network_group.inc();
210                 mdsalManager.syncRemoveGroup(groupEntity);
211             }
212         }
213     }
214
215     private GroupEntity buildExtNetGroupEntity(String macAddress, String subnetName,
216                                                long groupId, String extInterface, BigInteger dpnId) {
217
218         List<ActionInfo> actionList = new ArrayList<>();
219         final int setFieldEthDestActionPos = 0;
220         List<ActionInfo> egressActionList = new ArrayList<>();
221         if (extInterface != null) {
222             egressActionList = NatUtil.getEgressActionsForInterface(odlInterfaceRpcService, itmRpcService,
223                     interfaceManager, extInterface, null, setFieldEthDestActionPos + 1);
224         }
225         if (Strings.isNullOrEmpty(macAddress) || egressActionList.isEmpty()) {
226             if (Strings.isNullOrEmpty(macAddress)) {
227                 LOG.trace("buildExtNetGroupEntity : Building ext-net group {} entry with drop action since "
228                         + "GW mac has not been resolved for subnet {} extInterface {}",
229                         groupId, subnetName, extInterface);
230             } else {
231                 LOG.warn("buildExtNetGroupEntity : Building ext-net group {} entry with drop action since "
232                         + "no egress actions were found for subnet {} extInterface {}",
233                         groupId, subnetName, extInterface);
234             }
235             actionList.add(new ActionDrop());
236         } else {
237             LOG.trace("Building ext-net group {} entry for subnet {} extInterface {} macAddress {}",
238                       groupId, subnetName, extInterface, macAddress);
239             actionList.add(new ActionSetFieldEthernetDestination(setFieldEthDestActionPos, new MacAddress(macAddress)));
240             actionList.addAll(egressActionList);
241         }
242
243         List<BucketInfo> listBucketInfo = new ArrayList<>();
244         listBucketInfo.add(new BucketInfo(actionList));
245         return MDSALUtil.buildGroupEntity(dpnId, groupId, subnetName, GroupTypes.GroupAll, listBucketInfo);
246     }
247
248     private GroupEntity buildEmptyExtNetGroupEntity(String subnetName, long groupId, String extInterface) {
249         BigInteger dpId = NatUtil.getDpnForInterface(odlInterfaceRpcService, extInterface);
250         if (BigInteger.ZERO.equals(dpId)) {
251             LOG.error("buildEmptyExtNetGroupEntity: No DPN for interface {}. NAT ext-net flow will not be installed "
252                     + "for subnet {}", extInterface, subnetName);
253             return null;
254         }
255
256         return MDSALUtil.buildGroupEntity(dpId, groupId, subnetName, GroupTypes.GroupAll, new ArrayList<>());
257     }
258 }