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