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