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 com.google.common.base.Optional;
11 import java.math.BigInteger;
12 import java.net.InetAddress;
13 import java.net.UnknownHostException;
14 import java.util.ArrayList;
15 import java.util.List;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
18 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.genius.mdsalutil.AbstractDataChangeListener;
21 import org.opendaylight.genius.mdsalutil.FlowEntity;
22 import org.opendaylight.genius.mdsalutil.InstructionInfo;
23 import org.opendaylight.genius.mdsalutil.InstructionType;
24 import org.opendaylight.genius.mdsalutil.MDSALUtil;
25 import org.opendaylight.genius.mdsalutil.MatchFieldType;
26 import org.opendaylight.genius.mdsalutil.MatchInfo;
27 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
28 import org.opendaylight.genius.mdsalutil.NwConstants;
29 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
35 import org.opendaylight.yangtools.concepts.ListenerRegistration;
36 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
40 public class ExternalNetworkListener extends AbstractDataChangeListener<Networks> implements AutoCloseable {
41 private static final Logger LOG = LoggerFactory.getLogger(ExternalNetworkListener.class);
42 private ListenerRegistration<DataChangeListener> listenerRegistration;
43 private final DataBroker dataBroker;
44 private final IMdsalApiManager mdsalManager;
46 public ExternalNetworkListener (final DataBroker dataBroker, final IMdsalApiManager mdsalManager) {
47 super(Networks.class);
48 this.dataBroker = dataBroker;
49 this.mdsalManager = mdsalManager;
53 LOG.info("{} init", getClass().getSimpleName());
54 listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
55 getWildCardPath(), this, AsyncDataBroker.DataChangeScope.SUBTREE);
58 private InstanceIdentifier<Networks> getWildCardPath() {
59 return InstanceIdentifier.create(ExternalNetworks.class).child(Networks.class);
63 public void close() throws Exception {
64 if (listenerRegistration != null) {
65 listenerRegistration.close();
66 listenerRegistration = null;
68 LOG.info("{} close", getClass().getSimpleName());
72 protected void add(final InstanceIdentifier<Networks> identifier,
74 LOG.trace("External Network add mapping method - key: " + identifier + ", value=" + nw );
75 processExternalNwAdd(identifier, nw);
79 protected void remove(InstanceIdentifier<Networks> identifier, Networks nw) {
80 LOG.trace("External Network remove mapping method - key: " + identifier + ", value=" + nw );
81 processExternalNwDel(identifier, nw);
85 protected void update(InstanceIdentifier<Networks> identifier, Networks original, Networks update) {
86 LOG.trace("External Network update mapping method - key: " + identifier + ", original=" + original + ", update=" + update );
87 //check if a new router has been added or an already existing router has been deleted from the external nw to router association
88 List<Uuid> oldRtrs = original.getRouterIds();
89 List<Uuid> newRtrs = update.getRouterIds();
90 if (oldRtrs != newRtrs) {
91 //handle both addition and removal of routers
92 for (Uuid rtr : newRtrs) {
93 if (oldRtrs.contains(rtr)) {
97 //Routers added need to have the corresponding default Fib entry added to the switches in the router
98 String routerId = rtr.getValue();
99 addOrDelDefFibRouteToSNAT(routerId, true);
104 //Routers removed need to have the corresponding default Fib entry removed from the switches in the router
105 for (Uuid rtr : oldRtrs) {
106 String routerId = rtr.getValue();
107 addOrDelDefFibRouteToSNAT(routerId, false);
112 private void processExternalNwAdd(final InstanceIdentifier<Networks> identifier,
113 final Networks network) {
114 LOG.trace("Add event - key: {}, value: {}", identifier, network);
115 List<Uuid> routerList = network.getRouterIds();
117 if(routerList == null) {
118 LOG.debug("No routers associated with external network {}", identifier);
122 for(Uuid router: routerList) {
123 String routerId = router.getValue();
124 addOrDelDefFibRouteToSNAT(routerId, true);
128 private void processExternalNwDel(final InstanceIdentifier<Networks> identifier,
129 final Networks network) {
130 LOG.trace("Add event - key: {}, value: {}", identifier, network);
131 List<Uuid> routerList = network.getRouterIds();
133 for(Uuid router: routerList) {
134 String routerId = router.getValue();
135 addOrDelDefFibRouteToSNAT(routerId, false);
139 private void addOrDelDefFibRouteToSNAT(String routerId, boolean create) {
140 //Router ID is used as the internal VPN's name, hence the vrf-id in VpnInstance Op DataStore
141 InstanceIdentifier<VpnInstanceOpDataEntry> id = NatUtil.getVpnInstanceOpDataIdentifier(routerId);
142 Optional<VpnInstanceOpDataEntry> vpnInstOp = NatUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
143 if (vpnInstOp.isPresent()) {
144 List<VpnToDpnList> dpnListInVpn = vpnInstOp.get().getVpnToDpnList();
145 if (dpnListInVpn != null) {
146 for (VpnToDpnList dpn : dpnListInVpn) {
147 BigInteger dpnId = dpn.getDpnId();
148 long vpnId = NatUtil.readVpnId(dataBroker, vpnInstOp.get().getVrfId());
150 installDefNATRouteInDPN(dpnId, vpnId);
152 removeDefNATRouteInDPN(dpnId, vpnId);
159 private FlowEntity buildDefNATFlowEntity(BigInteger dpId, long vpnId) {
161 InetAddress defaultIP = null;
164 defaultIP = InetAddress.getByName("0.0.0.0");
166 } catch (UnknownHostException e) {
167 LOG.error("UnknowHostException in buildDefNATFlowEntity. Failed to build FIB Table Flow for Default Route to NAT table ");
171 List<MatchInfo> matches = new ArrayList<>();
172 matches.add(new MatchInfo(MatchFieldType.eth_type,
173 new long[] { 0x0800L }));
175 //add match for default route "0.0.0.0/0"
176 //matches.add(new MatchInfo(MatchFieldType.ipv4_src, new long[] {
177 // NatUtil.getIpAddress(defaultIP.getAddress()), 0 }));
179 //add match for vrfid
180 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
181 MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
183 List<InstructionInfo> instructions = new ArrayList<>();
184 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.PSNAT_TABLE }));
186 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.L3_FIB_TABLE, defaultIP);
188 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef,
189 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
190 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
197 private void installDefNATRouteInDPN(BigInteger dpnId, long vpnId) {
198 FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, vpnId);
199 if(flowEntity == null) {
200 LOG.error("Flow entity received is NULL. Cannot proceed with installation of Default NAT flow");
203 mdsalManager.installFlow(flowEntity);
206 private void removeDefNATRouteInDPN(BigInteger dpnId, long vpnId) {
207 FlowEntity flowEntity = buildDefNATFlowEntity(dpnId, vpnId);
208 if(flowEntity == null) {
209 LOG.error("Flow entity received is NULL. Cannot proceed with installation of Default NAT flow");
212 mdsalManager.removeFlow(flowEntity);