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