7da088ec9ce091627c9803b72c08ea0781d8f44a
[groupbasedpolicy.git] / neutron-mapper / src / main / java / org / opendaylight / groupbasedpolicy / neutron / mapper / mapping / NeutronRouterAware.java
1 /*
2  * Copyright (c) 2015 Intel, Cisco Systems, Inc. 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
9 package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping;
10
11 import static com.google.common.base.Preconditions.checkNotNull;
12
13 import java.util.List;
14 import java.util.concurrent.ExecutionException;
15
16 import javax.annotation.Nonnull;
17
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
22 import org.opendaylight.groupbasedpolicy.neutron.gbp.util.NeutronGbpIidFactory;
23 import org.opendaylight.groupbasedpolicy.neutron.mapper.EndpointRegistrator;
24 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
25 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.PortUtils;
26 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.SubnetUtils;
27 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
28 import org.opendaylight.groupbasedpolicy.util.IidFactory;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
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.groupbasedpolicy.common.rev140421.Description;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Key;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.external.gateways.as.l3.endpoints.ExternalGatewayAsL3Endpoint;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.TenantBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.ForwardingContext;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2BridgeDomain;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2BridgeDomainBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2FloodDomain;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L3Context;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L3ContextBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.SubnetBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.Routers;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
54 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58 import com.google.common.base.Optional;
59 import com.google.common.base.Strings;
60
61 public class NeutronRouterAware implements NeutronAware<Router> {
62
63     private static final Logger LOG = LoggerFactory.getLogger(NeutronRouterAware.class);
64     public static final InstanceIdentifier<Router> ROUTER_WILDCARD_IID =
65             InstanceIdentifier.builder(Neutron.class).child(Routers.class).child(Router.class).build();
66     private final DataBroker dataProvider;
67     private final EndpointRegistrator epRegistrator;
68
69     public NeutronRouterAware(DataBroker dataProvider, EndpointRegistrator epRegistrator) {
70         this.dataProvider = checkNotNull(dataProvider);
71         this.epRegistrator = checkNotNull(epRegistrator);
72     }
73
74     @Override
75     public void onCreated(Router router, Neutron neutron) {
76         LOG.trace("created router - {}", router);
77     }
78
79     @Override
80     public void onUpdated(Router oldRouter, Router newRouter, Neutron oldNeutron, Neutron newNeutron) {
81         LOG.trace("updated router - OLD: {}\nNEW: {}", oldRouter, newRouter);
82
83         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
84         TenantId tenantId = new TenantId(newRouter.getTenantId().getValue());
85         L3ContextId l3ContextIdFromRouterId = new L3ContextId(newRouter.getUuid().getValue());
86         InstanceIdentifier<L3Context> l3ContextIidForRouterId =
87                 IidFactory.l3ContextIid(tenantId, l3ContextIdFromRouterId);
88         Optional<L3Context> potentialL3ContextForRouter =
89                 DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, rwTx);
90         L3Context l3Context = null;
91         if (potentialL3ContextForRouter.isPresent()) {
92             l3Context = potentialL3ContextForRouter.get();
93         } else { // add L3 context if missing
94             l3Context = createL3ContextFromRouter(newRouter);
95             rwTx.put(LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, l3Context);
96         }
97
98         if (newRouter.getGatewayPortId() != null && oldRouter.getGatewayPortId() == null) {
99             // external network is attached to router
100             Uuid gatewayPortId = newRouter.getGatewayPortId();
101             Optional<Port> potentialGwPort = PortUtils.findPort(gatewayPortId, newNeutron.getPorts());
102             if (!potentialGwPort.isPresent()) {
103                 LOG.warn("Illegal state - router gateway port {} does not exist for router {}.",
104                         gatewayPortId.getValue(), newRouter);
105                 rwTx.cancel();
106                 return;
107             }
108
109             Port gwPort = potentialGwPort.get();
110             List<FixedIps> fixedIpsFromGwPort = gwPort.getFixedIps();
111             if (fixedIpsFromGwPort == null || fixedIpsFromGwPort.isEmpty()) {
112                 LOG.warn("Illegal state - router gateway port {} does not contain fixed IPs {}",
113                         gatewayPortId.getValue(), gwPort);
114                 rwTx.cancel();
115                 return;
116             }
117
118             // router can have only one external network
119             FixedIps ipWithSubnetFromGwPort = fixedIpsFromGwPort.get(0);
120             Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet> potentialSubnet = SubnetUtils.findSubnet(ipWithSubnetFromGwPort.getSubnetId(), newNeutron.getSubnets());
121             if (!potentialSubnet.isPresent()) {
122                 LOG.warn("Illegal state - Subnet {} does not exist for router {}.",
123                         ipWithSubnetFromGwPort.getSubnetId(), newRouter);
124                 rwTx.cancel();
125                 return;
126             }
127             IpAddress gatewayIp =  potentialSubnet.get().getGatewayIp();
128             boolean registeredExternalGateway = epRegistrator.registerL3EndpointAsExternalGateway(tenantId, gatewayIp,
129                     l3ContextIdFromRouterId, new NetworkDomainId(ipWithSubnetFromGwPort.getSubnetId().getValue()));
130             if (!registeredExternalGateway) {
131                 LOG.warn("Could not add L3Prefix as gateway of default route. Gateway port {}", gwPort);
132                 rwTx.cancel();
133                 return;
134             }
135             EndpointL3Key epL3Key = new EndpointL3Key(gatewayIp, l3ContextIdFromRouterId);
136             addNeutronExtGwGbpMapping(epL3Key, rwTx);
137
138             boolean registeredDefaultRoute = epRegistrator.registerExternalL3PrefixEndpoint(MappingUtils.DEFAULT_ROUTE,
139                     l3ContextIdFromRouterId, gatewayIp, tenantId);
140             if (!registeredDefaultRoute) {
141                 LOG.warn("Could not add EndpointL3Prefix as default route. Gateway port {}", gwPort);
142                 rwTx.cancel();
143                 return;
144             }
145             Subnet subnetWithGw =
146                     new SubnetBuilder().setId(new SubnetId(ipWithSubnetFromGwPort.getSubnetId().getValue()))
147                         .setVirtualRouterIp(gatewayIp)
148                 .build();
149             rwTx.merge(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnetWithGw.getId()),
150                     subnetWithGw);
151             L2BridgeDomainId l2BdId = new L2BridgeDomainId(potentialSubnet.get().getNetworkId().getValue());
152             Optional<L2BridgeDomain> optBd = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
153                     IidFactory.l2BridgeDomainIid(tenantId, l2BdId), rwTx);
154             if (!optBd.isPresent()) {
155                 LOG.warn(
156                         "Could not read L2-Bridge-Domain {} Modifiaction of it's parent to L3-Context of router {} aborted.",
157                         l2BdId, newRouter.getUuid());
158                 rwTx.cancel();
159                 return;
160             }
161             L2BridgeDomain l2BdWithGw = new L2BridgeDomainBuilder(optBd.get())
162                 .setParent(new L3ContextId(l3ContextIdFromRouterId.getValue()))
163                 .build();
164             rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BdId),
165                     l2BdWithGw);
166         }
167         DataStoreHelper.submitToDs(rwTx);
168     }
169
170     private static @Nonnull L3Context createL3ContextFromRouter(Router router) {
171         Name l3ContextName = null;
172         if (!Strings.isNullOrEmpty(router.getName())) {
173             l3ContextName = new Name(router.getName());
174         }
175         return new L3ContextBuilder().setId(new L3ContextId(router.getUuid().getValue()))
176             .setName(l3ContextName)
177             .setDescription(new Description(MappingUtils.NEUTRON_ROUTER + router.getUuid().getValue()))
178             .build();
179     }
180
181     private static void addNeutronExtGwGbpMapping(EndpointL3Key epL3Key, ReadWriteTransaction rwTx) {
182         ExternalGatewayAsL3Endpoint externalGatewayL3Endpoint =
183                 MappingFactory.createExternalGatewayByL3Endpoint(epL3Key);
184         rwTx.put(LogicalDatastoreType.OPERATIONAL,
185                 NeutronGbpIidFactory.externalGatewayAsL3Endpoint(epL3Key.getL3Context(), epL3Key.getIpAddress()),
186                 externalGatewayL3Endpoint, true);
187     }
188
189     @Override
190     public void onDeleted(Router router, Neutron oldNeutron, Neutron newNeutron) {
191         LOG.trace("deleted router - {}", router);
192     }
193
194 }