2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.vpnservice.natservice.internal;
10 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ExternalNetworks;
11 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.networks.Networks;
12 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
14 import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
15 import org.opendaylight.vpnservice.mdsalutil.ActionType;
16 import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
17 import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
18 import org.opendaylight.vpnservice.mdsalutil.InstructionType;
19 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
20 import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
21 import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
22 import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
23 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
24 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
25 import org.opendaylight.yangtools.concepts.ListenerRegistration;
26 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
27 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
28 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
29 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
30 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
31 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
32 import org.opendaylight.yangtools.yang.binding.DataObject;
33 import com.google.common.base.Optional;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
42 import java.math.BigInteger;
43 import java.net.InetAddress;
44 import java.net.UnknownHostException;
45 import java.util.List;
46 import java.util.ArrayList;
49 public class ExternalNetworkListener extends org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener<Networks> implements AutoCloseable {
50 private static final Logger LOG = LoggerFactory.getLogger(ExternalNetworkListener.class);
51 private ListenerRegistration<DataChangeListener> listenerRegistration;
52 private final DataBroker broker;
53 private IMdsalApiManager mdsalManager;
55 public ExternalNetworkListener (final DataBroker db) {
56 super(Networks.class);
58 //registerListener(db);
62 public void close() throws Exception {
63 if (listenerRegistration != null) {
65 listenerRegistration.close();
66 } catch (final Exception e) {
67 LOG.error("Error when cleaning up DataChangeListener.", e);
69 listenerRegistration = null;
71 LOG.info("ExternalNetwork Listener Closed");
74 private void registerListener(final DataBroker db) {
76 listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
77 getWildCardPath(), ExternalNetworkListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
78 } catch (final Exception e) {
79 LOG.error("External Network DataChange listener registration fail!", e);
80 throw new IllegalStateException("External Network registration Listener failed.", e);
84 private InstanceIdentifier<Networks> getWildCardPath() {
85 return InstanceIdentifier.create(ExternalNetworks.class).child(Networks.class);
88 public void setMdsalManager(IMdsalApiManager mdsalManager) {
89 this.mdsalManager = mdsalManager;
93 protected void add(final InstanceIdentifier<Networks> identifier,
95 LOG.trace("External Network add mapping method - key: " + identifier + ", value=" + nw );
96 processExternalNwAdd(identifier, nw);
100 protected void remove(InstanceIdentifier<Networks> identifier, Networks nw) {
101 LOG.trace("External Network remove mapping method - key: " + identifier + ", value=" + nw );
102 processExternalNwDel(identifier, nw);
106 protected void update(InstanceIdentifier<Networks> identifier, Networks original, Networks update) {
107 LOG.trace("External Network update mapping method - key: " + identifier + ", original=" + original + ", update=" + update );
108 //check if a new router has been added or an already existing router has been deleted from the external nw to router association
109 List<Uuid> oldRtrs = original.getRouterIds();
110 List<Uuid> newRtrs = update.getRouterIds();
111 if (oldRtrs != newRtrs) {
112 //handle both addition and removal of routers
113 for (Uuid rtr : newRtrs) {
114 if (oldRtrs.contains(rtr)) {
118 //Routers added need to have the corresponding default Fib entry added to the switches in the router
119 String routerId = rtr.getValue();
120 addOrDelDefFibRouteToSNAT(routerId, true);
125 //Routers removed need to have the corresponding default Fib entry removed from the switches in the router
126 for (Uuid rtr : oldRtrs) {
127 String routerId = rtr.getValue();
128 addOrDelDefFibRouteToSNAT(routerId, false);
133 private void processExternalNwAdd(final InstanceIdentifier<Networks> identifier,
134 final Networks network) {
135 LOG.trace("Add event - key: {}, value: {}", identifier, network);
136 List<Uuid> routerList = network.getRouterIds();
138 if(routerList == null) {
139 LOG.debug("No routers associated with external network {}", identifier);
143 for(Uuid router: routerList) {
144 String routerId = router.getValue();
145 addOrDelDefFibRouteToSNAT(routerId, true);
149 private void processExternalNwDel(final InstanceIdentifier<Networks> identifier,
150 final Networks network) {
151 LOG.trace("Add event - key: {}, value: {}", identifier, network);
152 List<Uuid> routerList = network.getRouterIds();
154 for(Uuid router: routerList) {
155 String routerId = router.getValue();
156 addOrDelDefFibRouteToSNAT(routerId, false);
160 private void addOrDelDefFibRouteToSNAT(String routerId, boolean create) {
161 //Router ID is used as the internal VPN's name, hence the vrf-id in VpnInstance Op DataStore
162 InstanceIdentifier<VpnInstanceOpDataEntry> id = NatUtil.getVpnInstanceOpDataIdentifier(routerId);
163 Optional<VpnInstanceOpDataEntry> vpnInstOp = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
164 if (vpnInstOp.isPresent()) {
165 List<VpnToDpnList> dpnListInVpn = vpnInstOp.get().getVpnToDpnList();
166 for (VpnToDpnList dpn : dpnListInVpn) {
167 BigInteger dpnId = dpn.getDpnId();
168 long vpnId = NatUtil.readVpnId(broker, vpnInstOp.get().getVrfId());
169 if (create == true) {
170 installDefNATRouteInDPN(dpnId, vpnId);
172 removeDefNATRouteInDPN(dpnId, vpnId);
178 private FlowEntity buildDefNATFlowEntity(BigInteger dpId, long vpnId) {
180 InetAddress defaultIP = null;
183 defaultIP = InetAddress.getByName("0.0.0.0");
185 } catch (UnknownHostException e) {
186 LOG.error("UnknowHostException in buildDefNATFlowEntity. Failed to build FIB Table Flow for Default Route to NAT table ");
190 List<MatchInfo> matches = new ArrayList<MatchInfo>();
191 matches.add(new MatchInfo(MatchFieldType.eth_type,
192 new long[] { 0x0800L }));
194 //add match for default route "0.0.0.0/0"
195 //matches.add(new MatchInfo(MatchFieldType.ipv4_src, new long[] {
196 // NatUtil.getIpAddress(defaultIP.getAddress()), 0 }));
198 //add match for vrfid
199 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
200 BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
202 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
203 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.PSNAT_TABLE }));
205 String flowRef = NatUtil.getFlowRef(dpId, NatConstants.L3_FIB_TABLE, defaultIP);
207 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.L3_FIB_TABLE, flowRef,
208 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
209 NatConstants.COOKIE_DNAT_TABLE, matches, instructions);
216 private void installDefNATRouteInDPN(BigInteger dpnId, long vpnId) {
217 FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, vpnId);
218 if(flowEntity == null) {
219 LOG.error("Flow entity received is NULL. Cannot proceed with installation of Default NAT flow");
222 mdsalManager.installFlow(flowEntity);
225 private void removeDefNATRouteInDPN(BigInteger dpnId, long vpnId) {
226 FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, vpnId);
227 if(flowEntity == null) {
228 LOG.error("Flow entity received is NULL. Cannot proceed with installation of Default NAT flow");
231 mdsalManager.removeFlow(flowEntity);