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