1 package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping;
3 import static com.google.common.base.Preconditions.checkNotNull;
5 import java.util.ArrayList;
8 import javax.annotation.Nonnull;
9 import javax.annotation.Nullable;
11 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
12 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
13 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
14 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
15 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
16 import org.opendaylight.groupbasedpolicy.neutron.mapper.infrastructure.Router;
17 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.rule.NeutronSecurityRuleAware;
18 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
19 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils.ForwardingCtx;
20 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.NeutronMapperIidFactory;
21 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.Utils;
22 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
23 import org.opendaylight.groupbasedpolicy.util.IidFactory;
24 import org.opendaylight.neutron.spi.INeutronPortCRUD;
25 import org.opendaylight.neutron.spi.INeutronRouterAware;
26 import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
27 import org.opendaylight.neutron.spi.NeutronCRUDInterfaces;
28 import org.opendaylight.neutron.spi.NeutronPort;
29 import org.opendaylight.neutron.spi.NeutronRouter;
30 import org.opendaylight.neutron.spi.NeutronRouter_Interface;
31 import org.opendaylight.neutron.spi.NeutronSubnet;
32 import org.opendaylight.neutron.spi.Neutron_IPs;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInputBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3Builder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.network.mappings.NetworkMapping;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomain;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomainBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3ContextBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Subnet;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.SubnetBuilder;
54 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
58 import com.google.common.base.Optional;
59 import com.google.common.base.Strings;
60 import com.google.common.collect.ImmutableList;
62 public class NeutronRouterAware implements INeutronRouterAware {
64 private static final Logger LOG = LoggerFactory.getLogger(NeutronRouterAware.class);
65 private final DataBroker dataProvider;
66 private final EndpointService epService;
67 private final NeutronSecurityRuleAware secRuleAware;
69 public NeutronRouterAware(DataBroker dataProvider, EndpointService epService, NeutronSecurityRuleAware secRuleAware) {
70 this.dataProvider = checkNotNull(dataProvider);
71 this.epService = checkNotNull(epService);
72 this.secRuleAware = checkNotNull(secRuleAware);
76 public int canCreateRouter(NeutronRouter router) {
77 LOG.trace("canCreateRouter - {}", router);
78 // nothing to consider
83 public void neutronRouterCreated(NeutronRouter router) {
84 LOG.trace("neutronRouterCreated - {}", router);
85 // TODO Li msunal external gateway
89 public int canUpdateRouter(NeutronRouter delta, NeutronRouter original) {
90 LOG.trace("canUpdateRouter - delta: {} original: {}", delta, original);
91 // TODO Li msunal external gateway
96 public void neutronRouterUpdated(NeutronRouter router) {
97 LOG.trace("neutronRouterUpdated - {}", router);
98 if (router.getExternalGatewayInfo() == null || router.getExternalGatewayInfo().getExternalFixedIPs() == null) {
99 LOG.trace("neutronRouterUpdated - not an external Gateway");
103 NeutronCRUDInterfaces neutronCRUDInterface = new NeutronCRUDInterfaces().fetchINeutronPortCRUD(this);
104 INeutronPortCRUD portInterface = neutronCRUDInterface.getPortInterface();
105 if (portInterface == null) {
106 LOG.warn("Illegal state - No provider for {}", INeutronPortCRUD.class.getName());
110 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
111 TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
112 L3ContextId l3ContextIdFromRouterId = new L3ContextId(router.getID());
113 InstanceIdentifier<L3Context> l3ContextIidForRouterId = IidFactory.l3ContextIid(tenantId,
114 l3ContextIdFromRouterId);
115 Optional<L3Context> potentialL3ContextForRouter = DataStoreHelper.readFromDs(
116 LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, rwTx);
117 L3Context l3Context = null;
118 if (potentialL3ContextForRouter.isPresent()) {
119 l3Context = potentialL3ContextForRouter.get();
120 } else { // add L3 context if missing
121 l3Context = createL3ContextFromRouter(router);
122 rwTx.put(LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, l3Context);
125 neutronCRUDInterface = neutronCRUDInterface.fetchINeutronSubnetCRUD(this);
126 INeutronSubnetCRUD subnetInterface = neutronCRUDInterface.getSubnetInterface();
127 if (subnetInterface == null) {
128 LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
131 NeutronSubnet defaultSubnet = subnetInterface.getSubnet(router.getExternalGatewayInfo()
132 .getExternalFixedIPs()
135 IpAddress defaultGateway = null;
136 if (defaultSubnet != null) {
137 defaultGateway = Utils.createIpAddress(defaultSubnet.getGatewayIP());
138 //Create L3Endpoint for defaultGateway and write to externalGateways to L3Endpoints in neutron-gbp datastore
139 NetworkDomainId containment = new NetworkDomainId(defaultSubnet.getID());
140 NeutronPortAware.addL3EndpointForExternalGateway(tenantId, l3Context.getId(), defaultGateway, containment ,rwTx);
142 // Create L3Prefix Endpoints for all routes
143 if (router.getRoutes().isEmpty()) {
144 List<String> defaultRoute = ImmutableList.of("0.0.0.0/0");
145 router.setRoutes(defaultRoute);
148 if (l3ContextIdFromRouterId != null) {
149 for (String route : router.getRoutes()) {
150 IpPrefix ipPrefix = Utils.createIpPrefix(route);
151 boolean addedL3Prefix = NeutronPortAware.addL3PrefixEndpoint(l3ContextIdFromRouterId, ipPrefix,
152 defaultGateway, tenantId, epService);
153 if (!addedL3Prefix) {
154 LOG.warn("Could not add EndpointL3Prefix for Neutron route {} for router {}", route, router.getID());
160 for (Neutron_IPs externalFixedIp : router.getExternalGatewayInfo().getExternalFixedIPs()) {
161 NeutronPort routerPort = portInterface.getPort(router.getGatewayPortId());
162 IpAddress ipAddress = Utils.createIpAddress(routerPort.getFixedIPs().get(0).getIpAddress());
163 // External subnet associated with gateway port should use the gateway IP not router IP.
164 NeutronSubnet neutronSubnet = subnetInterface.getSubnet(externalFixedIp.getSubnetUUID());
165 ipAddress = Utils.createIpAddress(neutronSubnet.getGatewayIP());
166 SubnetId subnetId = new SubnetId(externalFixedIp.getSubnetUUID());
167 Subnet subnet = resolveSubnetWithVirtualRouterIp(tenantId, subnetId, ipAddress, rwTx);
168 if (subnet == null) {
172 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnet.getId()), subnet);
174 if (Strings.isNullOrEmpty(routerPort.getTenantID())) {
175 routerPort.setTenantID(router.getTenantID());
178 boolean isSuccessful = setNewL3ContextToEpsFromSubnet(tenantId, l3Context, subnet, rwTx);
185 DataStoreHelper.submitToDs(rwTx);
189 public int canDeleteRouter(NeutronRouter router) {
190 LOG.trace("canDeleteRouter - {}", router);
191 // nothing to consider
192 return StatusCode.OK;
196 public void neutronRouterDeleted(NeutronRouter router) {
197 LOG.trace("neutronRouterDeleted - {}", router);
198 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
199 TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
200 Optional<EndpointGroup> potentialEpg = DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
201 IidFactory.endpointGroupIid(tenantId, Router.EPG_ID), rwTx);
202 if (!potentialEpg.isPresent()) {
203 LOG.warn("Illegal state - Endpoint group {} does not exist.", Router.EPG_ID.getValue());
207 DataStoreHelper.submitToDs(rwTx);
211 public int canAttachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface) {
212 LOG.trace("canAttachInterface - router: {} interface: {}", router, routerInterface);
213 try (ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction()) {
214 L3ContextId l3ContextIdFromRouterId = new L3ContextId(router.getID());
215 TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
216 SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
217 Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
218 IidFactory.subnetIid(tenantId, subnetId), rTx);
219 if (!potentialSubnet.isPresent()) {
220 LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
221 return StatusCode.NOT_FOUND;
223 Subnet subnet = potentialSubnet.get();
224 L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
225 ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rTx);
226 if (fwCtx.getL3Context() != null && fwCtx.getL3Context().getId().equals(l3ContextIdFromRouterId)) {
228 LOG.warn("Illegal state - Neutron mapper does not support multiple router interfaces in the same subnet yet.");
229 return StatusCode.FORBIDDEN;
231 return StatusCode.OK;
236 public void neutronRouterInterfaceAttached(NeutronRouter router, NeutronRouter_Interface routerInterface) {
237 LOG.trace("neutronRouterInterfaceAttached - router: {} interface: {}", router, routerInterface);
238 NeutronCRUDInterfaces neutronCRUDInterface = new NeutronCRUDInterfaces().fetchINeutronPortCRUD(this);
239 INeutronPortCRUD portInterface = neutronCRUDInterface.getPortInterface();
240 if (portInterface == null) {
241 LOG.warn("Illegal state - No provider for {}", INeutronPortCRUD.class.getName());
245 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
246 TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
247 L3ContextId l3ContextIdFromRouterId = new L3ContextId(router.getID());
248 InstanceIdentifier<L3Context> l3ContextIidForRouterId = IidFactory.l3ContextIid(tenantId,
249 l3ContextIdFromRouterId);
250 Optional<L3Context> potentialL3ContextForRouter = DataStoreHelper.readFromDs(
251 LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, rwTx);
252 L3Context l3Context = null;
253 if (potentialL3ContextForRouter.isPresent()) {
254 l3Context = potentialL3ContextForRouter.get();
255 } else { // add L3 context if missing
256 l3Context = createL3ContextFromRouter(router);
257 rwTx.put(LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, l3Context);
260 // Based on Neutron Northbound - Port representing router interface
261 // contains exactly on fixed IP
262 NeutronPort routerPort = portInterface.getPort(routerInterface.getPortUUID());
263 SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
264 IpAddress ipAddress = Utils.createIpAddress(routerPort.getFixedIPs().get(0).getIpAddress());
265 Subnet subnet = resolveSubnetWithVirtualRouterIp(tenantId, subnetId, ipAddress, rwTx);
266 if (subnet == null) {
270 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnet.getId()), subnet);
272 boolean isSuccessful = setNewL3ContextToEpsFromSubnet(tenantId, l3Context, subnet, rwTx);
278 DataStoreHelper.submitToDs(rwTx);
281 private static @Nonnull L3Context createL3ContextFromRouter(NeutronRouter router) {
282 Name l3ContextName = null;
283 if (!Strings.isNullOrEmpty(router.getName())) {
284 l3ContextName = new Name(router.getName());
286 return new L3ContextBuilder().setId(new L3ContextId(router.getID()))
287 .setName(l3ContextName)
288 .setDescription(new Description(MappingUtils.NEUTRON_ROUTER + router.getID()))
292 private @Nullable Subnet resolveSubnetWithVirtualRouterIp(TenantId tenantId, SubnetId subnetId,
293 IpAddress ipAddress, ReadTransaction rTx) {
294 Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
295 IidFactory.subnetIid(tenantId, subnetId), rTx);
296 if (!potentialSubnet.isPresent()) {
297 LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
301 // TODO: Li alagalah: Add gateways and prefixes instead of
303 return new SubnetBuilder(potentialSubnet.get()).setVirtualRouterIp(ipAddress).build();
307 * @return {@code false} if illegal state occurred; {@code true} otherwise
309 public boolean setNewL3ContextToEpsFromSubnet(TenantId tenantId, L3Context l3Context, Subnet subnet,
310 ReadWriteTransaction rwTx) {
311 if (subnet.getParent() == null) {
312 LOG.warn("Illegal state - subnet {} does not have a parent.", subnet.getId().getValue());
316 L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
317 ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
318 if (fwCtx.getL2BridgeDomain() == null) {
319 LOG.warn("Illegal state - l2-flood-domain {} does not have a parent.", l2FdId.getValue());
323 L2BridgeDomain l2BridgeDomain = new L2BridgeDomainBuilder(fwCtx.getL2BridgeDomain()).setParent(
324 l3Context.getId()).build();
325 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BridgeDomain.getId()),
328 NeutronCRUDInterfaces neutronCRUDInterface = new NeutronCRUDInterfaces().fetchINeutronSubnetCRUD(this);
329 INeutronSubnetCRUD subnetInterface = neutronCRUDInterface.getSubnetInterface();
330 if (subnetInterface == null) {
331 LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
335 List<L3> l3Eps = new ArrayList<>();
336 L3ContextId oldL3ContextId = fwCtx.getL3Context().getId();
337 NeutronSubnet neutronSubnet = subnetInterface.getSubnet(subnet.getId().getValue());
338 List<NeutronPort> portsInNeutronSubnet = neutronSubnet.getPortsInSubnet();
339 for (NeutronPort port : portsInNeutronSubnet) {
340 boolean isPortAdded = NeutronPortAware.addNeutronPort(port, rwTx, epService);
344 // TODO Li msunal this has to be rewrite when OFOverlay renderer
345 // will support l3-endpoints.
346 Neutron_IPs firstIp = MappingUtils.getFirstIp(port.getFixedIPs());
347 if (firstIp != null) {
348 l3Eps.add(new L3Builder().setL3Context(oldL3ContextId)
349 .setIpAddress(Utils.createIpAddress(firstIp.getIpAddress()))
353 if (neutronSubnet.getGatewayIP() != null) {
354 l3Eps.add(new L3Builder().setL3Context(oldL3ContextId)
355 .setIpAddress(Utils.createIpAddress(neutronSubnet.getGatewayIP()))
359 if (!l3Eps.isEmpty()) {
360 epService.unregisterEndpoint(new UnregisterEndpointInputBuilder().setL3(l3Eps).build());
366 public int canDetachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface) {
367 LOG.trace("canDetachInterface - router: {} interface: {}", router, routerInterface);
368 // nothing to consider
369 return StatusCode.OK;
373 public void neutronRouterInterfaceDetached(NeutronRouter router, NeutronRouter_Interface routerInterface) {
374 LOG.trace("neutronRouterInterfaceDetached - router: {} interface: {}", router, routerInterface);
375 NeutronCRUDInterfaces neutronCRUDInterface = new NeutronCRUDInterfaces().fetchINeutronSubnetCRUD(this);
376 INeutronSubnetCRUD subnetInterface = neutronCRUDInterface.getSubnetInterface();
377 if (subnetInterface == null) {
378 LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
382 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
383 TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
384 L3ContextId l3ContextId = new L3ContextId(router.getID());
385 SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
386 InstanceIdentifier<L3Context> l3ContextIid = IidFactory.l3ContextIid(tenantId, l3ContextId);
387 DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
388 IidFactory.l3ContextIid(tenantId, l3ContextId), rwTx);
390 Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
391 IidFactory.subnetIid(tenantId, subnetId), rwTx);
392 if (!potentialSubnet.isPresent()) {
393 LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
398 Subnet subnet = new SubnetBuilder(potentialSubnet.get()).setVirtualRouterIp(null).build();
399 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnetId), subnet);
401 L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
402 ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
403 if (fwCtx.getL2BridgeDomain() == null) {
404 LOG.warn("Illegal state - l2-flood-domain {} does not have a parent.", l2FdId.getValue());
409 Optional<NetworkMapping> potentialNetworkMapping = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
410 NeutronMapperIidFactory.networkMappingIid(l2FdId), rwTx);
411 if (!potentialNetworkMapping.isPresent()) {
412 LOG.warn("Illegal state - network-mapping {} does not exist.", l2FdId.getValue());
417 L2BridgeDomain l2BridgeDomain = new L2BridgeDomainBuilder(fwCtx.getL2BridgeDomain()).setParent(
418 potentialNetworkMapping.get().getL3ContextId()).build();
419 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BridgeDomain.getId()),
422 NeutronSubnet neutronSubnet = subnetInterface.getSubnet(subnetId.getValue());
423 List<NeutronPort> portsInNeutronSubnet = neutronSubnet.getPortsInSubnet();
424 for (NeutronPort port : portsInNeutronSubnet) {
425 boolean isPortAdded = NeutronPortAware.addNeutronPort(port, rwTx, epService);