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