Add INFO.yaml for GBP
[groupbasedpolicy.git] / neutron-mapper / src / main / java / org / opendaylight / groupbasedpolicy / neutron / mapper / mapping / NeutronPortAware.java
1 /*
2  * Copyright (c) 2015 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 package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping;
9
10 import static com.google.common.base.Preconditions.checkNotNull;
11
12 import com.google.common.base.Optional;
13 import com.google.common.collect.ImmutableList;
14 import com.google.common.collect.Lists;
15
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.List;
19 import java.util.Set;
20 import java.util.stream.Collectors;
21
22 import javax.annotation.Nullable;
23
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
26 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.groupbasedpolicy.domain_extension.l2_l3.util.L2L3IidFactory;
29 import org.opendaylight.groupbasedpolicy.neutron.gbp.util.NeutronGbpIidFactory;
30 import org.opendaylight.groupbasedpolicy.neutron.mapper.EndpointRegistrator;
31 import org.opendaylight.groupbasedpolicy.neutron.mapper.infrastructure.MetadataService;
32 import org.opendaylight.groupbasedpolicy.neutron.mapper.infrastructure.NetworkClient;
33 import org.opendaylight.groupbasedpolicy.neutron.mapper.infrastructure.NetworkService;
34 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
35 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.PortUtils;
36 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.SubnetUtils;
37 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
38 import org.opendaylight.groupbasedpolicy.util.IidFactory;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.RegisterEndpointInput;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.RegisterEndpointInputBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.UnregisterEndpointInput;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.UnregisterEndpointInputBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.NetworkContainmentBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.network.containment.containment.NetworkDomainContainmentBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpoint;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpointKey;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.child.endpoints.ChildEndpoint;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.child.endpoints.ChildEndpointBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.ParentEndpointCaseBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.endpoint._case.ParentEndpoint;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.endpoint._case.ParentEndpointBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.register.endpoint.input.AddressEndpointReg;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.register.endpoint.input.AddressEndpointRegBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.unregister.endpoint.input.AddressEndpointUnreg;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.unregister.endpoint.input.AddressEndpointUnregBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.UniqueId;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3AddressBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointKey;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L2;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L2Builder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3Builder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.IpPrefixType;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.L3Context;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.MacAddressType;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.forwarding.forwarding.by.tenant.ForwardingContext;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.forwarding.forwarding.by.tenant.ForwardingContextBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.forwarding.forwarding.by.tenant.NetworkDomain;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.base.endpoints.by.ports.BaseEndpointByPort;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.endpoints.by.ports.EndpointByPort;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.ports.by.base.endpoints.PortByBaseEndpoint;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.ports.by.base.endpoints.PortByBaseEndpointKey;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.ports.by.endpoints.PortByEndpoint;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2BridgeDomain;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2BridgeDomainBuilder;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIpsBuilder;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIpsKey;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.PortBuilder;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
96 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
97 import org.slf4j.Logger;
98 import org.slf4j.LoggerFactory;
99
100 public class NeutronPortAware implements NeutronAware<Port> {
101
102     private static final Logger LOG = LoggerFactory.getLogger(NeutronPortAware.class);
103     public static final InstanceIdentifier<Port> PORT_WILDCARD_IID =
104             InstanceIdentifier.builder(Neutron.class).child(Ports.class).child(Port.class).build();
105     private final DataBroker dataProvider;
106     private final EndpointRegistrator epRegistrator;
107     private final IpPrefix metadataIpPrefix;
108
109     public NeutronPortAware(DataBroker dataProvider, EndpointRegistrator epRegistrator,
110             @Nullable IpPrefix metadataIpPrefix) {
111         this.dataProvider = checkNotNull(dataProvider);
112         this.epRegistrator = checkNotNull(epRegistrator);
113         this.metadataIpPrefix = checkNotNull(metadataIpPrefix);
114     }
115
116     @Override
117     public void onCreated(Port createdItem, Neutron neutron) {
118         onCreated(createdItem, neutron, true);
119     }
120
121     @SuppressWarnings("checkstyle:LineLength") // Longer lines in this method are caused by long package names,
122                                                // this will be removed when deprecated classes will be cleared.
123     public void onCreated(Port port, Neutron neutron, boolean addBaseEpMapping) {
124         LOG.trace("created port - {}", port);
125         if (PortUtils.isRouterInterfacePort(port)) {
126             LOG.trace("Port is router interface port: {}", port.getUuid().getValue());
127             // router interface port can have only one IP
128             Optional<FixedIps> potentialPortIpWithSubnet = PortUtils.resolveFirstFixedIps(port);
129             if (!potentialPortIpWithSubnet.isPresent()) {
130                 LOG.warn("Illegal state - router interface port does not contain fixed IPs {}", port);
131                 return;
132             }
133             final FixedIps portIpWithSubnet = potentialPortIpWithSubnet.get();
134             final ContextId routerL3Context = new ContextId(port.getDeviceId());
135             AddressEndpointKey addrEpKey = new AddressEndpointKey(port.getMacAddress().getValue(), MacAddressType.class,
136                     new ContextId(port.getNetworkId().getValue()), MappingUtils.L2_BRDIGE_DOMAIN);
137             UniqueId portId = new UniqueId(port.getUuid().getValue());
138             ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
139             addBaseEndpointMappings(addrEpKey, portId, rwTx);
140             // Add Qrouter and VPProuter port as Endpoint
141             if (port.getAugmentation(PortBindingExtension.class) != null && PortUtils.DEVICE_VIF_TYPE
142                 .equals(port.getAugmentation(PortBindingExtension.class).getVifType())) {
143                 LOG.trace("Port is QRouter port: {}", port.getUuid().getValue());
144                 Optional<FixedIps> firstFixedIps = PortUtils.resolveFirstFixedIps(port);
145                 if (!firstFixedIps.isPresent()) {
146                     LOG.warn("QRouter port does not have an IP address. {}", port);
147                     return;
148                 }
149                 FixedIps ipWithSubnet = firstFixedIps.get();
150                 NetworkDomainId networkContainment = new NetworkDomainId(ipWithSubnet.getSubnetId().getValue());
151                 List<EndpointGroupId> epgsFromSecGroups = resolveEpgIdsFromSecGroups(port.getSecurityGroups());
152                 epgsFromSecGroups.add(NetworkService.EPG_ID);
153                 // BUILD BASE ENDPOINT
154                 AddressEndpointRegBuilder l2BaseEp =
155                         createBasicMacAddrEpInputBuilder(port, networkContainment, epgsFromSecGroups);
156                 AddressEndpointRegBuilder l3BaseEp =
157                         createBasicL3AddrEpInputBuilder(port, networkContainment, epgsFromSecGroups, neutron);
158                 setParentChildRelationshipForEndpoints(l3BaseEp, l2BaseEp);
159                 // BUILD ENDPOINT
160                 org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder epInBuilder =
161                         createEndpointRegFromPort(port, ipWithSubnet, networkContainment, epgsFromSecGroups, neutron);
162                 registerBaseEndpointAndStoreMapping(ImmutableList.of(l2BaseEp.build(), l3BaseEp.build()), port, rwTx,
163                         addBaseEpMapping);
164                 registerEndpointAndStoreMapping(epInBuilder.build(), port, rwTx);
165             }
166             // change L3Context for all EPs with same subnet as router port
167             changeL3ContextForEpsInSubnet(portIpWithSubnet.getSubnetId(), port.getNetworkId(),
168                     new Uuid(port.getDeviceId()), neutron, true);
169             // set L3Context as parent for bridge domain which is parent of subnet
170             TenantId tenantId = new TenantId(port.getTenantId().getValue());
171             Optional<Subnet> potentialRouterPortSubnet =
172                     SubnetUtils.findSubnet(portIpWithSubnet.getSubnetId(), neutron.getSubnets());
173             if (!potentialRouterPortSubnet.isPresent()) {
174                 LOG.warn("Illegal state - router interface port is in subnet which does not exist. {}", port);
175                 return;
176             }
177             Subnet routerPortSubnet = potentialRouterPortSubnet.get();
178             ContextId l2BdId = new ContextId(routerPortSubnet.getNetworkId().getValue());
179             ForwardingContext l2Bd = new ForwardingContextBuilder().setContextId(l2BdId)
180                 .setContextType(MappingUtils.L2_BRDIGE_DOMAIN)
181                 .setParent(MappingUtils.createParent(routerL3Context, MappingUtils.L3_CONTEXT))
182                 .build();
183             rwTx.merge(LogicalDatastoreType.CONFIGURATION, L2L3IidFactory.l2BridgeDomainIid(tenantId, l2BdId), l2Bd,
184                     true);
185             // set virtual router IP for subnet
186             NetworkDomain subnetDomain = NeutronSubnetAware.createSubnet(routerPortSubnet, neutron, null);
187             rwTx.merge(LogicalDatastoreType.CONFIGURATION,
188                     L2L3IidFactory.subnetIid(tenantId, subnetDomain.getNetworkDomainId()), subnetDomain);
189
190             // does the same for tenant forwarding domains
191             processTenantForwarding(routerPortSubnet, routerL3Context, portIpWithSubnet, tenantId, rwTx);
192
193             DataStoreHelper.submitToDs(rwTx);
194         } else if (PortUtils.isDhcpPort(port)) {
195             // process as normal port but put it to DHCP group
196             LOG.trace("Port is DHCP port: {}", port.getUuid().getValue());
197             Optional<FixedIps> firstFixedIps = PortUtils.resolveFirstFixedIps(port);
198             if (!firstFixedIps.isPresent()) {
199                 LOG.warn("DHCP port does not have an IP address. {}", port);
200                 return;
201             }
202             FixedIps ipWithSubnet = firstFixedIps.get();
203             NetworkDomainId networkContainment = new NetworkDomainId(ipWithSubnet.getSubnetId().getValue());
204             List<EndpointGroupId> epgsFromSecGroups = resolveEpgIdsFromSecGroups(port.getSecurityGroups());
205             epgsFromSecGroups.add(NetworkService.EPG_ID);
206             AddressEndpointRegBuilder l2BaseEp =
207                     createBasicMacAddrEpInputBuilder(port, networkContainment, Collections.emptyList());
208             AddressEndpointRegBuilder l3BaseEp =
209                     createBasicL3AddrEpInputBuilder(port, networkContainment, epgsFromSecGroups, neutron);
210
211             setParentChildRelationshipForEndpoints(l3BaseEp, l2BaseEp);
212             org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder epInBuilder =
213                     createEndpointRegFromPort(port, ipWithSubnet, networkContainment, epgsFromSecGroups, neutron);
214             ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
215             registerBaseEndpointAndStoreMapping(ImmutableList.of(l3BaseEp.build(), l2BaseEp.build()), port, rwTx,
216                     addBaseEpMapping);
217             registerMetadataServiceForDhcpPort(port, neutron, l2BaseEp, rwTx, true);
218             registerEndpointAndStoreMapping(epInBuilder.build(), port, rwTx);
219             DataStoreHelper.submitToDs(rwTx);
220         } else if (PortUtils.isNormalPort(port)) {
221             LOG.trace("Port is normal port: {}", port.getUuid().getValue());
222             org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder epInBuilder =
223                     null;
224             AddressEndpointRegBuilder l2BaseEp;
225             AddressEndpointRegBuilder l3BaseEp = null;
226             Optional<FixedIps> firstFixedIps = PortUtils.resolveFirstFixedIps(port);
227             List<EndpointGroupId> epgsFromSecGroups = resolveEpgIdsFromSecGroups(port.getSecurityGroups());
228             epgsFromSecGroups.add(NetworkClient.EPG_ID);
229             if (firstFixedIps.isPresent()) {
230                 // endpoint has only one network containment therefore only first IP is used
231                 FixedIps ipWithSubnet = firstFixedIps.get();
232                 NetworkDomainId containment = new NetworkDomainId(ipWithSubnet.getSubnetId().getValue());
233                 epInBuilder = createEndpointRegFromPort(port, ipWithSubnet, containment, epgsFromSecGroups, neutron);
234                 l2BaseEp = createBasicMacAddrEpInputBuilder(port, containment, epgsFromSecGroups);
235                 l3BaseEp = createBasicL3AddrEpInputBuilder(port, containment, epgsFromSecGroups, neutron);
236                 setParentChildRelationshipForEndpoints(l3BaseEp, l2BaseEp);
237             } else {
238                 NetworkDomainId containment = new NetworkDomainId(port.getNetworkId().getValue());
239                 epInBuilder = createEndpointRegFromPort(port, null, containment, epgsFromSecGroups, neutron);
240                 l2BaseEp = createBasicMacAddrEpInputBuilder(port, containment, epgsFromSecGroups);
241             }
242             List<AddressEndpointReg> baseEpRegs = new ArrayList<>();
243             baseEpRegs.add(l2BaseEp.build());
244             if (l3BaseEp != null) {
245                 baseEpRegs.add(l3BaseEp.build());
246             }
247             ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
248             registerBaseEndpointAndStoreMapping(baseEpRegs, port, rwTx, addBaseEpMapping);
249             registerEndpointAndStoreMapping(epInBuilder.build(), port, rwTx);
250             DataStoreHelper.submitToDs(rwTx);
251         } else if (PortUtils.isRouterGatewayPort(port)) {
252             // do nothing because actual trigger is attaching of port to router
253             LOG.trace("Port is router gateway port: {}", port.getUuid().getValue());
254         } else if (PortUtils.isFloatingIpPort(port)) {
255             // do nothing because trigger is floating IP
256             LOG.trace("Port is floating ip: {}", port.getUuid().getValue());
257         } else {
258             LOG.warn("Unknown port: {}", port);
259         }
260     }
261
262     private Port cloneMetadataPortFromDhcpPort(Port port, IpPrefix metadataPrefix) {
263         IpAddress metadataIp = MappingUtils.ipPrefixToIpAddress(metadataPrefix);
264         List<FixedIps> metadataIps = port.getFixedIps().stream().map(fi -> {
265             FixedIpsKey key = new FixedIpsKey(metadataIp, fi.getKey().getSubnetId());
266             return new FixedIpsBuilder(fi).setKey(key).setIpAddress(metadataIp).build();
267         }).collect(Collectors.toList());
268         return new PortBuilder(port).setFixedIps(metadataIps).build();
269     }
270
271     private void registerMetadataServiceForDhcpPort(Port port, Neutron neutron, AddressEndpointRegBuilder childEpToAdd,
272             ReadWriteTransaction rwTx, boolean registerMapping) {
273         Optional<NetworkDomainId> resolveNetworkContainment = PortUtils.resolveNetworkContainment(port);
274         if (!resolveNetworkContainment.isPresent()) {
275             LOG.warn("DHCP port does not have an IP address. {}", port);
276             return;
277         }
278         AddressEndpointRegBuilder metadataEp =
279                 createBasicL3AddrEpInputBuilder(cloneMetadataPortFromDhcpPort(port, metadataIpPrefix),
280                         resolveNetworkContainment.get(), Lists.newArrayList(MetadataService.EPG_ID), neutron);
281         AddressEndpointKey aek = new AddressEndpointKey(metadataEp.getAddress(), metadataEp.getAddressType(),
282                 metadataEp.getContextId(), metadataEp.getContextType());
283         Optional<AddressEndpoint> optMetadataEp =
284                 DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, IidFactory.addressEndpointIid(aek), rwTx);
285         if (!optMetadataEp.isPresent()) {
286             setParentChildRelationshipForEndpoints(metadataEp, childEpToAdd);
287         } else {
288             List<ChildEndpoint> childs = optMetadataEp.get().getChildEndpoint();
289             childs.add(createChildEndpoint(childEpToAdd));
290             metadataEp.setChildEndpoint(childs);
291         }
292         registerBaseEndpointAndStoreMapping(ImmutableList.of(metadataEp.build()), port, rwTx, registerMapping);
293     }
294
295     private void setParentChildRelationshipForEndpoints(AddressEndpointRegBuilder parentEp,
296             AddressEndpointRegBuilder childEp) {
297         childEp.setParentEndpointChoice(new ParentEndpointCaseBuilder()
298             .setParentEndpoint(ImmutableList.<ParentEndpoint>of(createParentEndpoint(parentEp))).build());
299         parentEp.setChildEndpoint(ImmutableList.<ChildEndpoint>of(createChildEndpoint(childEp)));
300     }
301
302     @Deprecated
303     @SuppressWarnings("checkstyle:LineLength") // Longer lines in this method are caused by long package names,
304                                                // this will be removed when deprecated classes will be cleared.
305     private void processTenantForwarding(Subnet routerPortSubnet, ContextId routerL3Context, FixedIps portIpWithSubnet,
306             TenantId tenantId, ReadWriteTransaction rwTx) {
307         L2BridgeDomainId l2BdId = new L2BridgeDomainId(routerPortSubnet.getNetworkId().getValue());
308         L2BridgeDomain l2Bd =
309                 new L2BridgeDomainBuilder().setId(l2BdId).setParent(new L3ContextId(routerL3Context)).build();
310         rwTx.merge(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BdId), l2Bd, true);
311         // set virtual router IP for subnet
312         org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet subnet =
313                 NeutronSubnetAware.createTenantSubnet(routerPortSubnet, portIpWithSubnet.getIpAddress());
314         rwTx.merge(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnet.getId()), subnet);
315     }
316
317     /**
318      * Registers endpoint from {@link Port} and method parameters.
319      * Always creates registration input for L2 endpoint.
320      * Creates registration input for L3 endpoint if fixedIps argument is not null.
321      */
322     @Deprecated
323     @SuppressWarnings("checkstyle:LineLength") // Longer lines in this method are caused by long package names,
324                                                // this will be removed when deprecated classes will be cleared.
325     private org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder createEndpointRegFromPort(
326             Port port, FixedIps fixedIps, NetworkDomainId networkContainment, List<EndpointGroupId> endpointGroupIds,
327             Neutron neutron) {
328         org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder epInBuilder =
329                 createBasicEndpointInputBuilder(port).setNetworkContainment(networkContainment);
330         if (fixedIps != null) {
331             L3Address l3Address = resolveL3AddressFromPort(port, fixedIps, neutron);
332             epInBuilder.setL3Address(ImmutableList.of(l3Address));
333         }
334         epInBuilder.setEndpointGroups(endpointGroupIds);
335         return epInBuilder;
336     }
337
338     private void changeL3ContextForEpsInSubnet(Uuid subnetUuid, Uuid networkId, Uuid routerId, Neutron neutron,
339             boolean routerInterfAdded) {
340         if (neutron == null) {
341             LOG.debug("No new data are written, there is no L3 context in subnet {} to update", subnetUuid);
342             return;
343         }
344         java.util.Optional<Subnet> optSubnet = neutron.getSubnets()
345             .getSubnet()
346             .stream()
347             .filter(subnet -> subnet.getNetworkId() != null
348                     && subnet.getUuid().getValue().equals(subnetUuid.getValue()))
349             .findAny();
350         if (!optSubnet.isPresent()) {
351             LOG.error("Failed to update metadata endpoint in subnet {}. Could not resolve Network ID", subnetUuid);
352         } else {
353             AddressEndpointUnregBuilder metadataEpUnreg =
354                     new AddressEndpointUnregBuilder().setAddress(String.valueOf(metadataIpPrefix.getValue()))
355                         .setAddressType(IpPrefixType.class)
356                         .setContextType(MappingUtils.L3_CONTEXT);
357             if (routerInterfAdded) {
358                 metadataEpUnreg.setContextId(new ContextId(networkId.getValue()));
359             } else {
360                 metadataEpUnreg.setContextId(new ContextId(routerId.getValue()));
361             }
362             epRegistrator.unregisterEndpoint(metadataEpUnreg.build());
363         }
364         Set<Port> portsInSameSubnet = PortUtils.findPortsBySubnet(subnetUuid, neutron.getPorts());
365         for (Port portInSameSubnet : portsInSameSubnet) {
366             if (PortUtils.isNormalPort(portInSameSubnet) || PortUtils.isDhcpPort(portInSameSubnet)
367                     || PortUtils.isQrouterOrVppRouterPort(portInSameSubnet)) {
368                 // endpoints are created only from neutron normal port or DHCP port
369                 Optional<FixedIps> firstFixedIps = PortUtils.resolveFirstFixedIps(portInSameSubnet);
370                 if (firstFixedIps.isPresent()) {
371                     // endpoint has only one network containment therefore only first IP is used
372                     FixedIps ipWithSubnet = firstFixedIps.get();
373                     List<EndpointGroupId> endpointGroupIds = new ArrayList<>();
374                     if (PortUtils.isDhcpPort(portInSameSubnet)
375                             || PortUtils.isQrouterOrVppRouterPort(portInSameSubnet)) {
376                         endpointGroupIds.add(NetworkService.EPG_ID);
377                     } else if (PortUtils.isNormalPort(portInSameSubnet)) {
378                         endpointGroupIds.add(NetworkClient.EPG_ID);
379                     }
380                     NetworkDomainId networkContainment = new NetworkDomainId(ipWithSubnet.getSubnetId().getValue());
381                     AddressEndpointRegBuilder l2BaseEp =
382                             createBasicMacAddrEpInputBuilder(portInSameSubnet, networkContainment, endpointGroupIds);
383                     AddressEndpointRegBuilder l3BaseEp = createBasicL3AddrEpInputBuilder(portInSameSubnet,
384                             networkContainment, endpointGroupIds, neutron);
385
386                     setParentChildRelationshipForEndpoints(l3BaseEp, l2BaseEp);
387                     AddressEndpointUnregBuilder addrEpUnreg =
388                             new AddressEndpointUnregBuilder().setAddress(l3BaseEp.getAddress())
389                                 .setAddressType(l3BaseEp.getAddressType())
390                                 .setContextType(l3BaseEp.getContextType());
391                     if (routerInterfAdded) {
392                         addrEpUnreg.setContextId(new ContextId(networkId.getValue()));
393                     } else {
394                         addrEpUnreg.setContextId(new ContextId(routerId.getValue()));
395                     }
396                     epRegistrator.unregisterEndpoint(addrEpUnreg.build());
397                     if (routerInterfAdded) {
398                         l3BaseEp.setContextId(new ContextId(routerId.getValue()));
399                     } else {
400                         l3BaseEp.setContextId(new ContextId(networkId.getValue()));
401                     }
402                     setParentChildRelationshipForEndpoints(l3BaseEp, l2BaseEp);
403                     RegisterEndpointInput regBaseEpInput = new RegisterEndpointInputBuilder()
404                         .setAddressEndpointReg(ImmutableList.of(l2BaseEp.build(), l3BaseEp.build())).build();
405                     epRegistrator.registerEndpoint(regBaseEpInput);
406                     if (PortUtils.isDhcpPort(portInSameSubnet)) {
407                         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
408                         registerMetadataServiceForDhcpPort(portInSameSubnet, neutron, l2BaseEp, rwTx, false);
409                         DataStoreHelper.submitToDs(rwTx);
410                     }
411                     modifyL3ContextForEndpoints(portInSameSubnet, ipWithSubnet, l3BaseEp.getContextId());
412                 }
413             }
414         }
415     }
416
417     private ChildEndpoint createChildEndpoint(AddressEndpointRegBuilder builder) {
418         return new ChildEndpointBuilder().setAddress(builder.getAddress())
419             .setAddressType(builder.getAddressType())
420             .setContextId(builder.getContextId())
421             .setContextType(builder.getContextType())
422             .build();
423     }
424
425     private ParentEndpoint createParentEndpoint(AddressEndpointRegBuilder builder) {
426         return new ParentEndpointBuilder().setAddress(builder.getAddress())
427             .setAddressType(builder.getAddressType())
428             .setContextId(builder.getContextId())
429             .setContextType(builder.getContextType())
430             .build();
431     }
432
433     @Deprecated
434     @SuppressWarnings("checkstyle:LineLength") // Longer lines in this method are caused by long package names,
435                                                // this will be removed when deprecated classes will be cleared.
436     private void modifyL3ContextForEndpoints(Port port, FixedIps resolvedPortFixedIp, ContextId newContextId) {
437         org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder epInBuilder =
438                 createBasicEndpointInputBuilder(port);
439         epInBuilder.setNetworkContainment(new NetworkDomainId(resolvedPortFixedIp.getSubnetId().getValue()));
440         L3Address l3Address = new L3AddressBuilder().setL3Context(new L3ContextId(newContextId))
441             .setIpAddress(resolvedPortFixedIp.getIpAddress())
442             .build();
443         epInBuilder.setL3Address(ImmutableList.of(l3Address));
444         List<EndpointGroupId> epgsFromSecGroups = resolveEpgIdsFromSecGroups(port.getSecurityGroups());
445         epgsFromSecGroups.add(NetworkClient.EPG_ID);
446         epInBuilder.setEndpointGroups(epgsFromSecGroups);
447         epRegistrator.registerEndpoint(epInBuilder.build());
448         // unregister L3EP
449         L3ContextId oldL3Context = new L3ContextId(port.getNetworkId().getValue());
450         L3 l3 = new L3Builder().setL3Context(oldL3Context).setIpAddress(resolvedPortFixedIp.getIpAddress()).build();
451         org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInput epUnreg =
452                 new org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInputBuilder()
453                     .setL3(ImmutableList.of(l3)).build();
454         epRegistrator.unregisterEndpoint(epUnreg);
455     }
456
457     private AddressEndpointRegBuilder createBasicMacAddrEpInputBuilder(Port port, NetworkDomainId networkContainment,
458             @Nullable List<EndpointGroupId> endpointGroupsToAdd) {
459         AddressEndpointRegBuilder addrEpbuilder = new AddressEndpointRegBuilder().setAddressType(MacAddressType.class)
460             .setAddress(port.getMacAddress().getValue())
461             .setAddressType(MacAddressType.class)
462             .setContextType(MappingUtils.L2_BRDIGE_DOMAIN)
463             .setContextId(new ContextId(port.getNetworkId().getValue()))
464             .setTenant(new TenantId(port.getTenantId().getValue()))
465             .setTimestamp(System.currentTimeMillis());
466         List<EndpointGroupId> epgs = concatEndpointGroups(port.getSecurityGroups(), endpointGroupsToAdd);
467         addrEpbuilder.setEndpointGroup(epgs);
468         if (networkContainment != null) {
469             addrEpbuilder.setNetworkContainment(new NetworkContainmentBuilder()
470                 .setContainment(new NetworkDomainContainmentBuilder().setNetworkDomainId(networkContainment)
471                     .setNetworkDomainType(MappingUtils.SUBNET)
472                     .build())
473                 .build());
474         }
475         return addrEpbuilder;
476     }
477
478     private AddressEndpointRegBuilder createBasicL3AddrEpInputBuilder(Port port, NetworkDomainId networkContainment,
479             @Nullable List<EndpointGroupId> endpointGroupsToAdd, Neutron neutron) {
480         Optional<FixedIps> firstFixedIps = PortUtils.resolveFirstFixedIps(port);
481         if (!firstFixedIps.isPresent()) {
482             throw new IllegalStateException(
483                     "Failed to resolve FixedIps for port " + port.getKey() + ". Cannot register L3 Address endpoint.");
484         }
485         ContextId resolveL3ContextForPort = resolveL3ContextForPort(port, port.getFixedIps().get(0), neutron);
486
487         AddressEndpointRegBuilder addrEpbuilder = new AddressEndpointRegBuilder().setAddressType(MacAddressType.class)
488             .setAddress(MappingUtils.ipAddressToStringIpPrefix(firstFixedIps.get().getIpAddress()))
489             .setAddressType(IpPrefixType.class)
490             .setContextType(MappingUtils.L3_CONTEXT)
491             .setContextId(resolveL3ContextForPort)
492             .setTenant(new TenantId(port.getTenantId().getValue()))
493             .setTimestamp(System.currentTimeMillis());
494         List<EndpointGroupId> epgs = concatEndpointGroups(port.getSecurityGroups(), endpointGroupsToAdd);
495         addrEpbuilder.setEndpointGroup(epgs);
496         if (networkContainment != null) {
497             addrEpbuilder.setNetworkContainment(new NetworkContainmentBuilder()
498                 .setContainment(new NetworkDomainContainmentBuilder().setNetworkDomainId(networkContainment)
499                     .setNetworkDomainType(MappingUtils.SUBNET)
500                     .build())
501                 .build());
502         }
503         return addrEpbuilder;
504     }
505
506     private List<EndpointGroupId> concatEndpointGroups(List<Uuid> securityGroups,
507             @Nullable List<EndpointGroupId> endpointGroupsToAdd) {
508         List<EndpointGroupId> epgs = new ArrayList<>();
509         if (securityGroups != null) {
510             for (Uuid sgId : securityGroups) {
511                 epgs.add(new EndpointGroupId(sgId.getValue()));
512             }
513         }
514         if (endpointGroupsToAdd != null) {
515             epgs.addAll(endpointGroupsToAdd);
516         }
517         return epgs;
518     }
519
520     @Deprecated
521     @SuppressWarnings("checkstyle:LineLength") // Longer lines in this method are caused by long package names,
522                                                // this will be removed when deprecated classes will be cleared.
523     private static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder createBasicEndpointInputBuilder(
524             Port port) {
525         return new org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder()
526             .setL2Context(new L2BridgeDomainId(port.getNetworkId().getValue()))
527             .setMacAddress(new MacAddress(port.getMacAddress().getValue()))
528             .setTenant(new TenantId(port.getTenantId().getValue()))
529             .setTimestamp(System.currentTimeMillis());
530     }
531
532     private static List<EndpointGroupId> resolveEpgIdsFromSecGroups(@Nullable List<Uuid> securityGroups) {
533         List<EndpointGroupId> epgIds = new ArrayList<>();
534         if ((securityGroups == null || securityGroups.isEmpty())) {
535             return epgIds;
536         }
537         for (Uuid secGrp : securityGroups) {
538             epgIds.add(new EndpointGroupId(secGrp.getValue()));
539         }
540         return epgIds;
541     }
542
543     @Deprecated
544     @SuppressWarnings("checkstyle:LineLength") // Longer lines in this method are caused by long package names,
545                                                // this will be removed when deprecated classes will be cleared.
546     private void registerEndpointAndStoreMapping(
547             org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInput regEpInput,
548             Port port, ReadWriteTransaction rwTx) {
549         boolean isRegisteredEndpoint = epRegistrator.registerEndpoint(regEpInput);
550         if (!isRegisteredEndpoint) {
551             LOG.error("Failed to register endpoint: {}", regEpInput);
552             return;
553         }
554         UniqueId portId = new UniqueId(port.getUuid().getValue());
555         EndpointKey epKey = new EndpointKey(new L2BridgeDomainId(port.getNetworkId().getValue()),
556                 new MacAddress(port.getMacAddress().getValue()));
557         LOG.trace("Adding Port-Endpoint mapping for port {} (device owner {}) and endpoint {}",
558                 port.getUuid().getValue(), port.getDeviceOwner(), epKey);
559         EndpointByPort endpointByPort = MappingFactory.createEndpointByPort(epKey, portId);
560         rwTx.put(LogicalDatastoreType.OPERATIONAL, NeutronGbpIidFactory.endpointByPortIid(portId), endpointByPort,
561                 true);
562         PortByEndpoint portByEndpoint = MappingFactory.createPortByEndpoint(portId, epKey);
563         rwTx.put(LogicalDatastoreType.OPERATIONAL,
564                 NeutronGbpIidFactory.portByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()), portByEndpoint,
565                 true);
566     }
567
568     @Deprecated
569     @SuppressWarnings("checkstyle:LineLength") // Longer lines in this method are caused by long package names,
570                                                // this will be removed when deprecated classes will be cleared.
571     private void unregisterEndpointAndRemoveMapping(
572             org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInput unregEpInput,
573             Port port, ReadWriteTransaction rwTx) {
574         boolean isUnregisteredEndpoint = epRegistrator.unregisterEndpoint(unregEpInput);
575         if (isUnregisteredEndpoint) {
576             UniqueId portId = new UniqueId(port.getUuid().getValue());
577             EndpointKey epKey = new EndpointKey(new L2BridgeDomainId(port.getNetworkId().getValue()),
578                     new MacAddress(port.getMacAddress().getValue()));
579             LOG.trace("Removing Port-Endpoint mapping for port {} (device owner {}) and endpoint {}",
580                     port.getUuid().getValue(), port.getDeviceOwner(), epKey);
581             DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
582                     NeutronGbpIidFactory.endpointByPortIid(portId), rwTx);
583             DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
584                     NeutronGbpIidFactory.portByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()), rwTx);
585         }
586     }
587
588     private void unregisterEndpointAndRemoveMapping(UnregisterEndpointInput baseEpUnreg, Port port,
589         ReadWriteTransaction rwTx, boolean removeBaseEpMappings) {
590         boolean isUnregisteredBaseEndpoint = epRegistrator.unregisterEndpoint(baseEpUnreg);
591         if (isUnregisteredBaseEndpoint) {
592             UniqueId portId = new UniqueId(port.getUuid().getValue());
593             PortByBaseEndpointKey portByBaseEndpointKey = new PortByBaseEndpointKey(port.getMacAddress().getValue(),
594                 MacAddressType.class, new ContextId(port.getNetworkId().getValue()), MappingUtils.L2_BRDIGE_DOMAIN);
595             LOG.trace("Removing Port-BaseEndpoint mapping for port {} (device owner {}) and endpoint {}",
596                 port.getUuid().getValue(), port.getDeviceOwner(), portByBaseEndpointKey);
597             if (removeBaseEpMappings) {
598                 removeBaseEndpointMappings(portByBaseEndpointKey, portId, rwTx);
599             }
600         }
601     }
602
603     private void registerBaseEndpointAndStoreMapping(List<AddressEndpointReg> addrEpRegs, Port port,
604             WriteTransaction writeTx, boolean addBaseEpMappings) {
605         RegisterEndpointInput regBaseEpInput =
606                 new RegisterEndpointInputBuilder().setAddressEndpointReg(addrEpRegs).build();
607
608         boolean isRegisteredBaseEndpoint = epRegistrator.registerEndpoint(regBaseEpInput);
609         if (!isRegisteredBaseEndpoint) {
610             LOG.error("Failed to register address endpoint: {}", addrEpRegs);
611             return;
612         }
613         for (AddressEndpointReg addrEpReg : addrEpRegs) {
614             if (MappingUtils.L2_BRDIGE_DOMAIN.equals(addrEpReg.getContextType()) && addBaseEpMappings) {
615                 UniqueId portId = new UniqueId(port.getUuid().getValue());
616                 LOG.trace("Adding Port-BaseEndpoint mapping for port {} (device owner {}) and endpoint {}",
617                         port.getUuid());
618                 AddressEndpointKey addrEpKey = new AddressEndpointKey(addrEpReg.getAddress(),
619                         addrEpReg.getAddressType(), addrEpReg.getContextId(), addrEpReg.getContextType());
620                 addBaseEndpointMappings(addrEpKey, portId, writeTx);
621             }
622         }
623     }
624
625     private void addBaseEndpointMappings(AddressEndpointKey addrEpKey, UniqueId portId, WriteTransaction writeTx) {
626         BaseEndpointByPort baseEndpointByPort = MappingFactory.createBaseEndpointByPort(addrEpKey, portId);
627         writeTx.put(LogicalDatastoreType.OPERATIONAL, NeutronGbpIidFactory.baseEndpointByPortIid(portId),
628                 baseEndpointByPort, true);
629         PortByBaseEndpoint portByBaseEndpoint = MappingFactory.createPortByBaseEndpoint(portId, addrEpKey);
630         writeTx.put(LogicalDatastoreType.OPERATIONAL,
631                 NeutronGbpIidFactory.portByBaseEndpointIid(new PortByBaseEndpointKey(portByBaseEndpoint.getKey())),
632                 portByBaseEndpoint, true);
633     }
634
635     private void removeBaseEndpointMappings(PortByBaseEndpointKey portByBaseEndpointKey, UniqueId portId,
636             ReadWriteTransaction rwTx) {
637         DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
638                 NeutronGbpIidFactory.baseEndpointByPortIid(portId), rwTx);
639         DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
640                 NeutronGbpIidFactory.portByBaseEndpointIid(portByBaseEndpointKey), rwTx);
641     }
642
643     @Override
644     public void onUpdated(Port oldPort, Port newPort, Neutron oldNeutron, Neutron newNeutron) {
645         LOG.trace("updated port - OLD: {}\nNEW: {}", oldPort, newPort);
646         onDeleted(oldPort, oldNeutron, newNeutron, false);
647         onCreated(newPort, newNeutron, false);
648     }
649
650     @Override
651     public void onDeleted(Port deletedItem, Neutron oldNeutron, Neutron newNeutron) {
652         onDeleted(deletedItem, oldNeutron, newNeutron, true);
653     }
654
655     public void onDeleted(Port port, Neutron oldNeutron, Neutron newNeutron, boolean removeBaseEpMapping) {
656         LOG.trace("deleted port - {}", port);
657         if (PortUtils.isRouterInterfacePort(port)) {
658             LOG.trace("Port is router interface port: {}", port.getUuid().getValue());
659             // router interface port can have only one IP
660             Optional<FixedIps> potentialPortIpWithSubnet = PortUtils.resolveFirstFixedIps(port);
661             if (!potentialPortIpWithSubnet.isPresent()) {
662                 LOG.warn("Illegal state - router interface port does not contain fixed IPs {}", port);
663                 return;
664             }
665             FixedIps portIpWithSubnet = potentialPortIpWithSubnet.get();
666             L3ContextId l3Context = new L3ContextId(port.getNetworkId().getValue());
667             // change L3Context for all new EPs with same subnet as router port
668             changeL3ContextForEpsInSubnet(portIpWithSubnet.getSubnetId(), port.getNetworkId(),
669                     new Uuid(port.getDeviceId()), newNeutron, false);
670             // set L3Context as parent for bridge domain which is parent of subnet
671             TenantId tenantId = new TenantId(port.getTenantId().getValue());
672             Optional<Subnet> potentialRouterPortSubnet =
673                     SubnetUtils.findSubnet(portIpWithSubnet.getSubnetId(), oldNeutron.getSubnets());
674             if (!potentialRouterPortSubnet.isPresent()) {
675                 LOG.warn("Illegal state - router interface port is in subnet which does not exist. {}", port);
676                 return;
677             }
678             ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
679             Subnet routerPortSubnet = potentialRouterPortSubnet.get();
680             modifyForwardingOnDelete(routerPortSubnet, l3Context, tenantId, rwTx);
681             ContextId l2BdId = new ContextId(routerPortSubnet.getNetworkId().getValue());
682             ForwardingContext fwdCtx = new ForwardingContextBuilder().setContextId(l2BdId)
683                 .setContextType(MappingUtils.L2_BRDIGE_DOMAIN)
684                 .setParent(MappingUtils.createParent(l3Context, MappingUtils.L3_CONTEXT))
685                 .build();
686             rwTx.merge(LogicalDatastoreType.CONFIGURATION,
687                     L2L3IidFactory.l2BridgeDomainIid(tenantId, fwdCtx.getContextId()), fwdCtx);
688             NetworkDomain subnet = NeutronSubnetAware.createSubnet(routerPortSubnet, newNeutron, null);
689             rwTx.put(LogicalDatastoreType.CONFIGURATION,
690                     L2L3IidFactory.subnetIid(tenantId, subnet.getNetworkDomainId()), subnet);
691             unregisterEndpointAndRemoveMapping(createUnregisterEndpointInput(port, oldNeutron), port, rwTx);
692             unregisterEndpointAndRemoveMapping(createUnregisterBaseEndpointInput(port, oldNeutron), port, rwTx,
693                     removeBaseEpMapping);
694             DataStoreHelper.submitToDs(rwTx);
695         } else if (PortUtils.isDhcpPort(port)) {
696             LOG.trace("Port is DHCP port: {}", port.getUuid().getValue());
697             ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
698             unregisterEndpointAndRemoveMapping(createUnregisterEndpointInput(port, oldNeutron), port, rwTx);
699             unregisterEndpointAndRemoveMapping(createUnregisterBaseEndpointInput(port, oldNeutron), port, rwTx,
700                     removeBaseEpMapping);
701             DataStoreHelper.submitToDs(rwTx);
702             if (!oldNeutron.getPorts()
703                 .getPort()
704                 .stream()
705                 .filter(PortUtils::isDhcpPort)
706                 .anyMatch(p -> !p.getUuid().equals(port.getUuid()))) {
707                 Port metadataPort = cloneMetadataPortFromDhcpPort(port, metadataIpPrefix);
708                 if (PortUtils.resolveFirstFixedIps(metadataPort).isPresent()) {
709                     ContextId metadataCtx = resolveL3ContextForPort(metadataPort,
710                             PortUtils.resolveFirstFixedIps(metadataPort).get(), oldNeutron);
711                     AddressEndpointUnregBuilder metadataEpUnreg =
712                             new AddressEndpointUnregBuilder().setAddress(String.valueOf(metadataIpPrefix.getValue()))
713                                 .setAddressType(IpPrefixType.class)
714                                 .setContextType(MappingUtils.L3_CONTEXT)
715                                 .setContextId(metadataCtx);
716                     epRegistrator.unregisterEndpoint(metadataEpUnreg.build());
717                 }
718             }
719         } else if (PortUtils.isNormalPort(port)) {
720             LOG.trace("Port is normal port: {}", port.getUuid().getValue());
721             ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
722             unregisterEndpointAndRemoveMapping(createUnregisterEndpointInput(port, oldNeutron), port, rwTx);
723             unregisterEndpointAndRemoveMapping(createUnregisterBaseEndpointInput(port, oldNeutron), port, rwTx,
724                     removeBaseEpMapping);
725             DataStoreHelper.submitToDs(rwTx);
726         } else if (PortUtils.isRouterGatewayPort(port)) {
727             // do nothing because actual trigger is detaching of port from router
728             LOG.trace("Port is router gateway port: {}", port.getUuid().getValue());
729         } else if (PortUtils.isFloatingIpPort(port)) {
730             // do nothing because trigger is floating IP
731             LOG.trace("Port is floating ip: {}", port.getUuid().getValue());
732         } else {
733             LOG.warn("Unknown port: {}", port);
734         }
735     }
736
737     @Deprecated
738     @SuppressWarnings("checkstyle:LineLength") // Longer lines in this method are caused by long package names,
739                                                // this will be removed when deprecated classes will be cleared.
740     private void modifyForwardingOnDelete(Subnet routerPortSubnet, L3ContextId l3contextId, TenantId tenantId,
741             ReadWriteTransaction rwTx) {
742         L2BridgeDomainId l2BdId = new L2BridgeDomainId(routerPortSubnet.getNetworkId().getValue());
743         L2BridgeDomain l2Bd = new L2BridgeDomainBuilder().setId(l2BdId).setParent(l3contextId).build();
744         rwTx.merge(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BdId), l2Bd);
745         // remove virtual router IP for subnet
746         org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet tenantSubnet =
747                 NeutronSubnetAware.createTenantSubnet(routerPortSubnet, null);
748         rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, tenantSubnet.getId()),
749                 tenantSubnet);
750     }
751
752     @SuppressWarnings("checkstyle:LineLength") // Longer lines in this method are caused by long package names,
753                                                // this will be removed when deprecated classes will be cleared.
754     private org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.UnregisterEndpointInput createUnregisterBaseEndpointInput(
755             Port port, Neutron neutron) {
756         List<AddressEndpointUnreg> list = new ArrayList<>();
757         AddressEndpointUnregBuilder addrL2EpUnregBuilder = new AddressEndpointUnregBuilder();
758         addrL2EpUnregBuilder.setAddress(port.getMacAddress().getValue())
759             .setAddressType(MacAddressType.class)
760             .setContextId(new ContextId(port.getNetworkId().getValue()))
761             .setContextType(MappingUtils.L2_BRDIGE_DOMAIN);
762         list.add(addrL2EpUnregBuilder.build());
763         Optional<FixedIps> potentialFirstIp = PortUtils.resolveFirstFixedIps(port);
764         if (potentialFirstIp.isPresent()) {
765             ContextId l3ContextId = resolveL3ContextForPort(port, potentialFirstIp.get(), neutron);
766             AddressEndpointUnregBuilder addrL3EpUnregBuilder = new AddressEndpointUnregBuilder();
767             addrL3EpUnregBuilder
768                 .setAddress(MappingUtils.ipAddressToStringIpPrefix(potentialFirstIp.get().getIpAddress()))
769                 .setAddressType(IpPrefixType.class)
770                 .setContextId(l3ContextId)
771                 .setContextType(L3Context.class);
772             list.add(addrL3EpUnregBuilder.build());
773         }
774         UnregisterEndpointInputBuilder inputBuilder = new UnregisterEndpointInputBuilder();
775         inputBuilder.setAddressEndpointUnreg(list);
776         return inputBuilder.build();
777     }
778
779     @Deprecated
780     @SuppressWarnings("checkstyle:LineLength") // Longer lines in this method are caused by long package names,
781                                                // this will be removed when deprecated classes will be cleared.
782     private org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInput createUnregisterEndpointInput(
783             Port port, Neutron neutron) {
784         org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInputBuilder inputBuilder =
785                 new org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInputBuilder();
786         L2 l2Ep = new L2Builder().setL2Context(new L2BridgeDomainId(port.getNetworkId().getValue()))
787             .setMacAddress(new MacAddress(port.getMacAddress().getValue()))
788             .build();
789         inputBuilder.setL2(ImmutableList.of(l2Ep));
790         // we've registered EP with only first IP so remove only EP with first IP
791         Optional<FixedIps> potentialFirstIp = PortUtils.resolveFirstFixedIps(port);
792         if (potentialFirstIp.isPresent()) {
793             FixedIps firstIp = potentialFirstIp.get();
794             L3Address l3Address = resolveL3AddressFromPort(port, firstIp, neutron);
795             L3 l3 = new L3Builder().setIpAddress(l3Address.getIpAddress())
796                 .setL3Context(l3Address.getL3Context())
797                 .build();
798             inputBuilder.setL3(ImmutableList.of(l3));
799         }
800         return inputBuilder.build();
801     }
802
803     @Deprecated
804     private static L3Address resolveL3AddressFromPort(Port port, FixedIps portFixedIPs, Neutron neutron) {
805         Set<Port> routerIfacePorts = PortUtils.findRouterInterfacePorts(neutron.getPorts());
806         for (Port routerIfacePort : routerIfacePorts) {
807             Uuid routerIfacePortSubnet = routerIfacePort.getFixedIps().get(0).getSubnetId();
808             // if port is in the same subnet as router interface then we want to use L3Context of
809             // router
810             if (portFixedIPs.getSubnetId().equals(routerIfacePortSubnet)) {
811                 L3ContextId epL3ContextId = new L3ContextId(routerIfacePort.getDeviceId());
812                 LOG.trace("Router interface port was found in the same subnet as port have {}", port);
813                 return new L3AddressBuilder().setL3Context(epL3ContextId)
814                     .setIpAddress(portFixedIPs.getIpAddress())
815                     .build();
816             }
817         }
818         return new L3AddressBuilder().setL3Context(new L3ContextId(port.getNetworkId().getValue()))
819             .setIpAddress(portFixedIPs.getIpAddress())
820             .build();
821     }
822
823     private static ContextId resolveL3ContextForPort(Port port, FixedIps portFixedIPs, Neutron neutron) {
824         Set<Port> routerIfacePorts = PortUtils.findRouterInterfacePorts(neutron.getPorts());
825         for (Port routerIfacePort : routerIfacePorts) {
826             Uuid routerIfacePortSubnet = routerIfacePort.getFixedIps().get(0).getSubnetId();
827             // if port is in the same subnet as router interface then we want to use L3Context of
828             // router
829             if (portFixedIPs.getSubnetId().equals(routerIfacePortSubnet)) {
830                 LOG.trace("Router interface port was found in the same subnet as port have {}", port);
831                 return new ContextId(routerIfacePort.getDeviceId());
832             }
833         }
834         return new ContextId(port.getNetworkId().getValue());
835     }
836 }