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.netvirt.natservice.internal;
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;
22 import com.google.common.base.Optional;
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;
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;
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;
43 public ExternalNetworkListener (final DataBroker db) {
44 super(Networks.class);
46 //registerListener(db);
50 public void close() throws Exception {
51 if (listenerRegistration != null) {
53 listenerRegistration.close();
54 } catch (final Exception e) {
55 LOG.error("Error when cleaning up DataChangeListener.", e);
57 listenerRegistration = null;
59 LOG.info("ExternalNetwork Listener Closed");
62 private void registerListener(final DataBroker db) {
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);
72 private InstanceIdentifier<Networks> getWildCardPath() {
73 return InstanceIdentifier.create(ExternalNetworks.class).child(Networks.class);
76 public void setMdsalManager(IMdsalApiManager mdsalManager) {
77 this.mdsalManager = mdsalManager;
81 protected void add(final InstanceIdentifier<Networks> identifier,
83 LOG.trace("External Network add mapping method - key: " + identifier + ", value=" + nw );
84 processExternalNwAdd(identifier, nw);
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);
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)) {
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);
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);
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();
126 if(routerList == null) {
127 LOG.debug("No routers associated with external network {}", identifier);
131 for(Uuid router: routerList) {
132 String routerId = router.getValue();
133 addOrDelDefFibRouteToSNAT(routerId, true);
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();
142 for(Uuid router: routerList) {
143 String routerId = router.getValue();
144 addOrDelDefFibRouteToSNAT(routerId, false);
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());
158 installDefNATRouteInDPN(dpnId, vpnId);
160 removeDefNATRouteInDPN(dpnId, vpnId);
166 private FlowEntity buildDefNATFlowEntity(BigInteger dpId, long vpnId) {
168 InetAddress defaultIP = null;
171 defaultIP = InetAddress.getByName("0.0.0.0");
173 } catch (UnknownHostException e) {
174 LOG.error("UnknowHostException in buildDefNATFlowEntity. Failed to build FIB Table Flow for Default Route to NAT table ");
178 List<MatchInfo> matches = new ArrayList<>();
179 matches.add(new MatchInfo(MatchFieldType.eth_type,
180 new long[] { 0x0800L }));
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 }));
186 //add match for vrfid
187 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
188 BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
190 List<InstructionInfo> instructions = new ArrayList<>();
191 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.PSNAT_TABLE }));
193 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.L3_FIB_TABLE, defaultIP);
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);
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");
210 mdsalManager.installFlow(flowEntity);
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");
219 mdsalManager.removeFlow(flowEntity);