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