Bug 3988 - Jenkins Build failing due to Changes is NeutronCRUDInterfaces
[groupbasedpolicy.git] / neutron-mapper / src / main / java / org / opendaylight / groupbasedpolicy / neutron / mapper / mapping / NeutronRouterAware.java
1 package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping;
2
3 import static com.google.common.base.Preconditions.checkNotNull;
4
5 import java.util.ArrayList;
6 import java.util.List;
7
8 import javax.annotation.Nonnull;
9 import javax.annotation.Nullable;
10
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.util.MappingUtils;
17 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils.ForwardingCtx;
18 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.NeutronMapperIidFactory;
19 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.NeutronUtils;
20 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.Utils;
21 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
22 import org.opendaylight.groupbasedpolicy.util.IidFactory;
23 import org.opendaylight.neutron.spi.INeutronPortCRUD;
24 import org.opendaylight.neutron.spi.INeutronRouterAware;
25 import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
26 import org.opendaylight.neutron.spi.NeutronCRUDInterfaces;
27 import org.opendaylight.neutron.spi.NeutronPort;
28 import org.opendaylight.neutron.spi.NeutronRouter;
29 import org.opendaylight.neutron.spi.NeutronRouter_Interface;
30 import org.opendaylight.neutron.spi.NeutronSecurityRule;
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.EndpointGroupId;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInputBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3Builder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.network.mappings.NetworkMapping;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomain;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomainBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3ContextBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Subnet;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.SubnetBuilder;
55 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59 import com.google.common.base.Optional;
60 import com.google.common.base.Strings;
61 import com.google.common.collect.ImmutableList;
62
63 public class NeutronRouterAware implements INeutronRouterAware {
64
65     private static final Logger LOG = LoggerFactory.getLogger(NeutronRouterAware.class);
66     private static final NeutronRouterAware INSTANCE = new NeutronRouterAware();
67     private static DataBroker dataProvider;
68     private static EndpointService epService;
69
70     private NeutronRouterAware() {
71         if (NeutronRouterAware.INSTANCE != null) {
72             throw new IllegalStateException("Already instantiated");
73         }
74     }
75
76     public static NeutronRouterAware getInstance() {
77         return NeutronRouterAware.INSTANCE;
78     }
79
80     public static void init(DataBroker dataProvider, EndpointService epService) {
81         NeutronRouterAware.dataProvider = checkNotNull(dataProvider);
82         NeutronRouterAware.epService = checkNotNull(epService);
83     }
84
85     @Override
86     public int canCreateRouter(NeutronRouter router) {
87         LOG.trace("canCreateRouter - {}", router);
88         // nothing to consider
89         return StatusCode.OK;
90     }
91
92     @Override
93     public void neutronRouterCreated(NeutronRouter router) {
94         LOG.trace("neutronRouterCreated - {}", router);
95         // TODO Li msunal external gateway
96     }
97
98     @Override
99     public int canUpdateRouter(NeutronRouter delta, NeutronRouter original) {
100         LOG.trace("canUpdateRouter - delta: {} original: {}", delta, original);
101         // TODO Li msunal external gateway
102         return StatusCode.OK;
103     }
104
105     @Override
106     public void neutronRouterUpdated(NeutronRouter router) {
107         LOG.trace("neutronRouterUpdated - {}", router);
108         if (router.getExternalGatewayInfo() == null || router.getExternalGatewayInfo().getExternalFixedIPs() == null) {
109             LOG.trace("neutronRouterUpdated - not an external Gateway");
110             return;
111         }
112
113         NeutronCRUDInterfaces neutronCRUDInterface = new NeutronCRUDInterfaces().fetchINeutronPortCRUD(this);
114         INeutronPortCRUD portInterface = neutronCRUDInterface.getPortInterface();
115         if (portInterface == null) {
116             LOG.warn("Illegal state - No provider for {}", INeutronPortCRUD.class.getName());
117             return;
118         }
119
120         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
121         TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
122         L3ContextId l3ContextIdFromRouterId = new L3ContextId(router.getID());
123         InstanceIdentifier<L3Context> l3ContextIidForRouterId = IidFactory.l3ContextIid(tenantId,
124                 l3ContextIdFromRouterId);
125         Optional<L3Context> potentialL3ContextForRouter = DataStoreHelper.readFromDs(
126                 LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, rwTx);
127         L3Context l3Context = null;
128         if (potentialL3ContextForRouter.isPresent()) {
129             l3Context = potentialL3ContextForRouter.get();
130         } else { // add L3 context if missing
131             l3Context = createL3ContextFromRouter(router);
132             rwTx.put(LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, l3Context);
133         }
134
135         neutronCRUDInterface = neutronCRUDInterface.fetchINeutronSubnetCRUD(this);
136         INeutronSubnetCRUD subnetInterface = neutronCRUDInterface.getSubnetInterface();
137         if (subnetInterface == null) {
138             LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
139             return;
140         }
141         NeutronSubnet defaultSubnet = subnetInterface.getSubnet(router.getExternalGatewayInfo()
142             .getExternalFixedIPs()
143             .get(0)
144             .getSubnetUUID());
145         IpAddress defaultGateway = null;
146         if (defaultSubnet != null) {
147             defaultGateway = Utils.createIpAddress(defaultSubnet.getGatewayIP());
148             //Create L3Endpoint for defaultGateway and write to externalGateways to L3Endpoints in neutron-gbp datastore
149             NetworkDomainId containment = new NetworkDomainId(defaultSubnet.getID());
150             NeutronPortAware.addL3EndpointForExternalGateway(tenantId, l3Context.getId(), defaultGateway, containment ,rwTx);
151         }
152         // Create L3Prefix Endpoints for all routes
153         if (router.getRoutes().isEmpty()) {
154             List<String> defaultRoute = ImmutableList.of("0.0.0.0/0");
155             router.setRoutes(defaultRoute);
156
157         }
158         if (l3ContextIdFromRouterId != null) {
159             for (String route : router.getRoutes()) {
160                 IpPrefix ipPrefix = Utils.createIpPrefix(route);
161                 boolean addedL3Prefix = NeutronPortAware.addL3PrefixEndpoint(l3ContextIdFromRouterId, ipPrefix,
162                         defaultGateway, tenantId, rwTx, epService);
163                 if (!addedL3Prefix) {
164                     LOG.warn("Could not add EndpointL3Prefix for Neutron route {} for router {}", route, router.getID());
165                     rwTx.cancel();
166                     return;
167                 }
168             }
169         }
170         for (Neutron_IPs externalFixedIp : router.getExternalGatewayInfo().getExternalFixedIPs()) {
171             NeutronPort routerPort = portInterface.getPort(router.getGatewayPortId());
172             IpAddress ipAddress = Utils.createIpAddress(routerPort.getFixedIPs().get(0).getIpAddress());
173             // External subnet associated with gateway port should use the gateway IP not router IP.
174             NeutronSubnet neutronSubnet = subnetInterface.getSubnet(externalFixedIp.getSubnetUUID());
175             ipAddress = Utils.createIpAddress(neutronSubnet.getGatewayIP());
176             SubnetId subnetId = new SubnetId(externalFixedIp.getSubnetUUID());
177             Subnet subnet = resolveSubnetWithVirtualRouterIp(tenantId, subnetId, ipAddress, rwTx);
178             if (subnet == null) {
179                 rwTx.cancel();
180                 return;
181             }
182             rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnet.getId()), subnet);
183
184             if (Strings.isNullOrEmpty(routerPort.getTenantID())) {
185                 routerPort.setTenantID(router.getTenantID());
186             }
187             // create security rules for router
188             List<NeutronSecurityRule> routerSecRules = createRouterSecRules(routerPort, null, rwTx);
189             if (routerSecRules == null) {
190                 rwTx.cancel();
191                 return;
192             }
193             for (NeutronSecurityRule routerSecRule : routerSecRules) {
194                 boolean isRouterSecRuleAdded = NeutronSecurityRuleAware.addNeutronSecurityRule(routerSecRule, rwTx);
195                 if (!isRouterSecRuleAdded) {
196                     rwTx.cancel();
197                     return;
198                 }
199             }
200
201             boolean isSuccessful = setNewL3ContextToEpsFromSubnet(tenantId, l3Context, subnet, rwTx);
202             if (!isSuccessful) {
203                 rwTx.cancel();
204                 return;
205             }
206         }
207
208         DataStoreHelper.submitToDs(rwTx);
209     }
210
211     @Override
212     public int canDeleteRouter(NeutronRouter router) {
213         LOG.trace("canDeleteRouter - {}", router);
214         // nothing to consider
215         return StatusCode.OK;
216     }
217
218     @Override
219     public void neutronRouterDeleted(NeutronRouter router) {
220         LOG.trace("neutronRouterDeleted - {}", router);
221         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
222         TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
223         Optional<EndpointGroup> potentialEpg = DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
224                 IidFactory.endpointGroupIid(tenantId, MappingUtils.EPG_ROUTER_ID), rwTx);
225         if (!potentialEpg.isPresent()) {
226             LOG.warn("Illegal state - Endpoint group {} does not exist.", MappingUtils.EPG_ROUTER_ID.getValue());
227             rwTx.cancel();
228             return;
229         }
230         DataStoreHelper.submitToDs(rwTx);
231     }
232
233     @Override
234     public int canAttachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface) {
235         LOG.trace("canAttachInterface - router: {} interface: {}", router, routerInterface);
236         try (ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction()) {
237             L3ContextId l3ContextIdFromRouterId = new L3ContextId(router.getID());
238             TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
239             SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
240             Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
241                     IidFactory.subnetIid(tenantId, subnetId), rTx);
242             if (!potentialSubnet.isPresent()) {
243                 LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
244                 return StatusCode.NOT_FOUND;
245             }
246             Subnet subnet = potentialSubnet.get();
247             L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
248             ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rTx);
249             if (fwCtx.getL3Context() != null && fwCtx.getL3Context().getId().equals(l3ContextIdFromRouterId)) {
250                 // TODO Be msunal
251                 LOG.warn("Illegal state - Neutron mapper does not support multiple router interfaces in the same subnet yet.");
252                 return StatusCode.FORBIDDEN;
253             }
254             return StatusCode.OK;
255         }
256     }
257
258     @Override
259     public void neutronRouterInterfaceAttached(NeutronRouter router, NeutronRouter_Interface routerInterface) {
260         LOG.trace("neutronRouterInterfaceAttached - router: {} interface: {}", router, routerInterface);
261         NeutronCRUDInterfaces neutronCRUDInterface = new NeutronCRUDInterfaces().fetchINeutronPortCRUD(this);
262         INeutronPortCRUD portInterface = neutronCRUDInterface.getPortInterface();
263         if (portInterface == null) {
264             LOG.warn("Illegal state - No provider for {}", INeutronPortCRUD.class.getName());
265             return;
266         }
267
268         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
269         TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
270         L3ContextId l3ContextIdFromRouterId = new L3ContextId(router.getID());
271         InstanceIdentifier<L3Context> l3ContextIidForRouterId = IidFactory.l3ContextIid(tenantId,
272                 l3ContextIdFromRouterId);
273         Optional<L3Context> potentialL3ContextForRouter = DataStoreHelper.readFromDs(
274                 LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, rwTx);
275         L3Context l3Context = null;
276         if (potentialL3ContextForRouter.isPresent()) {
277             l3Context = potentialL3ContextForRouter.get();
278         } else { // add L3 context if missing
279             l3Context = createL3ContextFromRouter(router);
280             rwTx.put(LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, l3Context);
281         }
282
283         // Based on Neutron Northbound - Port representing router interface
284         // contains exactly on fixed IP
285         NeutronPort routerPort = portInterface.getPort(routerInterface.getPortUUID());
286         SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
287         IpAddress ipAddress = Utils.createIpAddress(routerPort.getFixedIPs().get(0).getIpAddress());
288         Subnet subnet = resolveSubnetWithVirtualRouterIp(tenantId, subnetId, ipAddress, rwTx);
289         if (subnet == null) {
290             rwTx.cancel();
291             return;
292         }
293         rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnet.getId()), subnet);
294
295         // create security rules for router
296         List<NeutronSecurityRule> routerSecRules = createRouterSecRules(routerPort, null, rwTx);
297         if (routerSecRules == null) {
298             rwTx.cancel();
299             return;
300         }
301         for (NeutronSecurityRule routerSecRule : routerSecRules) {
302             boolean isRouterSecRuleAdded = NeutronSecurityRuleAware.addNeutronSecurityRule(routerSecRule, rwTx);
303             if (!isRouterSecRuleAdded) {
304                 rwTx.cancel();
305                 return;
306             }
307         }
308
309         boolean isSuccessful = setNewL3ContextToEpsFromSubnet(tenantId, l3Context, subnet, rwTx);
310         if (!isSuccessful) {
311             rwTx.cancel();
312             return;
313         }
314
315         DataStoreHelper.submitToDs(rwTx);
316     }
317
318     private static @Nonnull L3Context createL3ContextFromRouter(NeutronRouter router) {
319         Name l3ContextName = null;
320         if (!Strings.isNullOrEmpty(router.getName())) {
321             l3ContextName = new Name(router.getName());
322         }
323         return new L3ContextBuilder().setId(new L3ContextId(router.getID()))
324             .setName(l3ContextName)
325             .setDescription(new Description(MappingUtils.NEUTRON_ROUTER__ + router.getID()))
326             .build();
327     }
328
329     private @Nullable Subnet resolveSubnetWithVirtualRouterIp(TenantId tenantId, SubnetId subnetId,
330             IpAddress ipAddress, ReadTransaction rTx) {
331         Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
332                 IidFactory.subnetIid(tenantId, subnetId), rTx);
333         if (!potentialSubnet.isPresent()) {
334             LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
335             return null;
336         }
337
338         // TODO: Li alagalah: Add gateways and prefixes instead of
339         // VirtualRouterID
340         return new SubnetBuilder(potentialSubnet.get()).setVirtualRouterIp(ipAddress).build();
341     }
342
343     /**
344      * @return {@code false} if illegal state occurred; {@code true} otherwise
345      */
346     public boolean setNewL3ContextToEpsFromSubnet(TenantId tenantId, L3Context l3Context, Subnet subnet,
347             ReadWriteTransaction rwTx) {
348         if (subnet.getParent() == null) {
349             LOG.warn("Illegal state - subnet {} does not have a parent.", subnet.getId().getValue());
350             return false;
351         }
352
353         L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
354         ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
355         if (fwCtx.getL2BridgeDomain() == null) {
356             LOG.warn("Illegal state - l2-flood-domain {} does not have a parent.", l2FdId.getValue());
357             return false;
358         }
359
360         L2BridgeDomain l2BridgeDomain = new L2BridgeDomainBuilder(fwCtx.getL2BridgeDomain()).setParent(
361                 l3Context.getId()).build();
362         rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BridgeDomain.getId()),
363                 l2BridgeDomain);
364
365         NeutronCRUDInterfaces neutronCRUDInterface = new NeutronCRUDInterfaces().fetchINeutronSubnetCRUD(this);
366         INeutronSubnetCRUD subnetInterface = neutronCRUDInterface.getSubnetInterface();
367         if (subnetInterface == null) {
368             LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
369             return false;
370         }
371
372         List<L3> l3Eps = new ArrayList<>();
373         L3ContextId oldL3ContextId = fwCtx.getL3Context().getId();
374         NeutronSubnet neutronSubnet = subnetInterface.getSubnet(subnet.getId().getValue());
375         List<NeutronPort> portsInNeutronSubnet = neutronSubnet.getPortsInSubnet();
376         for (NeutronPort port : portsInNeutronSubnet) {
377             boolean isPortAdded = NeutronPortAware.addNeutronPort(port, rwTx, epService);
378             if (!isPortAdded) {
379                 return false;
380             }
381             // TODO Li msunal this has to be rewrite when OFOverlay renderer
382             // will support l3-endpoints.
383             Neutron_IPs firstIp = MappingUtils.getFirstIp(port.getFixedIPs());
384             if (firstIp != null) {
385                 l3Eps.add(new L3Builder().setL3Context(oldL3ContextId)
386                     .setIpAddress(Utils.createIpAddress(firstIp.getIpAddress()))
387                     .build());
388             }
389         }
390         if (neutronSubnet.getGatewayIP() != null) {
391             l3Eps.add(new L3Builder().setL3Context(oldL3ContextId)
392                     .setIpAddress(Utils.createIpAddress(neutronSubnet.getGatewayIP()))
393                     .build());
394         }
395
396         if (!l3Eps.isEmpty()) {
397             epService.unregisterEndpoint(new UnregisterEndpointInputBuilder().setL3(l3Eps).build());
398         }
399         return true;
400     }
401
402     public static List<NeutronSecurityRule> createRouterSecRules(NeutronPort port, EndpointGroupId consumerEpgId,
403             ReadTransaction rTx) {
404         TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
405         Neutron_IPs firstIp = MappingUtils.getFirstIp(port.getFixedIPs());
406         if (firstIp == null) {
407             LOG.warn("Illegal state - Router port does not have an IP address.");
408             return null;
409         }
410         SubnetId routerSubnetId = new SubnetId(firstIp.getSubnetUUID());
411         Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
412                 IidFactory.subnetIid(tenantId, routerSubnetId), rTx);
413         if (!potentialSubnet.isPresent()) {
414             LOG.warn("Illegal state - Subnet {} where is router port does not exist.", routerSubnetId.getValue());
415             return null;
416         }
417         IpPrefix ipSubnet = potentialSubnet.get().getIpPrefix();
418         NeutronSecurityRule routerRuleEgress = createRouterSecRule(port.getID(), tenantId, ipSubnet, consumerEpgId,
419                 true);
420         NeutronSecurityRule routerRuleIngress = createRouterSecRule(port.getID(), tenantId, ipSubnet, consumerEpgId,
421                 false);
422         return ImmutableList.of(routerRuleEgress, routerRuleIngress);
423     }
424
425     private static NeutronSecurityRule createRouterSecRule(String ruleUuid, TenantId tenantId, IpPrefix ipSubnet,
426             EndpointGroupId consumerEpgId, boolean isEgress) {
427         NeutronSecurityRule routerSecRule = new NeutronSecurityRule();
428         routerSecRule.setSecurityRuleGroupID(MappingUtils.EPG_ROUTER_ID.getValue());
429         routerSecRule.setSecurityRuleTenantID(tenantId.getValue());
430         routerSecRule.setSecurityRuleRemoteIpPrefix(Utils.getStringIpPrefix(ipSubnet));
431         if (isEgress) {
432             routerSecRule.setSecurityRuleUUID(NeutronUtils.EGRESS + "__" + ruleUuid);
433             routerSecRule.setSecurityRuleDirection(NeutronUtils.EGRESS);
434         } else {
435             routerSecRule.setSecurityRuleUUID(NeutronUtils.INGRESS + "__" + ruleUuid);
436             routerSecRule.setSecurityRuleDirection(NeutronUtils.INGRESS);
437         }
438         if (ipSubnet.getIpv4Prefix() != null) {
439             routerSecRule.setSecurityRuleEthertype(NeutronUtils.IPv4);
440         } else {
441             routerSecRule.setSecurityRuleEthertype(NeutronUtils.IPv6);
442         }
443         return routerSecRule;
444     }
445
446     @Override
447     public int canDetachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface) {
448         LOG.trace("canDetachInterface - router: {} interface: {}", router, routerInterface);
449         // nothing to consider
450         return StatusCode.OK;
451     }
452
453     @Override
454     public void neutronRouterInterfaceDetached(NeutronRouter router, NeutronRouter_Interface routerInterface) {
455         LOG.trace("neutronRouterInterfaceDetached - router: {} interface: {}", router, routerInterface);
456         NeutronCRUDInterfaces neutronCRUDInterface = new NeutronCRUDInterfaces().fetchINeutronSubnetCRUD(this);
457         INeutronSubnetCRUD subnetInterface = neutronCRUDInterface.getSubnetInterface();
458         if (subnetInterface == null) {
459             LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
460             return;
461         }
462
463         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
464         TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
465         L3ContextId l3ContextId = new L3ContextId(router.getID());
466         SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
467         InstanceIdentifier<L3Context> l3ContextIid = IidFactory.l3ContextIid(tenantId, l3ContextId);
468         DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
469                 IidFactory.l3ContextIid(tenantId, l3ContextId), rwTx);
470
471         Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
472                 IidFactory.subnetIid(tenantId, subnetId), rwTx);
473         if (!potentialSubnet.isPresent()) {
474             LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
475             rwTx.cancel();
476             return;
477         }
478
479         Subnet subnet = new SubnetBuilder(potentialSubnet.get()).setVirtualRouterIp(null).build();
480         rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnetId), subnet);
481
482         L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
483         ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
484         if (fwCtx.getL2BridgeDomain() == null) {
485             LOG.warn("Illegal state - l2-flood-domain {} does not have a parent.", l2FdId.getValue());
486             rwTx.cancel();
487             return;
488         }
489
490         Optional<NetworkMapping> potentialNetworkMapping = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
491                 NeutronMapperIidFactory.networkMappingIid(l2FdId), rwTx);
492         if (!potentialNetworkMapping.isPresent()) {
493             LOG.warn("Illegal state - network-mapping {} does not exist.", l2FdId.getValue());
494             rwTx.cancel();
495             return;
496         }
497
498         L2BridgeDomain l2BridgeDomain = new L2BridgeDomainBuilder(fwCtx.getL2BridgeDomain()).setParent(
499                 potentialNetworkMapping.get().getL3ContextId()).build();
500         rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BridgeDomain.getId()),
501                 l2BridgeDomain);
502
503         NeutronSubnet neutronSubnet = subnetInterface.getSubnet(subnetId.getValue());
504         List<NeutronPort> portsInNeutronSubnet = neutronSubnet.getPortsInSubnet();
505         for (NeutronPort port : portsInNeutronSubnet) {
506             boolean isPortAdded = NeutronPortAware.addNeutronPort(port, rwTx, epService);
507             if (!isPortAdded) {
508                 rwTx.cancel();
509                 return;
510             }
511         }
512     }
513
514 }