Merge "Clean up subnet routes when vpn is out of a dpn."
[vpnservice.git] / natservice / natservice-impl / src / main / java / org / opendaylight / vpnservice / natservice / internal / DpnInVpnListener.java
1 /*
2  * Copyright (c) 2016 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.vpnservice.natservice.internal;
9
10 import java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.List;
13
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
16 import org.opendaylight.vpnservice.mdsalutil.*;
17 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.AddDpnEvent;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.add.dpn.event.AddEventData;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.RemoveDpnEvent;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.remove.dpn.event.RemoveEventData;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.OdlL3vpnListener;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.Routers;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
30 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 import com.google.common.base.Optional;
35
36 public class DpnInVpnListener implements OdlL3vpnListener {
37     private static final Logger LOG = LoggerFactory.getLogger(DpnInVpnListener.class);
38     private DataBroker dataBroker;
39     private SNATDefaultRouteProgrammer defaultRouteProgrammer;
40     private NaptSwitchHA naptSwitchHA;
41     private IMdsalApiManager mdsalManager;
42     private IdManagerService idManager;
43
44     public DpnInVpnListener(DataBroker dataBroker) {
45         this.dataBroker = dataBroker;
46     }
47
48     void setDefaultProgrammer(SNATDefaultRouteProgrammer defaultRouteProgrammer) {
49         this.defaultRouteProgrammer = defaultRouteProgrammer;
50     }
51
52     void setNaptSwitchHA(NaptSwitchHA switchHA) {
53         naptSwitchHA = switchHA;
54     }
55
56     void setMdsalManager(IMdsalApiManager mdsalManager) {
57         this.mdsalManager = mdsalManager;
58     }
59
60     public void setIdManager(IdManagerService idManager) {
61         this.idManager = idManager;
62     }
63
64     public void onAddDpnEvent(AddDpnEvent notification) {
65         AddEventData eventData =  notification.getAddEventData();
66         BigInteger dpnId = eventData.getDpnId();
67         String vpnName = eventData.getVpnName();
68         LOG.info("Received add dpn {} in vpn {} event", dpnId, vpnName);
69         String  routerId = NatUtil.getRouterIdfromVpnId(dataBroker, vpnName);
70         if (routerId != null) {
71             //check router is associated to external network
72             InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
73             Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
74             if (routerData.isPresent()) {
75                 Uuid networkId = routerData.get().getNetworkId();
76                 if(networkId != null) {
77                     LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
78                     long vpnId = NatUtil.readVpnId(dataBroker, vpnName);
79                     if(vpnId != NatConstants.INVALID_ID) {
80                         //Install default entry in FIB to SNAT table
81                         LOG.debug("Installing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
82                         defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId);
83                     } else {
84                         LOG.debug("Add DPN Event: Could not read vpnId for vpnName {}", vpnName);
85                     }
86                     if (routerData.get().isEnableSnat()) {
87                         LOG.info("SNAT enabled for router {}", routerId);
88                         handleSNATForDPN(dpnId, routerId);
89                     } else {
90                         LOG.info("SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
91                     }
92                 }
93             }
94         }
95     }
96
97     void handleSNATForDPN(BigInteger dpnId, String routerName) {
98         //Check if primary and secondary switch are selected, If not select the role
99         //Install select group to NAPT switch
100         //Install default miss entry to NAPT switch
101         BigInteger naptSwitch;
102         try {
103             Long routerId = NatUtil.getVpnId(dataBroker, routerName);
104             if (routerId == NatConstants.INVALID_ID) {
105                 LOG.error("Invalid routerId returned for routerName {}",routerName);
106                 return;
107             }
108             BigInteger naptId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
109             if (naptId == null) {
110                 LOG.debug("No Naptswitch is selected for router {}", routerName);
111
112                 naptSwitch = dpnId;
113                 boolean naptstatus = naptSwitchHA.updateNaptSwitch(routerName, naptSwitch);
114                 if(!naptstatus) {
115                     LOG.error("Failed to update newNaptSwitch {} for routername {}",naptSwitch,routerName);
116                     return;
117                 }
118                 LOG.debug("Switch {} is elected as NaptSwitch for router {}", dpnId, routerName);
119
120                 //installing group
121                 List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInPrimarySwitch();
122                 naptSwitchHA.installSnatGroupEntry(naptSwitch,bucketInfo,routerName);
123
124             }  else {
125                 LOG.debug("Napt switch is already elected for router {}"
126                         , naptId, routerName);
127                 naptSwitch = naptId;
128
129                 //installing group
130                 List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInNeighborSwitches(dpnId, routerName, naptSwitch);
131                 if (bucketInfo == null) {
132                     return;
133                 }
134                 naptSwitchHA.installSnatGroupEntry(dpnId, bucketInfo, routerName);
135
136             }
137             // Install miss entry pointing to group
138             long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
139             FlowEntity flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId,NatConstants.ADD_FLOW);
140             if (flowEntity == null) {
141                 LOG.debug("Failed to populate flowentity for router {} with dpnId {} groupIs {}",routerName,dpnId,groupId);
142                 return;
143             }
144             LOG.debug("Sucessfully installed flow for dpnId {} router {} group {}",dpnId,routerName,groupId);
145             mdsalManager.installFlow(flowEntity);
146         } catch (Exception ex) {
147             LOG.error("Exception in handleSNATForDPN method : {}",ex);
148         }
149     }
150
151     public void onRemoveDpnEvent(RemoveDpnEvent notification) {
152         RemoveEventData eventData = notification.getRemoveEventData();
153         BigInteger dpnId = eventData.getDpnId();
154         String vpnName = eventData.getVpnName();
155         LOG.info("Received remove dpn {} in vpn {} event", dpnId, vpnName);
156         String  routerId = NatUtil.getRouterIdfromVpnId(dataBroker, vpnName);
157         if (routerId != null) {
158             //check router is associated to external network
159             InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
160             Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
161             if (routerData.isPresent()) {
162                 Uuid networkId = routerData.get().getNetworkId();
163                 if(networkId != null) {
164                     LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
165                     long vpnId = NatUtil.readVpnId(dataBroker, vpnName);
166                     if(vpnId != NatConstants.INVALID_ID) {
167                         //Remove default entry in FIB
168                         LOG.debug("Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
169                         defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId);
170                     } else {
171                         LOG.debug("Remove DPN Event: Could not read vpnId for vpnName {}", vpnName);
172                     }
173                     if (routerData.get().isEnableSnat()) {
174                         LOG.info("SNAT enabled for router {}", routerId);
175                         removeSNATFromDPN(dpnId,routerId);
176                     } else {
177                         LOG.info("SNAT is not enabled for router {} to handle removeDPN event {}", routerId, dpnId);
178                     }
179                 }
180             }
181         }
182     }
183
184     void removeSNATFromDPN(BigInteger dpnId, String routerName) {
185         //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
186         //remove miss entry to NAPT switch
187         long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
188         FlowEntity flowEntity = null;
189         try {
190             flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, NatConstants.DEL_FLOW);
191             if (flowEntity == null) {
192                 LOG.debug("Failed to populate flowentity for router {} with dpnId {} groupIs {}",routerName,dpnId,groupId);
193                 return;
194             }
195             LOG.debug("NAT Service : Removing default SNAT miss entry flow entity {}",flowEntity);
196             mdsalManager.removeFlow(flowEntity);
197
198         } catch (Exception ex) {
199             LOG.debug("NAT Service : Failed to remove default SNAT miss entry flow entity {} : {}",flowEntity,ex);
200             return;
201         }
202         LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routername {}", dpnId, routerName);
203
204         //remove group
205         try {
206             GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
207                     GroupTypes.GroupAll, null);
208             LOG.info("NAT Service : Removing NAPT GroupEntity:{}", groupEntity);
209             mdsalManager.removeGroup(groupEntity);
210         } catch (Exception ex) {
211             LOG.debug("NAT Service : Failed to remove group entity {} : {}",flowEntity,ex);
212             return;
213         }
214         LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routername {}", dpnId, routerName);
215     }
216 }