7efb852268d531ce212e1bbc0d347814b7af89a2
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / SNATDefaultRouteProgrammer.java
1 /*
2  * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. 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 package org.opendaylight.netvirt.natservice.internal;
9
10 import java.math.BigInteger;
11 import java.net.InetAddress;
12 import java.net.UnknownHostException;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.List;
16 import java.util.Set;
17 import java.util.concurrent.ExecutionException;
18 import javax.annotation.Nullable;
19 import javax.inject.Inject;
20 import javax.inject.Singleton;
21
22 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
23 import org.opendaylight.genius.infra.Datastore.Configuration;
24 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
25 import org.opendaylight.genius.infra.TypedWriteTransaction;
26 import org.opendaylight.genius.mdsalutil.FlowEntity;
27 import org.opendaylight.genius.mdsalutil.InstructionInfo;
28 import org.opendaylight.genius.mdsalutil.MDSALUtil;
29 import org.opendaylight.genius.mdsalutil.MatchInfo;
30 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
31 import org.opendaylight.genius.mdsalutil.NwConstants;
32 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
33 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
34 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
35 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
36 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
37 import org.opendaylight.netvirt.natservice.api.NatSwitchCache;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.Subnets;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 @Singleton
45 public class SNATDefaultRouteProgrammer {
46
47     private static final Logger LOG = LoggerFactory.getLogger(SNATDefaultRouteProgrammer.class);
48     private final IMdsalApiManager mdsalManager;
49     private final DataBroker dataBroker;
50     private final IdManagerService idManager;
51     private final ExternalNetworkGroupInstaller extNetGroupInstaller;
52     private final NatServiceCounters natServiceCounters;
53     private final JobCoordinator jobCoordinator;
54     private final NatSwitchCache natSwitchCache;
55
56     @Inject
57     public SNATDefaultRouteProgrammer(final IMdsalApiManager mdsalManager, final DataBroker dataBroker,
58             final IdManagerService idManager, final ExternalNetworkGroupInstaller extNetGroupInstaller,
59             NatServiceCounters natServiceCounters, final JobCoordinator jobCoordinator,
60             final NatSwitchCache natSwitchCache) {
61         this.mdsalManager = mdsalManager;
62         this.dataBroker = dataBroker;
63         this.idManager = idManager;
64         this.extNetGroupInstaller = extNetGroupInstaller;
65         this.natServiceCounters = natServiceCounters;
66         this.jobCoordinator = jobCoordinator;
67         this.natSwitchCache = natSwitchCache;
68     }
69
70     @Nullable
71     private FlowEntity buildDefNATFlowEntity(BigInteger dpId, long vpnId) {
72         InetAddress defaultIP = null;
73         try {
74             defaultIP = InetAddress.getByName("0.0.0.0");
75         } catch (UnknownHostException e) {
76             LOG.error("buildDefNATFlowEntity : Failed  to build FIB Table Flow for "
77                 + "Default Route to NAT table", e);
78             return null;
79         }
80
81         List<MatchInfo> matches = new ArrayList<>();
82         matches.add(MatchEthernetType.IPV4);
83
84         //add match for default route "0.0.0.0/0"
85 //        matches.add(new MatchInfo(MatchFieldType.ipv4_dst, new long[] {
86 //                NatUtil.getIpAddress(defaultIP.getAddress()), 0 }));
87
88         //add match for vrfid
89         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
90
91         List<InstructionInfo> instructions = new ArrayList<>();
92         instructions.add(new InstructionGotoTable(NwConstants.PSNAT_TABLE));
93
94         String flowRef = NatUtil.getFlowRef(dpId, NwConstants.L3_FIB_TABLE, defaultIP, vpnId);
95
96         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef,
97             NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
98             NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
99
100         return flowEntity;
101     }
102
103     @Nullable
104     private FlowEntity buildDefNATFlowEntity(BigInteger dpId, long bgpVpnId, long routerId) {
105         InetAddress defaultIP = null;
106         try {
107             defaultIP = InetAddress.getByName("0.0.0.0");
108         } catch (UnknownHostException e) {
109             LOG.error("buildDefNATFlowEntity : Failed  to build FIB Table Flow for "
110                 + "Default Route to NAT table", e);
111             return null;
112         }
113
114         List<MatchInfo> matches = new ArrayList<>();
115         matches.add(MatchEthernetType.IPV4);
116
117         //add match for default route "0.0.0.0/0"
118 //        matches.add(new MatchInfo(MatchFieldType.ipv4_dst, new long[] {
119 //                NatUtil.getIpAddress(defaultIP.getAddress()), 0 }));
120
121         //add match for vrfid
122         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(bgpVpnId), MetaDataUtil.METADATA_MASK_VRFID));
123
124         List<InstructionInfo> instructions = new ArrayList<>();
125         instructions.add(new InstructionGotoTable(NwConstants.PSNAT_TABLE));
126
127         String flowRef = NatUtil.getFlowRef(dpId, NwConstants.L3_FIB_TABLE, defaultIP, routerId);
128
129         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef,
130             NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
131             NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
132
133         return flowEntity;
134
135
136     }
137
138     public void installDefNATRouteInDPN(BigInteger dpnId, long vpnId, TypedWriteTransaction<Configuration> confTx) {
139         FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, vpnId);
140         if (flowEntity == null) {
141             LOG.error("installDefNATRouteInDPN : Flow entity received is NULL."
142                     + "Cannot proceed with installation of Default NAT flow");
143             return;
144         }
145         natServiceCounters.installDefaultNatFlow();
146         mdsalManager.addFlow(confTx, flowEntity);
147     }
148
149     public void installDefNATRouteInDPN(BigInteger dpnId, long bgpVpnId, long routerId,
150         TypedWriteTransaction<Configuration> confTx) {
151         FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, bgpVpnId, routerId);
152         if (flowEntity == null) {
153             LOG.error("installDefNATRouteInDPN : Flow entity received is NULL."
154                     + "Cannot proceed with installation of Default NAT flow");
155             return;
156         }
157         natServiceCounters.installDefaultNatFlow();
158         mdsalManager.addFlow(confTx, flowEntity);
159     }
160
161     public void installDefNATRouteInDPN(BigInteger dpnId, long vpnId, String subnetId) {
162         FlowEntity flowEntity = NatUtil.buildDefaultNATFlowEntityForExternalSubnet(dpnId, vpnId, subnetId, idManager);
163         if (flowEntity == null) {
164             LOG.error("installDefNATRouteInDPN : Flow entity received is NULL."
165                     + "Cannot proceed with installation of Default NAT flow");
166             return;
167         }
168         natServiceCounters.installDefaultNatFlow();
169         mdsalManager.installFlow(flowEntity);
170     }
171
172     public void removeDefNATRouteInDPN(BigInteger dpnId, long vpnId, TypedReadWriteTransaction<Configuration> confTx)
173             throws ExecutionException, InterruptedException {
174         FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, vpnId);
175         if (flowEntity == null) {
176             LOG.error("removeDefNATRouteInDPN : Flow entity received is NULL."
177                     + "Cannot proceed with installation of Default NAT flow");
178             return;
179         }
180         natServiceCounters.removeDefaultNatFlow();
181         mdsalManager.removeFlow(confTx, flowEntity);
182     }
183
184     public void removeDefNATRouteInDPN(BigInteger dpnId, long bgpVpnId, long routerId,
185             TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
186         FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, bgpVpnId, routerId);
187         if (flowEntity == null) {
188             LOG.error("removeDefNATRouteInDPN : Flow entity received is NULL."
189                     + "Cannot proceed with installation of Default NAT flow");
190             return;
191         }
192         natServiceCounters.removeDefaultNatFlow();
193         mdsalManager.removeFlow(confTx, flowEntity);
194     }
195
196     public void addOrDelDefaultFibRouteToSNATForSubnet(Subnets subnet, String networkId, int flowAction, long vpnId) {
197         String providerNet = NatUtil.getElanInstancePhysicalNetwok(networkId, dataBroker);
198         Set<BigInteger> dpnList = natSwitchCache.getSwitchesConnectedToExternal(providerNet);
199
200         for (BigInteger dpn : dpnList) {
201             addOrDelDefaultFibRouteToSNATForSubnetInDpn(subnet, networkId, flowAction, vpnId, dpn);
202         }
203     }
204
205     public void addOrDelDefaultFibRouteToSNATForSubnetInDpn(Subnets subnet, String networkId, int flowAction,
206             long vpnId, BigInteger dpn) {
207         String subnetId = subnet.getId().getValue();
208         String macAddress = NatUtil.getSubnetGwMac(dataBroker, subnet.getId(), networkId);
209         extNetGroupInstaller.installExtNetGroupEntry(new Uuid(networkId), subnet.getId(),
210                 dpn, macAddress);
211         FlowEntity flowEntity = NatUtil.buildDefaultNATFlowEntityForExternalSubnet(dpn,
212                 vpnId, subnetId, idManager);
213         if (flowAction == NwConstants.ADD_FLOW || flowAction == NwConstants.MOD_FLOW) {
214             LOG.info("addOrDelDefaultFibRouteToSNATForSubnet : Installing flow {} for subnetId {},"
215                     + "vpnId {} on dpn {}", flowEntity, subnetId, vpnId, dpn);
216             jobCoordinator.enqueueJob(NatUtil.getDefaultFibRouteToSNATForSubnetJobKey(subnetId, dpn),
217                 () -> Collections.singletonList(mdsalManager.installFlow(flowEntity)));
218         } else {
219             LOG.info("addOrDelDefaultFibRouteToSNATForSubnet : Removing flow for subnetId {},"
220                     + "vpnId {} with dpn {}", subnetId, vpnId, dpn);
221             jobCoordinator.enqueueJob(NatUtil.getDefaultFibRouteToSNATForSubnetJobKey(subnetId, dpn),
222                 () -> Collections.singletonList(mdsalManager.removeFlow(flowEntity)));
223         }
224     }
225 }