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