Using Table Ids from NwConstants.java
[netvirt.git] / vpnservice / natservice / natservice-impl / src / main / java / org / opendaylight / netvirt / natservice / internal / ExternalNetworkListener.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.netvirt.natservice.internal;
9
10 import org.opendaylight.genius.mdsalutil.*;
11 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
12 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
13 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
14 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
15 import org.opendaylight.yangtools.concepts.ListenerRegistration;
16 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
19 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21
22 import com.google.common.base.Optional;
23
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 import java.math.BigInteger;
31 import java.net.InetAddress;
32 import java.net.UnknownHostException;
33 import java.util.List;
34 import java.util.ArrayList;
35
36
37 public class ExternalNetworkListener extends AbstractDataChangeListener<Networks> implements AutoCloseable {
38     private static final Logger LOG = LoggerFactory.getLogger(ExternalNetworkListener.class);
39     private ListenerRegistration<DataChangeListener> listenerRegistration;
40     private final DataBroker broker;
41     private IMdsalApiManager mdsalManager;
42
43     public ExternalNetworkListener (final DataBroker db) {
44         super(Networks.class);
45         broker = db;
46         //registerListener(db);
47     }
48
49     @Override
50     public void close() throws Exception {
51         if (listenerRegistration != null) {
52             try {
53                 listenerRegistration.close();
54             } catch (final Exception e) {
55                 LOG.error("Error when cleaning up DataChangeListener.", e);
56             }
57             listenerRegistration = null;
58         }
59         LOG.info("ExternalNetwork Listener Closed");
60     }
61
62     private void registerListener(final DataBroker db) {
63         try {
64             listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
65                     getWildCardPath(), ExternalNetworkListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
66         } catch (final Exception e) {
67             LOG.error("External Network DataChange listener registration fail!", e);
68             throw new IllegalStateException("External Network registration Listener failed.", e);
69         }
70     }
71
72     private InstanceIdentifier<Networks> getWildCardPath() {
73         return InstanceIdentifier.create(ExternalNetworks.class).child(Networks.class);
74     }
75
76     public void setMdsalManager(IMdsalApiManager mdsalManager) {
77         this.mdsalManager = mdsalManager;
78     }
79
80     @Override
81     protected void add(final InstanceIdentifier<Networks> identifier,
82                        final Networks nw) {
83         LOG.trace("External Network add mapping method - key: " + identifier + ", value=" + nw );
84         processExternalNwAdd(identifier, nw);
85     }
86
87     @Override
88     protected void remove(InstanceIdentifier<Networks> identifier, Networks nw) {
89         LOG.trace("External Network remove mapping method - key: " + identifier + ", value=" + nw );
90         processExternalNwDel(identifier, nw);
91     }
92
93     @Override
94     protected void update(InstanceIdentifier<Networks> identifier, Networks original, Networks update) {
95         LOG.trace("External Network update mapping method - key: " + identifier + ", original=" + original + ", update=" + update );
96         //check if a new router has been added or an already existing router has been deleted from the external nw to router association
97         List<Uuid> oldRtrs = original.getRouterIds();
98         List<Uuid> newRtrs = update.getRouterIds();
99         if (oldRtrs != newRtrs) {
100             //handle both addition and removal of routers
101             for (Uuid rtr : newRtrs) {
102                 if (oldRtrs.contains(rtr)) {
103                     oldRtrs.remove(rtr);
104                 } else {
105                     // new router case
106                     //Routers added need to have the corresponding default Fib entry added to the switches in the router
107                     String routerId = rtr.getValue();
108                     addOrDelDefFibRouteToSNAT(routerId, true);
109
110                 }
111             }
112
113             //Routers removed need to have the corresponding default Fib entry removed from the switches in the router
114             for (Uuid rtr : oldRtrs) {
115                 String routerId = rtr.getValue();
116                 addOrDelDefFibRouteToSNAT(routerId, false);
117             }
118         }
119     }
120
121     private void processExternalNwAdd(final InstanceIdentifier<Networks> identifier,
122                                       final Networks network) {
123         LOG.trace("Add event - key: {}, value: {}", identifier, network);
124         List<Uuid> routerList = network.getRouterIds();
125
126         if(routerList == null) {
127             LOG.debug("No routers associated with external network {}", identifier);
128             return;
129         }
130
131         for(Uuid router: routerList) {
132             String routerId = router.getValue();
133             addOrDelDefFibRouteToSNAT(routerId, true);
134         }
135     }
136
137     private void processExternalNwDel(final InstanceIdentifier<Networks> identifier,
138                                       final Networks network) {
139         LOG.trace("Add event - key: {}, value: {}", identifier, network);
140         List<Uuid> routerList = network.getRouterIds();
141
142         for(Uuid router: routerList) {
143             String routerId = router.getValue();
144             addOrDelDefFibRouteToSNAT(routerId, false);
145         }
146     }
147
148     private void addOrDelDefFibRouteToSNAT(String routerId, boolean create) {
149         //Router ID is used as the internal VPN's name, hence the vrf-id in VpnInstance Op DataStore
150         InstanceIdentifier<VpnInstanceOpDataEntry> id = NatUtil.getVpnInstanceOpDataIdentifier(routerId);
151         Optional<VpnInstanceOpDataEntry> vpnInstOp = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
152         if (vpnInstOp.isPresent()) {
153             List<VpnToDpnList> dpnListInVpn = vpnInstOp.get().getVpnToDpnList();
154             for (VpnToDpnList dpn : dpnListInVpn) {
155                 BigInteger dpnId = dpn.getDpnId();
156                 long vpnId = NatUtil.readVpnId(broker, vpnInstOp.get().getVrfId());
157                 if (create) {
158                     installDefNATRouteInDPN(dpnId, vpnId);
159                 } else {
160                     removeDefNATRouteInDPN(dpnId, vpnId);
161                 }
162             }
163         }
164     }
165
166     private FlowEntity buildDefNATFlowEntity(BigInteger dpId, long vpnId) {
167
168         InetAddress defaultIP = null;
169
170         try {
171             defaultIP = InetAddress.getByName("0.0.0.0");
172
173         } catch (UnknownHostException e) {
174             LOG.error("UnknowHostException in buildDefNATFlowEntity. Failed  to build FIB Table Flow for Default Route to NAT table ");
175             return null;
176         }
177
178         List<MatchInfo> matches = new ArrayList<>();
179         matches.add(new MatchInfo(MatchFieldType.eth_type,
180                 new long[] { 0x0800L }));
181
182         //add match for default route "0.0.0.0/0"
183         //matches.add(new MatchInfo(MatchFieldType.ipv4_src, new long[] {
184         //        NatUtil.getIpAddress(defaultIP.getAddress()), 0 }));
185
186         //add match for vrfid
187         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
188                 BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
189
190         List<InstructionInfo> instructions = new ArrayList<>();
191         instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.PSNAT_TABLE }));
192
193         String flowRef = NatUtil.getFlowRef(dpId, NwConstants.L3_FIB_TABLE, defaultIP);
194
195         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef,
196                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
197                 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
198
199         return flowEntity;
200
201
202     }
203
204     private void installDefNATRouteInDPN(BigInteger dpnId, long vpnId) {
205         FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, vpnId);
206         if(flowEntity == null) {
207             LOG.error("Flow entity received is NULL. Cannot proceed with installation of Default NAT flow");
208             return;
209         }
210         mdsalManager.installFlow(flowEntity);
211     }
212
213     private void removeDefNATRouteInDPN(BigInteger dpnId, long vpnId) {
214         FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, vpnId);
215         if(flowEntity == null) {
216             LOG.error("Flow entity received is NULL. Cannot proceed with installation of Default NAT flow");
217             return;
218         }
219         mdsalManager.removeFlow(flowEntity);
220     }
221
222
223 }