2 * Copyright (c) 2015 Intel, Cisco Systems, Inc. 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
9 package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping;
11 import static com.google.common.base.Preconditions.checkNotNull;
13 import java.util.ArrayList;
14 import java.util.List;
16 import javax.annotation.Nonnull;
17 import javax.annotation.Nullable;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
21 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
22 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.groupbasedpolicy.neutron.mapper.infrastructure.Router;
25 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.rule.NeutronSecurityRuleAware;
26 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
27 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils.ForwardingCtx;
28 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.NeutronMapperIidFactory;
29 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.Utils;
30 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
31 import org.opendaylight.groupbasedpolicy.util.IidFactory;
32 import org.opendaylight.neutron.spi.INeutronPortCRUD;
33 import org.opendaylight.neutron.spi.INeutronRouterAware;
34 import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
35 import org.opendaylight.neutron.spi.NeutronCRUDInterfaces;
36 import org.opendaylight.neutron.spi.NeutronPort;
37 import org.opendaylight.neutron.spi.NeutronRouter;
38 import org.opendaylight.neutron.spi.NeutronRouter_Interface;
39 import org.opendaylight.neutron.spi.NeutronSubnet;
40 import org.opendaylight.neutron.spi.Neutron_IPs;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInputBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3Builder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.network.mappings.NetworkMapping;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomain;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomainBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3ContextBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Subnet;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.SubnetBuilder;
62 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
66 import com.google.common.base.Optional;
67 import com.google.common.base.Strings;
68 import com.google.common.collect.ImmutableList;
70 public class NeutronRouterAware implements INeutronRouterAware {
72 private static final Logger LOG = LoggerFactory.getLogger(NeutronRouterAware.class);
73 private final DataBroker dataProvider;
74 private final EndpointService epService;
75 private final NeutronSecurityRuleAware secRuleAware;
77 public NeutronRouterAware(DataBroker dataProvider, EndpointService epService, NeutronSecurityRuleAware secRuleAware) {
78 this.dataProvider = checkNotNull(dataProvider);
79 this.epService = checkNotNull(epService);
80 this.secRuleAware = checkNotNull(secRuleAware);
84 public int canCreateRouter(NeutronRouter router) {
85 LOG.trace("canCreateRouter - {}", router);
86 // nothing to consider
91 public void neutronRouterCreated(NeutronRouter router) {
92 LOG.trace("neutronRouterCreated - {}", router);
93 // TODO Li msunal external gateway
97 public int canUpdateRouter(NeutronRouter delta, NeutronRouter original) {
98 LOG.trace("canUpdateRouter - delta: {} original: {}", delta, original);
99 // TODO Li msunal external gateway
100 return StatusCode.OK;
104 public void neutronRouterUpdated(NeutronRouter router) {
105 LOG.trace("neutronRouterUpdated - {}", router);
106 if (router.getExternalGatewayInfo() == null || router.getExternalGatewayInfo().getExternalFixedIPs() == null) {
107 LOG.trace("neutronRouterUpdated - not an external Gateway");
111 NeutronCRUDInterfaces neutronCRUDInterface = new NeutronCRUDInterfaces().fetchINeutronPortCRUD(this);
112 INeutronPortCRUD portInterface = neutronCRUDInterface.getPortInterface();
113 if (portInterface == null) {
114 LOG.warn("Illegal state - No provider for {}", INeutronPortCRUD.class.getName());
118 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
119 TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
120 L3ContextId l3ContextIdFromRouterId = new L3ContextId(router.getID());
121 InstanceIdentifier<L3Context> l3ContextIidForRouterId = IidFactory.l3ContextIid(tenantId,
122 l3ContextIdFromRouterId);
123 Optional<L3Context> potentialL3ContextForRouter = DataStoreHelper.readFromDs(
124 LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, rwTx);
125 L3Context l3Context = null;
126 if (potentialL3ContextForRouter.isPresent()) {
127 l3Context = potentialL3ContextForRouter.get();
128 } else { // add L3 context if missing
129 l3Context = createL3ContextFromRouter(router);
130 rwTx.put(LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, l3Context);
133 neutronCRUDInterface = neutronCRUDInterface.fetchINeutronSubnetCRUD(this);
134 INeutronSubnetCRUD subnetInterface = neutronCRUDInterface.getSubnetInterface();
135 if (subnetInterface == null) {
136 LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
139 NeutronSubnet defaultSubnet = subnetInterface.getSubnet(router.getExternalGatewayInfo()
140 .getExternalFixedIPs()
143 IpAddress defaultGateway = null;
144 if (defaultSubnet != null) {
145 defaultGateway = Utils.createIpAddress(defaultSubnet.getGatewayIP());
146 //Create L3Endpoint for defaultGateway and write to externalGateways to L3Endpoints in neutron-gbp datastore
147 NetworkDomainId containment = new NetworkDomainId(defaultSubnet.getID());
148 NeutronPortAware.addL3EndpointForExternalGateway(tenantId, l3Context.getId(), defaultGateway, containment ,rwTx);
150 // Create L3Prefix Endpoints for all routes
151 if (router.getRoutes().isEmpty()) {
152 List<String> defaultRoute = ImmutableList.of("0.0.0.0/0");
153 router.setRoutes(defaultRoute);
156 if (l3ContextIdFromRouterId != null) {
157 for (String route : router.getRoutes()) {
158 IpPrefix ipPrefix = Utils.createIpPrefix(route);
159 boolean addedL3Prefix = NeutronPortAware.addL3PrefixEndpoint(l3ContextIdFromRouterId, ipPrefix,
160 defaultGateway, tenantId, epService);
161 if (!addedL3Prefix) {
162 LOG.warn("Could not add EndpointL3Prefix for Neutron route {} for router {}", route, router.getID());
168 for (Neutron_IPs externalFixedIp : router.getExternalGatewayInfo().getExternalFixedIPs()) {
169 NeutronPort routerPort = portInterface.getPort(router.getGatewayPortId());
170 IpAddress ipAddress = Utils.createIpAddress(routerPort.getFixedIPs().get(0).getIpAddress());
171 // External subnet associated with gateway port should use the gateway IP not router IP.
172 NeutronSubnet neutronSubnet = subnetInterface.getSubnet(externalFixedIp.getSubnetUUID());
173 ipAddress = Utils.createIpAddress(neutronSubnet.getGatewayIP());
174 SubnetId subnetId = new SubnetId(externalFixedIp.getSubnetUUID());
175 Subnet subnet = resolveSubnetWithVirtualRouterIp(tenantId, subnetId, ipAddress, rwTx);
176 if (subnet == null) {
180 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnet.getId()), subnet);
182 if (Strings.isNullOrEmpty(routerPort.getTenantID())) {
183 routerPort.setTenantID(router.getTenantID());
186 boolean isSuccessful = setNewL3ContextToEpsFromSubnet(tenantId, l3Context, subnet, rwTx);
193 DataStoreHelper.submitToDs(rwTx);
197 public int canDeleteRouter(NeutronRouter router) {
198 LOG.trace("canDeleteRouter - {}", router);
199 // nothing to consider
200 return StatusCode.OK;
204 public void neutronRouterDeleted(NeutronRouter router) {
205 LOG.trace("neutronRouterDeleted - {}", router);
206 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
207 TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
208 Optional<EndpointGroup> potentialEpg = DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
209 IidFactory.endpointGroupIid(tenantId, Router.EPG_ID), rwTx);
210 if (!potentialEpg.isPresent()) {
211 LOG.warn("Illegal state - Endpoint group {} does not exist.", Router.EPG_ID.getValue());
215 DataStoreHelper.submitToDs(rwTx);
219 public int canAttachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface) {
220 LOG.trace("canAttachInterface - router: {} interface: {}", router, routerInterface);
221 try (ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction()) {
222 L3ContextId l3ContextIdFromRouterId = new L3ContextId(router.getID());
223 TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
224 SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
225 Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
226 IidFactory.subnetIid(tenantId, subnetId), rTx);
227 if (!potentialSubnet.isPresent()) {
228 LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
229 return StatusCode.NOT_FOUND;
231 Subnet subnet = potentialSubnet.get();
232 L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
233 ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rTx);
234 if (fwCtx.getL3Context() != null && fwCtx.getL3Context().getId().equals(l3ContextIdFromRouterId)) {
236 LOG.warn("Illegal state - Neutron mapper does not support multiple router interfaces in the same subnet yet.");
237 return StatusCode.FORBIDDEN;
239 return StatusCode.OK;
244 public void neutronRouterInterfaceAttached(NeutronRouter router, NeutronRouter_Interface routerInterface) {
245 LOG.trace("neutronRouterInterfaceAttached - router: {} interface: {}", router, routerInterface);
246 NeutronCRUDInterfaces neutronCRUDInterface = new NeutronCRUDInterfaces().fetchINeutronPortCRUD(this);
247 INeutronPortCRUD portInterface = neutronCRUDInterface.getPortInterface();
248 if (portInterface == null) {
249 LOG.warn("Illegal state - No provider for {}", INeutronPortCRUD.class.getName());
253 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
254 TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
255 L3ContextId l3ContextIdFromRouterId = new L3ContextId(router.getID());
256 InstanceIdentifier<L3Context> l3ContextIidForRouterId = IidFactory.l3ContextIid(tenantId,
257 l3ContextIdFromRouterId);
258 Optional<L3Context> potentialL3ContextForRouter = DataStoreHelper.readFromDs(
259 LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, rwTx);
260 L3Context l3Context = null;
261 if (potentialL3ContextForRouter.isPresent()) {
262 l3Context = potentialL3ContextForRouter.get();
263 } else { // add L3 context if missing
264 l3Context = createL3ContextFromRouter(router);
265 rwTx.put(LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, l3Context);
268 // Based on Neutron Northbound - Port representing router interface
269 // contains exactly on fixed IP
270 NeutronPort routerPort = portInterface.getPort(routerInterface.getPortUUID());
271 SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
272 IpAddress ipAddress = Utils.createIpAddress(routerPort.getFixedIPs().get(0).getIpAddress());
273 Subnet subnet = resolveSubnetWithVirtualRouterIp(tenantId, subnetId, ipAddress, rwTx);
274 if (subnet == null) {
278 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnet.getId()), subnet);
280 boolean isSuccessful = setNewL3ContextToEpsFromSubnet(tenantId, l3Context, subnet, rwTx);
286 DataStoreHelper.submitToDs(rwTx);
289 private static @Nonnull L3Context createL3ContextFromRouter(NeutronRouter router) {
290 Name l3ContextName = null;
291 if (!Strings.isNullOrEmpty(router.getName())) {
292 l3ContextName = new Name(router.getName());
294 return new L3ContextBuilder().setId(new L3ContextId(router.getID()))
295 .setName(l3ContextName)
296 .setDescription(new Description(MappingUtils.NEUTRON_ROUTER + router.getID()))
300 private @Nullable Subnet resolveSubnetWithVirtualRouterIp(TenantId tenantId, SubnetId subnetId,
301 IpAddress ipAddress, ReadTransaction rTx) {
302 Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
303 IidFactory.subnetIid(tenantId, subnetId), rTx);
304 if (!potentialSubnet.isPresent()) {
305 LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
309 // TODO: Li alagalah: Add gateways and prefixes instead of
311 return new SubnetBuilder(potentialSubnet.get()).setVirtualRouterIp(ipAddress).build();
315 * @return {@code false} if illegal state occurred; {@code true} otherwise
317 public boolean setNewL3ContextToEpsFromSubnet(TenantId tenantId, L3Context l3Context, Subnet subnet,
318 ReadWriteTransaction rwTx) {
319 if (subnet.getParent() == null) {
320 LOG.warn("Illegal state - subnet {} does not have a parent.", subnet.getId().getValue());
324 L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
325 ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
326 if (fwCtx.getL2BridgeDomain() == null) {
327 LOG.warn("Illegal state - l2-flood-domain {} does not have a parent.", l2FdId.getValue());
331 L2BridgeDomain l2BridgeDomain = new L2BridgeDomainBuilder(fwCtx.getL2BridgeDomain()).setParent(
332 l3Context.getId()).build();
333 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BridgeDomain.getId()),
336 NeutronCRUDInterfaces neutronCRUDInterface = new NeutronCRUDInterfaces().fetchINeutronSubnetCRUD(this);
337 INeutronSubnetCRUD subnetInterface = neutronCRUDInterface.getSubnetInterface();
338 if (subnetInterface == null) {
339 LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
343 List<L3> l3Eps = new ArrayList<>();
344 L3ContextId oldL3ContextId = fwCtx.getL3Context().getId();
345 NeutronSubnet neutronSubnet = subnetInterface.getSubnet(subnet.getId().getValue());
346 List<NeutronPort> portsInNeutronSubnet = neutronSubnet.getPortsInSubnet();
347 for (NeutronPort port : portsInNeutronSubnet) {
348 boolean isPortAdded = NeutronPortAware.addNeutronPort(port, rwTx, epService);
352 // TODO Li msunal this has to be rewrite when OFOverlay renderer
353 // will support l3-endpoints.
354 Neutron_IPs firstIp = MappingUtils.getFirstIp(port.getFixedIPs());
355 if (firstIp != null) {
356 l3Eps.add(new L3Builder().setL3Context(oldL3ContextId)
357 .setIpAddress(Utils.createIpAddress(firstIp.getIpAddress()))
361 if (neutronSubnet.getGatewayIP() != null) {
362 l3Eps.add(new L3Builder().setL3Context(oldL3ContextId)
363 .setIpAddress(Utils.createIpAddress(neutronSubnet.getGatewayIP()))
367 if (!l3Eps.isEmpty()) {
368 epService.unregisterEndpoint(new UnregisterEndpointInputBuilder().setL3(l3Eps).build());
374 public int canDetachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface) {
375 LOG.trace("canDetachInterface - router: {} interface: {}", router, routerInterface);
376 // nothing to consider
377 return StatusCode.OK;
381 public void neutronRouterInterfaceDetached(NeutronRouter router, NeutronRouter_Interface routerInterface) {
382 LOG.trace("neutronRouterInterfaceDetached - router: {} interface: {}", router, routerInterface);
383 NeutronCRUDInterfaces neutronCRUDInterface = new NeutronCRUDInterfaces().fetchINeutronSubnetCRUD(this);
384 INeutronSubnetCRUD subnetInterface = neutronCRUDInterface.getSubnetInterface();
385 if (subnetInterface == null) {
386 LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
390 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
391 TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
392 L3ContextId l3ContextId = new L3ContextId(router.getID());
393 SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
394 InstanceIdentifier<L3Context> l3ContextIid = IidFactory.l3ContextIid(tenantId, l3ContextId);
395 DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
396 IidFactory.l3ContextIid(tenantId, l3ContextId), rwTx);
398 Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
399 IidFactory.subnetIid(tenantId, subnetId), rwTx);
400 if (!potentialSubnet.isPresent()) {
401 LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
406 Subnet subnet = new SubnetBuilder(potentialSubnet.get()).setVirtualRouterIp(null).build();
407 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnetId), subnet);
409 L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
410 ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
411 if (fwCtx.getL2BridgeDomain() == null) {
412 LOG.warn("Illegal state - l2-flood-domain {} does not have a parent.", l2FdId.getValue());
417 Optional<NetworkMapping> potentialNetworkMapping = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
418 NeutronMapperIidFactory.networkMappingIid(l2FdId), rwTx);
419 if (!potentialNetworkMapping.isPresent()) {
420 LOG.warn("Illegal state - network-mapping {} does not exist.", l2FdId.getValue());
425 L2BridgeDomain l2BridgeDomain = new L2BridgeDomainBuilder(fwCtx.getL2BridgeDomain()).setParent(
426 potentialNetworkMapping.get().getL3ContextId()).build();
427 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BridgeDomain.getId()),
430 NeutronSubnet neutronSubnet = subnetInterface.getSubnet(subnetId.getValue());
431 List<NeutronPort> portsInNeutronSubnet = neutronSubnet.getPortsInSubnet();
432 for (NeutronPort port : portsInNeutronSubnet) {
433 boolean isPortAdded = NeutronPortAware.addNeutronPort(port, rwTx, epService);