2 * Copyright © 2016, 2017 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.neutronvpn;
10 import com.google.common.base.Optional;
11 import java.util.ArrayList;
12 import java.util.HashMap;
13 import java.util.List;
14 import javax.annotation.PostConstruct;
15 import javax.inject.Inject;
16 import javax.inject.Singleton;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
20 import org.opendaylight.genius.mdsalutil.NwConstants;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.l3.attributes.Routes;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.Routers;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.router.external_gateway_info.ExternalFixedIps;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
29 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
34 public class NeutronRouterChangeListener extends AsyncDataTreeChangeListenerBase<Router, NeutronRouterChangeListener> {
35 private static final Logger LOG = LoggerFactory.getLogger(NeutronRouterChangeListener.class);
36 private final DataBroker dataBroker;
37 private final NeutronvpnManager nvpnManager;
38 private final NeutronvpnNatManager nvpnNatManager;
39 private final NeutronSubnetGwMacResolver gwMacResolver;
40 private final NeutronvpnUtils neutronvpnUtils;
43 public NeutronRouterChangeListener(final DataBroker dataBroker, final NeutronvpnManager neutronvpnManager,
44 final NeutronvpnNatManager neutronvpnNatManager,
45 final NeutronSubnetGwMacResolver gwMacResolver,
46 final NeutronvpnUtils neutronvpnUtils) {
47 super(Router.class, NeutronRouterChangeListener.class);
48 this.dataBroker = dataBroker;
49 nvpnManager = neutronvpnManager;
50 nvpnNatManager = neutronvpnNatManager;
51 this.gwMacResolver = gwMacResolver;
52 this.neutronvpnUtils = neutronvpnUtils;
58 LOG.info("{} init", getClass().getSimpleName());
59 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
63 protected InstanceIdentifier<Router> getWildCardPath() {
64 return InstanceIdentifier.create(Neutron.class).child(Routers.class).child(Router.class);
68 protected NeutronRouterChangeListener getDataTreeChangeListener() {
69 return NeutronRouterChangeListener.this;
74 protected void add(InstanceIdentifier<Router> identifier, Router input) {
75 LOG.trace("Adding Router : key: {}, value={}", identifier, input);
76 neutronvpnUtils.addToRouterCache(input);
77 // Create internal VPN
78 nvpnManager.createL3InternalVpn(input.getUuid(), null, null, null, null, null, input.getUuid(), null);
79 nvpnNatManager.handleExternalNetworkForRouter(null, input);
80 gwMacResolver.sendArpRequestsToExtGateways(input);
84 protected void remove(InstanceIdentifier<Router> identifier, Router input) {
85 LOG.trace("Removing router : key: {}, value={}", identifier, input);
86 Uuid routerId = input.getUuid();
87 // Handle router deletion for the NAT service
88 /*External Router and networks is handled before deleting the internal VPN, as there is dependency
89 on vpn operational data to release Lport tag in case of L3VPN over VxLAN*/
90 if (input.getExternalGatewayInfo() != null) {
91 Uuid extNetId = input.getExternalGatewayInfo().getExternalNetworkId();
92 List<ExternalFixedIps> externalFixedIps = input.getExternalGatewayInfo().getExternalFixedIps();
93 nvpnNatManager.removeExternalNetworkFromRouter(extNetId, input, externalFixedIps);
95 //NOTE: Pass an empty routerSubnetIds list, as router interfaces
96 //will be removed from VPN by invocations from NeutronPortChangeListener
97 List<Uuid> routerSubnetIds = new ArrayList<>();
98 nvpnManager.handleNeutronRouterDeleted(routerId, routerSubnetIds);
100 neutronvpnUtils.removeFromRouterCache(input);
104 protected void update(InstanceIdentifier<Router> identifier, Router original, Router update) {
105 LOG.trace("Updating Router : key: {}, original value={}, update value={}", identifier, original, update);
106 neutronvpnUtils.addToRouterCache(update);
107 Uuid routerId = update.getUuid();
108 neutronvpnUtils.addToRouterCache(update);
109 Uuid vpnId = neutronvpnUtils.getVpnForRouter(routerId, true);
110 // internal vpn always present in case external vpn not found
114 List<Routes> oldRoutes = original.getRoutes() != null ? original.getRoutes() : new ArrayList<>();
115 List<Routes> newRoutes = update.getRoutes() != null ? update.getRoutes() : new ArrayList<>();
116 if (!oldRoutes.equals(newRoutes)) {
117 newRoutes.removeIf(oldRoutes::remove);
119 handleChangedRoutes(vpnId, newRoutes, NwConstants.ADD_FLOW);
121 if (!oldRoutes.isEmpty()) {
122 handleChangedRoutes(vpnId, oldRoutes, NwConstants.DEL_FLOW);
126 nvpnNatManager.handleExternalNetworkForRouter(original, update);
127 gwMacResolver.sendArpRequestsToExtGateways(update);
130 private void handleChangedRoutes(Uuid vpnName, List<Routes> routes, int addedOrRemoved) {
131 // Some routes may point to an InterVpnLink's endpoint, lets treat them differently
132 List<Routes> interVpnLinkRoutes = new ArrayList<>();
133 List<Routes> otherRoutes = new ArrayList<>();
134 HashMap<String, InterVpnLink> nexthopsXinterVpnLinks = new HashMap<>();
135 for (Routes route : routes) {
136 String nextHop = String.valueOf(route.getNexthop().getValue());
137 // Nexthop is another VPN?
138 Optional<InterVpnLink> interVpnLink = neutronvpnUtils.getInterVpnLinkByEndpointIp(nextHop);
139 if (interVpnLink.isPresent()) {
140 Optional<InterVpnLinkState> interVpnLinkState =
141 neutronvpnUtils.getInterVpnLinkState(interVpnLink.get().getName());
142 if (interVpnLinkState.isPresent() && interVpnLinkState.get().getState()
143 == InterVpnLinkState.State.Active) {
144 interVpnLinkRoutes.add(route);
145 nexthopsXinterVpnLinks.put(nextHop, interVpnLink.get());
147 LOG.error("Failed installing route to {}. Reason: InterVPNLink {} is not Active",
148 String.valueOf(route.getDestination().getValue()), interVpnLink.get().getName());
151 otherRoutes.add(route);
155 if (addedOrRemoved == NwConstants.ADD_FLOW) {
156 nvpnManager.addInterVpnRoutes(vpnName, interVpnLinkRoutes, nexthopsXinterVpnLinks);
157 nvpnManager.updateVpnInterfaceWithExtraRouteAdjacency(vpnName, otherRoutes);
159 nvpnManager.removeAdjacencyforExtraRoute(vpnName, otherRoutes);
160 nvpnManager.removeInterVpnRoutes(vpnName, interVpnLinkRoutes, nexthopsXinterVpnLinks);