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