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