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