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