Implementation of INeutronFloatingIPAware introduced
[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.Collection;
14 import java.util.HashSet;
15 import java.util.List;
16 import java.util.Set;
17 import java.util.concurrent.ExecutionException;
18
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
21 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
22 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.DataStoreHelper;
25 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.IidFactory;
26 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
27 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils.ForwardingCtx;
28 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.NeutronUtils;
29 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.Utils;
30 import org.opendaylight.neutron.spi.INeutronPortAware;
31 import org.opendaylight.neutron.spi.NeutronPort;
32 import org.opendaylight.neutron.spi.NeutronSecurityGroup;
33 import org.opendaylight.neutron.spi.NeutronSecurityRule;
34 import org.opendaylight.neutron.spi.Neutron_IPs;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.UniqueId;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInput;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInput;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInputBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3AddressBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointKey;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L2;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L2Builder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3Builder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.endpoints.by.ports.EndpointByPort;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.endpoints.by.ports.EndpointByPortBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.ports.by.endpoints.PortByEndpoint;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.ports.by.endpoints.PortByEndpointBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextInput;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextInputBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Subnet;
65 import org.opendaylight.yangtools.yang.common.RpcResult;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
68
69 import com.google.common.base.Function;
70 import com.google.common.base.Optional;
71 import com.google.common.base.Strings;
72 import com.google.common.collect.Collections2;
73 import com.google.common.collect.ImmutableList;
74
75 public class NeutronPortAware implements INeutronPortAware {
76
77     public static final Logger LOG = LoggerFactory.getLogger(NeutronPortAware.class);
78     private static final String DEVICE_OWNER_DHCP = "network:dhcp";
79     private static final String DEVICE_OWNER_ROUTER_IFACE = "network:router_interface";
80     private static final String DEVICE_OWNER_ROUTER_GATEWAY = "network:router_gateway";
81     private static final String DEVICE_OWNER_FLOATING_IP = "network:floatingip";
82     private static final int DHCP_CLIENT_PORT = 68;
83     private static final int DHCP_SERVER_PORT = 67;
84     private final DataBroker dataProvider;
85     private final EndpointService epService;
86
87     public NeutronPortAware(DataBroker dataProvider, EndpointService epService) {
88         this.dataProvider = checkNotNull(dataProvider);
89         this.epService = checkNotNull(epService);
90     }
91
92     /**
93      * @see org.opendaylight.neutron.spi.INeutronPortAware#canCreatePort(org.opendaylight.neutron.spi.NeutronPort)
94      */
95     @Override
96     public int canCreatePort(NeutronPort port) {
97         LOG.trace("canCreatePort - {}", port);
98         // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
99         List<Neutron_IPs> fixedIPs = port.getFixedIPs();
100         if (fixedIPs != null && fixedIPs.size() > 1) {
101             LOG.warn("Neutron mapper does not support multiple IPs on the same port.");
102             return StatusCode.BAD_REQUEST;
103         }
104         return StatusCode.OK;
105     }
106
107     /**
108      * @see org.opendaylight.neutron.spi.INeutronPortAware#neutronPortCreated(org.opendaylight.neutron.spi.NeutronPort)
109      */
110     @Override
111     public void neutronPortCreated(NeutronPort port) {
112         LOG.trace("neutronPortCreated - {}", port);
113         if (isRouterInterfacePort(port)) {
114             LOG.trace("Port is router interface - {} does nothing. {} handles router iface.",
115                     NeutronPortAware.class.getSimpleName(), NeutronRouterAware.class.getSimpleName());
116             return;
117         }
118         if (isRouterGatewayPort(port)) {
119             LOG.trace("Port is router gateway - {}", port.getID());
120             return;
121         }
122         if (isFloatingIp(port)) {
123             LOG.trace("Port is floating ip - {}", port.getID());
124             return;
125         }
126         if (Strings.isNullOrEmpty(port.getTenantID())) {
127             LOG.trace("REMOVE ME: Tenant is null - {}", port.getID());
128             return;
129         }
130         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
131         TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
132         if (isDhcpPort(port)) {
133             LOG.trace("Port is DHCP port. - {}", port.getID());
134             List<NeutronSecurityRule> dhcpSecRules = createDhcpSecRules(port, null, rwTx);
135             if (dhcpSecRules == null) {
136                 rwTx.cancel();
137                 return;
138             }
139
140             for (NeutronSecurityRule dhcpSecRule : dhcpSecRules) {
141                 boolean isDhcpSecRuleAdded = NeutronSecurityRuleAware.addNeutronSecurityRule(dhcpSecRule, rwTx);
142                 if (!isDhcpSecRuleAdded) {
143                     rwTx.cancel();
144                     return;
145                 }
146             }
147         } else {
148             List<NeutronSecurityGroup> secGroups = port.getSecurityGroups();
149             if (secGroups != null) {
150                 for (NeutronSecurityGroup secGroup : secGroups) {
151                     EndpointGroupId epgId = new EndpointGroupId(secGroup.getSecurityGroupUUID());
152                     Optional<EndpointGroup> potentialEpg = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
153                             IidFactory.endpointGroupIid(tenantId, epgId), rwTx);
154                     if (!potentialEpg.isPresent()) {
155                         boolean isSecGroupCreated = NeutronSecurityGroupAware.addNeutronSecurityGroup(secGroup, rwTx);
156                         if (!isSecGroupCreated) {
157                             rwTx.cancel();
158                             return;
159                         }
160                         if (containsSecRuleWithRemoteSecGroup(secGroup)) {
161                             List<NeutronSecurityRule> dhcpSecRules = createDhcpSecRules(port, epgId, rwTx);
162                             if (dhcpSecRules == null) {
163                                 rwTx.cancel();
164                                 return;
165                             }
166                             List<NeutronSecurityRule> routerSecRules = NeutronRouterAware.createRouterSecRules(port, epgId, rwTx);
167                             if (routerSecRules == null) {
168                                 rwTx.cancel();
169                                 return;
170                             }
171                         }
172                     } else {
173                         List<NeutronSecurityRule> secRules = secGroup.getSecurityRules();
174                         if (secRules != null) {
175                             for (NeutronSecurityRule secRule : secRules) {
176                                 NeutronSecurityRuleAware.addNeutronSecurityRule(secRule, rwTx);
177                             }
178                         }
179                     }
180                 }
181             }
182         }
183
184         boolean isNeutronPortCreated = addNeutronPort(port, rwTx, epService);
185         if (!isNeutronPortCreated) {
186             rwTx.cancel();
187             return;
188         }
189
190         DataStoreHelper.submitToDs(rwTx);
191     }
192
193     public static boolean addNeutronPort(NeutronPort port, ReadWriteTransaction rwTx, EndpointService epService) {
194         TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
195         L2FloodDomainId l2FdId = new L2FloodDomainId(port.getNetworkUUID());
196         ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
197         boolean isFwCtxValid = validateForwardingCtx(fwCtx);
198         if (!isFwCtxValid) {
199             return false;
200         }
201         EndpointKey epKey = new EndpointKey(fwCtx.getL2BridgeDomain().getId(), new MacAddress(port.getMacAddress()));
202         UniqueId portId = new UniqueId(port.getID());
203         EndpointByPort endpointByPort = createEndpointByPort(epKey, portId);
204         rwTx.put(LogicalDatastoreType.OPERATIONAL, IidFactory.endpointByPortIid(portId), endpointByPort);
205         PortByEndpoint portByEndpoint = createPortByEndpoint(portId, epKey);
206         rwTx.put(LogicalDatastoreType.OPERATIONAL,
207                 IidFactory.portByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()), portByEndpoint);
208
209         try {
210             RegisterEndpointInput registerEpRpcInput = createRegisterEndpointInput(port, fwCtx);
211
212             RpcResult<Void> rpcResult = epService.registerEndpoint(registerEpRpcInput).get();
213             if (!rpcResult.isSuccessful()) {
214                 LOG.warn("Illegal state - RPC registerEndpoint failed. Input of RPC: {}", registerEpRpcInput);
215                 return false;
216             }
217         } catch (InterruptedException | ExecutionException e) {
218             LOG.error("addPort - RPC invocation failed.", e);
219             return false;
220         }
221         return true;
222     }
223
224     private static boolean validateForwardingCtx(ForwardingCtx fwCtx) {
225         if (fwCtx.getL2FloodDomain() == null) {
226             LOG.warn("Illegal state - l2-flood-domain does not exist.");
227             return false;
228         }
229         if (fwCtx.getL2BridgeDomain() == null) {
230             LOG.warn("Illegal state - l2-bridge-domain does not exist.");
231             return false;
232         }
233         if (fwCtx.getL3Context() == null) {
234             LOG.warn("Illegal state - l3-context does not exist.");
235             return false;
236         }
237         return true;
238     }
239
240     private static EndpointByPort createEndpointByPort(EndpointKey epKey, UniqueId portId) {
241         return new EndpointByPortBuilder().setPortId(portId)
242             .setL2Context(epKey.getL2Context())
243             .setMacAddress(epKey.getMacAddress())
244             .build();
245     }
246
247     private static PortByEndpoint createPortByEndpoint(UniqueId portId, EndpointKey epKey) {
248         return new PortByEndpointBuilder().setPortId(portId)
249             .setL2Context(epKey.getL2Context())
250             .setMacAddress(epKey.getMacAddress())
251             .build();
252     }
253
254     private List<NeutronSecurityRule> createDhcpSecRules(NeutronPort port, EndpointGroupId consumerEpgId, ReadTransaction rTx) {
255         TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
256         Neutron_IPs firstIp = MappingUtils.getFirstIp(port.getFixedIPs());
257         if (firstIp == null) {
258             LOG.warn("Illegal state - DHCP port does not have an IP address.");
259             return null;
260         }
261         SubnetId dhcpSubnetId = new SubnetId(firstIp.getSubnetUUID());
262         Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
263                 IidFactory.subnetIid(tenantId, dhcpSubnetId), rTx);
264         if (!potentialSubnet.isPresent()) {
265             LOG.warn("Illegal state - Subnet {} where is DHCP port does not exist.", dhcpSubnetId.getValue());
266             return null;
267         }
268         IpPrefix ipSubnet = potentialSubnet.get().getIpPrefix();
269         NeutronSecurityRule dhcpRuleEgress = createDhcpSecRule(port.getID(), tenantId, ipSubnet, consumerEpgId, true);
270         NeutronSecurityRule dhcpRuleIngress = createDhcpSecRule(port.getID(), tenantId, ipSubnet, consumerEpgId, false);
271         return ImmutableList.of(dhcpRuleEgress, dhcpRuleIngress);
272     }
273
274     private NeutronSecurityRule createDhcpSecRule(String ruleUuid, TenantId tenantId, IpPrefix ipSubnet, EndpointGroupId consumerEpgId,
275             boolean isEgress) {
276         NeutronSecurityRule dhcpSecRule = new NeutronSecurityRule();
277         dhcpSecRule.setSecurityRuleGroupID(MappingUtils.EPG_DHCP_ID.getValue());
278         dhcpSecRule.setSecurityRuleTenantID(tenantId.getValue());
279         dhcpSecRule.setSecurityRuleRemoteIpPrefix(Utils.getStringIpPrefix(ipSubnet));
280         if (consumerEpgId != null) {
281             dhcpSecRule.setSecurityRemoteGroupID(consumerEpgId.getValue());
282         }
283         if (isEgress) {
284             dhcpSecRule.setSecurityRuleUUID(NeutronUtils.EGRESS + "__" + ruleUuid);
285             dhcpSecRule.setSecurityRuleDirection(NeutronUtils.EGRESS);
286             dhcpSecRule.setSecurityRulePortMin(DHCP_CLIENT_PORT);
287             dhcpSecRule.setSecurityRulePortMax(DHCP_CLIENT_PORT);
288         } else {
289             dhcpSecRule.setSecurityRuleUUID(NeutronUtils.INGRESS + "__" + ruleUuid);
290             dhcpSecRule.setSecurityRuleDirection(NeutronUtils.INGRESS);
291             dhcpSecRule.setSecurityRulePortMin(DHCP_SERVER_PORT);
292             dhcpSecRule.setSecurityRulePortMax(DHCP_SERVER_PORT);
293         }
294         dhcpSecRule.setSecurityRuleProtocol(NeutronUtils.UDP);
295         if (ipSubnet.getIpv4Prefix() != null) {
296             dhcpSecRule.setSecurityRuleEthertype(NeutronUtils.IPv4);
297         } else {
298             dhcpSecRule.setSecurityRuleEthertype(NeutronUtils.IPv6);
299         }
300         return dhcpSecRule;
301     }
302
303     /**
304      * @see org.opendaylight.neutron.spi.INeutronPortAware#canUpdatePort(org.opendaylight.neutron.spi.NeutronPort,
305      *      org.opendaylight.neutron.spi.NeutronPort)
306      */
307     @Override
308     public int canUpdatePort(NeutronPort delta, NeutronPort original) {
309         LOG.trace("canUpdatePort - delta: {} original: {}", delta, original);
310         if (delta.getFixedIPs() == null || delta.getFixedIPs().isEmpty()) {
311             return StatusCode.OK;
312         }
313         // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
314         List<Neutron_IPs> fixedIPs = delta.getFixedIPs();
315         if (fixedIPs != null && fixedIPs.size() > 1) {
316             LOG.warn("Neutron mapper does not support multiple IPs on the same port.");
317             return StatusCode.BAD_REQUEST;
318         }
319         return StatusCode.OK;
320     }
321
322     /**
323      * @see org.opendaylight.neutron.spi.INeutronPortAware#neutronPortUpdated(org.opendaylight.neutron.spi.NeutronPort)
324      */
325     @Override
326     public void neutronPortUpdated(NeutronPort port) {
327         LOG.trace("neutronPortUpdated - {}", port);
328         if (isRouterInterfacePort(port)) {
329             LOG.trace("Port is router interface - {} does nothing. {} handles router iface.",
330                     NeutronPortAware.class.getSimpleName(), NeutronRouterAware.class.getSimpleName());
331             return;
332         }
333         if (isRouterGatewayPort(port)) {
334             LOG.trace("Port is router gateway - {}", port.getID());
335             return;
336         }
337         if (isFloatingIp(port)) {
338             LOG.trace("Port is floating ip - {}", port.getID());
339             return;
340         }
341         if (Strings.isNullOrEmpty(port.getTenantID())) {
342             LOG.trace("REMOVE ME: Tenant is null - {}", port.getID());
343             return;
344         }
345
346         ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction();
347         TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
348         MacAddress macAddress = new MacAddress(port.getMacAddress());
349         L2FloodDomainId l2FdId = new L2FloodDomainId(port.getNetworkUUID());
350         ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rTx);
351         boolean isFwCtxValid = validateForwardingCtx(fwCtx);
352         if (!isFwCtxValid) {
353             rTx.close();
354             return;
355         }
356
357         Optional<Endpoint> potentionalEp = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
358                 IidFactory.endpointIid(fwCtx.getL2BridgeDomain().getId(), macAddress), rTx);
359         if (!potentionalEp.isPresent()) {
360             LOG.warn("Illegal state - endpoint {} does not exist.", new EndpointKey(fwCtx.getL2BridgeDomain().getId(),
361                     macAddress));
362             rTx.close();
363             return;
364         }
365
366         Endpoint ep = potentionalEp.get();
367         if (isEpIpDifferentThanPortFixedIp(ep, port) || isEpgDifferentThanSecGrp(ep, port)) {
368             UnregisterEndpointInput unregisterEpRpcInput = createUnregisterEndpointInput(ep);
369             RegisterEndpointInput registerEpRpcInput = createRegisterEndpointInput(port, fwCtx);
370             try {
371                 RpcResult<Void> rpcResult = epService.unregisterEndpoint(unregisterEpRpcInput).get();
372                 if (!rpcResult.isSuccessful()) {
373                     LOG.warn("Illegal state - RPC unregisterEndpoint failed. Input of RPC: {}", unregisterEpRpcInput);
374                     rTx.close();
375                     return;
376                 }
377                 rpcResult = epService.registerEndpoint(registerEpRpcInput).get();
378                 if (!rpcResult.isSuccessful()) {
379                     LOG.warn("Illegal state - RPC registerEndpoint failed. Input of RPC: {}", registerEpRpcInput);
380                     rTx.close();
381                     return;
382                 }
383             } catch (InterruptedException | ExecutionException e) {
384                 LOG.error("addPort - RPC invocation failed.", e);
385                 rTx.close();
386                 return;
387             }
388         }
389         rTx.close();
390     }
391
392     private boolean isEpIpDifferentThanPortFixedIp(Endpoint ep, NeutronPort port) {
393         List<L3Address> l3Addresses = ep.getL3Address();
394         List<Neutron_IPs> fixedIPs = port.getFixedIPs();
395         if ((l3Addresses == null || l3Addresses.isEmpty()) && (fixedIPs == null || fixedIPs.isEmpty())) {
396             return false;
397         }
398         if (l3Addresses != null && !l3Addresses.isEmpty() && fixedIPs != null && !fixedIPs.isEmpty()) {
399             if (fixedIPs.get(0).getIpAddress().equals(Utils.getStringIpAddress(l3Addresses.get(0).getIpAddress()))) {
400                 return false;
401             }
402         }
403         return true;
404     }
405
406     private boolean isEpgDifferentThanSecGrp(Endpoint ep, NeutronPort port) {
407         List<EndpointGroupId> epgIds = ep.getEndpointGroups();
408         List<NeutronSecurityGroup> secGroups = port.getSecurityGroups();
409         if ((epgIds == null || epgIds.isEmpty()) && (secGroups == null || secGroups.isEmpty())) {
410             return false;
411         }
412         if (epgIds != null && !epgIds.isEmpty() && secGroups != null && !secGroups.isEmpty()) {
413             if (epgIds.size() != secGroups.size()) {
414                 return true;
415             }
416             Collection<EndpointGroupId> epgIdsFromSecGroups = Collections2.transform(secGroups,
417                     new Function<NeutronSecurityGroup, EndpointGroupId>() {
418
419                         @Override
420                         public EndpointGroupId apply(NeutronSecurityGroup input) {
421                             return new EndpointGroupId(input.getSecurityGroupUUID());
422                         }
423                     });
424             // order independent equals
425             Set<EndpointGroupId> one = new HashSet<>(epgIds);
426             Set<EndpointGroupId> two = new HashSet<>(epgIdsFromSecGroups);
427             if (one.equals(two)) {
428                 return false;
429             }
430         }
431         return true;
432     }
433
434     /**
435      * @see org.opendaylight.neutron.spi.INeutronPortAware#canDeletePort(org.opendaylight.neutron.spi.NeutronPort)
436      */
437     @Override
438     public int canDeletePort(NeutronPort port) {
439         LOG.trace("canDeletePort - {}", port);
440         // nothing to consider
441         return StatusCode.OK;
442     }
443
444     /**
445      * @see org.opendaylight.neutron.spi.INeutronPortAware#neutronPortDeleted(org.opendaylight.neutron.spi.NeutronPort)
446      */
447     @Override
448     public void neutronPortDeleted(NeutronPort port) {
449         LOG.trace("neutronPortDeleted - {}", port);
450         if (isRouterInterfacePort(port)) {
451             LOG.trace("Port is router interface - {} does nothing. {} handles router iface.",
452                     NeutronPortAware.class.getSimpleName(), NeutronRouterAware.class.getSimpleName());
453             return;
454         }
455         ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction();
456         TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
457         L2FloodDomainId l2FdId = new L2FloodDomainId(port.getNetworkUUID());
458         ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rTx);
459         boolean isFwCtxValid = validateForwardingCtx(fwCtx);
460         if (!isFwCtxValid) {
461             rTx.close();
462             return;
463         }
464
465         UnregisterEndpointInput unregisterEpRpcInput = createUnregisterEndpointInput(port, fwCtx);
466         try {
467             RpcResult<Void> rpcResult = epService.unregisterEndpoint(unregisterEpRpcInput).get();
468             if (!rpcResult.isSuccessful()) {
469                 LOG.warn("Illegal state - RPC unregisterEndpoint failed. Input of RPC: {}", unregisterEpRpcInput);
470             }
471         } catch (InterruptedException | ExecutionException e) {
472             LOG.error("addPort - RPC invocation failed.", e);
473         } finally {
474             rTx.close();
475         }
476     }
477
478     private static RegisterEndpointInput createRegisterEndpointInput(NeutronPort port, ForwardingCtx fwCtx) {
479         List<EndpointGroupId> epgIds = new ArrayList<>();
480         // each EP has to be in EPG ANY, except dhcp and router
481         if (isDhcpPort(port)) {
482             epgIds.add(MappingUtils.EPG_DHCP_ID);
483         } else if (!containsSecRuleWithRemoteSecGroup(port.getSecurityGroups())) {
484             epgIds.add(MappingUtils.EPG_ANY_ID);
485         }
486
487         List<NeutronSecurityGroup> securityGroups = port.getSecurityGroups();
488         if ((securityGroups == null || securityGroups.isEmpty())) {
489             if (!isDhcpPort(port)) {
490                 LOG.warn(
491                         "Port {} does not contain any security group. The port should belong to 'default' security group at least.",
492                         port.getPortUUID());
493             }
494         } else {
495             for (NeutronSecurityGroup secGrp : securityGroups) {
496                 epgIds.add(new EndpointGroupId(secGrp.getSecurityGroupUUID()));
497             }
498         }
499         RegisterEndpointInputBuilder inputBuilder = new RegisterEndpointInputBuilder().setL2Context(
500                 fwCtx.getL2BridgeDomain().getId())
501             .setMacAddress(new MacAddress(port.getMacAddress()))
502             .setTenant(new TenantId(Utils.normalizeUuid(port.getTenantID())))
503             .setEndpointGroups(epgIds)
504             .addAugmentation(OfOverlayContextInput.class,
505                     new OfOverlayContextInputBuilder().setPortName(createTapPortName(port)).build())
506             .setTimestamp(System.currentTimeMillis());
507         List<Neutron_IPs> fixedIPs = port.getFixedIPs();
508         // TODO Li msunal this getting of just first IP has to be rewrite when OFOverlay renderer
509         // will support l3-endpoints. Then we will register L2 and L3 endpoints separately.
510         Neutron_IPs firstIp = MappingUtils.getFirstIp(fixedIPs);
511         if (firstIp != null) {
512             inputBuilder.setNetworkContainment(new SubnetId(firstIp.getSubnetUUID()));
513             L3Address l3Address = new L3AddressBuilder().setIpAddress(Utils.createIpAddress(firstIp.getIpAddress()))
514                 .setL3Context(fwCtx.getL3Context().getId())
515                 .build();
516             inputBuilder.setL3Address(ImmutableList.of(l3Address));
517         }
518         if (!Strings.isNullOrEmpty(port.getName())) {
519
520         }
521         return inputBuilder.build();
522     }
523
524     private static boolean containsSecRuleWithRemoteSecGroup(List<NeutronSecurityGroup> secGroups) {
525         if (secGroups == null) {
526             return false;
527         }
528         for (NeutronSecurityGroup secGroup : secGroups) {
529             boolean containsSecRuleWithRemoteSecGroup = containsSecRuleWithRemoteSecGroup(secGroup);
530             if (containsSecRuleWithRemoteSecGroup) {
531                 return true;
532             }
533         }
534         return false;
535     }
536
537     private static boolean containsSecRuleWithRemoteSecGroup(NeutronSecurityGroup secGroup) {
538         List<NeutronSecurityRule> secRules = secGroup.getSecurityRules();
539         if (secRules == null) {
540             return false;
541         }
542         for (NeutronSecurityRule secRule : secRules) {
543             if (!Strings.isNullOrEmpty(secRule.getSecurityRemoteGroupID())) {
544                 return true;
545             }
546         }
547         return false;
548     }
549
550     private static Name createTapPortName(NeutronPort port) {
551         return new Name("tap" + port.getID().substring(0, 11));
552     }
553
554     private static boolean isDhcpPort(NeutronPort port) {
555         return DEVICE_OWNER_DHCP.equals(port.getDeviceOwner());
556     }
557
558     private static boolean isRouterInterfacePort(NeutronPort port) {
559         return DEVICE_OWNER_ROUTER_IFACE.equals(port.getDeviceOwner());
560     }
561
562     private static boolean isRouterGatewayPort(NeutronPort port) {
563         return DEVICE_OWNER_ROUTER_GATEWAY.equals(port.getDeviceOwner());
564     }
565
566     private static boolean isFloatingIp(NeutronPort port) {
567         return DEVICE_OWNER_FLOATING_IP.equals(port.getDeviceOwner());
568     }
569
570     private UnregisterEndpointInput createUnregisterEndpointInput(Endpoint ep) {
571         UnregisterEndpointInputBuilder inputBuilder = new UnregisterEndpointInputBuilder();
572         L2 l2Ep = new L2Builder().setL2Context(ep.getL2Context()).setMacAddress(ep.getMacAddress()).build();
573         inputBuilder.setL2(ImmutableList.of(l2Ep));
574         // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
575         // Endpoint probably will not have l3-addresses anymore, because L2 and L3 endpoints should
576         // be registered separately.
577         if (ep.getL3Address() != null && !ep.getL3Address().isEmpty()) {
578             List<L3> l3Eps = new ArrayList<>();
579             for (L3Address ip : ep.getL3Address()) {
580                 l3Eps.add(new L3Builder().setL3Context(ip.getL3Context()).setIpAddress(ip.getIpAddress()).build());
581             }
582             inputBuilder.setL3(l3Eps);
583         }
584         return inputBuilder.build();
585     }
586
587     private UnregisterEndpointInput createUnregisterEndpointInput(NeutronPort port, ForwardingCtx fwCtx) {
588         UnregisterEndpointInputBuilder inputBuilder = new UnregisterEndpointInputBuilder();
589         L2 l2Ep = new L2Builder().setL2Context(fwCtx.getL2BridgeDomain().getId())
590             .setMacAddress(new MacAddress(port.getMacAddress()))
591             .build();
592         inputBuilder.setL2(ImmutableList.of(l2Ep));
593         // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
594         // Endpoint probably will not have l3-addresses anymore, because L2 and L3 endpoints should
595         // be registered separately.
596         if (port.getFixedIPs() != null && !port.getFixedIPs().isEmpty()) {
597             inputBuilder.setL3(createL3s(port.getFixedIPs(), fwCtx.getL3Context().getId()));
598         }
599         return inputBuilder.build();
600     }
601
602     private List<L3> createL3s(List<Neutron_IPs> neutronIps, L3ContextId l3ContextId) {
603         List<L3> l3s = new ArrayList<>();
604         for (Neutron_IPs fixedIp : neutronIps) {
605             String ip = fixedIp.getIpAddress();
606             L3 l3 = new L3Builder().setIpAddress(Utils.createIpAddress(ip)).setL3Context(l3ContextId).build();
607             l3s.add(l3);
608         }
609         return l3s;
610     }
611
612 }