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