Leaving deprecated API in 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.ReadWriteTransaction;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.groupbasedpolicy.neutron.gbp.util.NeutronGbpIidFactory;
24 import org.opendaylight.groupbasedpolicy.neutron.mapper.infrastructure.NetworkClient;
25 import org.opendaylight.groupbasedpolicy.neutron.mapper.infrastructure.NetworkService;
26 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.group.NeutronSecurityGroupAware;
27 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.rule.NeutronSecurityRuleAware;
28 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
29 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils.ForwardingCtx;
30 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.Utils;
31 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
32 import org.opendaylight.groupbasedpolicy.util.IidFactory;
33 import org.opendaylight.neutron.spi.NeutronPort;
34 import org.opendaylight.neutron.spi.NeutronPort_AllowedAddressPairs;
35 import org.opendaylight.neutron.spi.NeutronPort_ExtraDHCPOption;
36 import org.opendaylight.neutron.spi.NeutronPort_VIFDetail;
37 import org.opendaylight.neutron.spi.NeutronRouter;
38 import org.opendaylight.neutron.spi.NeutronRouter_Interface;
39 import org.opendaylight.neutron.spi.NeutronSecurityGroup;
40 import org.opendaylight.neutron.spi.NeutronSecurityRule;
41 import org.opendaylight.neutron.spi.Neutron_IPs;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.UniqueId;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInput;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterL3PrefixEndpointInput;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterL3PrefixEndpointInputBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInput;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInputBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3AddressBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.l3.prefix.fields.EndpointL3Gateways;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.l3.prefix.fields.EndpointL3GatewaysBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointKey;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Builder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Key;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3PrefixKey;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L2;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L2Builder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3Builder;
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.neutron.by.gbp.mappings.external.gateways.as.l3.endpoints.ExternalGatewayAsL3Endpoint;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.ports.by.endpoints.PortByEndpoint;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroup;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.binding.attributes.VifDetails;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.AllowedAddressPairs;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.ExtraDhcpOpts;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
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 import com.google.common.collect.Lists;
96
97 public class NeutronPortAware implements MappingProcessor<Port, NeutronPort> {
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
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     @Override
117     public NeutronPort convertToNeutron(Port port) {
118         return toNeutron(port);
119     }
120
121     static NeutronPort toNeutron(Port port) {
122         NeutronPort result = new NeutronPort();
123         result.setAdminStateUp(port.isAdminStateUp());
124         if (port.getAllowedAddressPairs() != null) {
125             List<NeutronPort_AllowedAddressPairs> pairs = new ArrayList<NeutronPort_AllowedAddressPairs>();
126             for (AllowedAddressPairs mdPair : port.getAllowedAddressPairs()) {
127                 NeutronPort_AllowedAddressPairs pair = new NeutronPort_AllowedAddressPairs();
128                 pair.setIpAddress(mdPair.getIpAddress());
129                 pair.setMacAddress(mdPair.getMacAddress());
130                 pairs.add(pair);
131             }
132             result.setAllowedAddressPairs(pairs);
133         }
134         result.setDeviceID(port.getDeviceId());
135         result.setDeviceOwner(port.getDeviceOwner());
136         if (port.getExtraDhcpOpts() != null) {
137             List<NeutronPort_ExtraDHCPOption> options = new ArrayList<NeutronPort_ExtraDHCPOption>();
138             for (ExtraDhcpOpts opt : port.getExtraDhcpOpts()) {
139                 NeutronPort_ExtraDHCPOption arg = new NeutronPort_ExtraDHCPOption();
140                 arg.setName(opt.getOptName());
141                 arg.setValue(opt.getOptValue());
142                 arg.setIpVersion(NeutronSubnetAware.IPV_MAP.get(opt.getIpVersion()));
143                 options.add(arg);
144             }
145             result.setExtraDHCPOptions(options);
146         }
147         if (port.getFixedIps() != null) {
148             List<Neutron_IPs> ips = new ArrayList<Neutron_IPs>();
149             for (FixedIps mdIP : port.getFixedIps()) {
150                 Neutron_IPs ip = new Neutron_IPs();
151                 ip.setIpAddress(String.valueOf(mdIP.getIpAddress().getValue()));
152                 ip.setSubnetUUID(mdIP.getSubnetId().getValue());
153                 ips.add(ip);
154             }
155             result.setFixedIPs(ips);
156         }
157         result.setMacAddress(port.getMacAddress());
158         result.setName(port.getName());
159         result.setNetworkUUID(port.getNetworkId().getValue());
160         if(port.getSecurityGroups() != null) {
161             result.setSecurityGroups(Lists.transform(port.getSecurityGroups(),
162                 new Function<Uuid, NeutronSecurityGroup>() {
163
164                     @Override
165                     public NeutronSecurityGroup apply(Uuid uuid) {
166                         NeutronSecurityGroup sg = new NeutronSecurityGroup();
167                         sg.setID(uuid.getValue());
168                         return sg;
169                     }
170                 }));
171         }
172         result.setStatus(port.getStatus());
173         if (port.getTenantId() != null) {
174             result.setTenantID(port.getTenantId());
175         }
176         result.setID(port.getUuid().getValue());
177         addExtensions(port, result);
178         return result;
179     }
180
181     protected static void addExtensions(Port port, NeutronPort result) {
182         PortBindingExtension binding = port.getAugmentation(PortBindingExtension.class);
183         result.setBindinghostID(binding.getHostId());
184         if (binding.getVifDetails() != null) {
185             List<NeutronPort_VIFDetail> details = new ArrayList<NeutronPort_VIFDetail>();
186             for (VifDetails vifDetail : binding.getVifDetails()) {
187                 NeutronPort_VIFDetail detail = new NeutronPort_VIFDetail();
188                 detail.setPortFilter(vifDetail.isPortFilter());
189                 detail.setOvsHybridPlug(vifDetail.isOvsHybridPlug());
190                 details.add(detail);
191             }
192             result.setVIFDetail(details);
193         }
194         result.setBindingvifType(binding.getVifType());
195         result.setBindingvnicType(binding.getVnicType());
196     }
197
198     @Override
199     public int canCreate(NeutronPort port) {
200         LOG.trace("canCreate port - {}", port);
201         // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
202         List<Neutron_IPs> fixedIPs = port.getFixedIPs();
203         if (fixedIPs != null && fixedIPs.size() > 1) {
204             LOG.warn("Neutron mapper does not support multiple IPs on the same port.");
205             return StatusCode.BAD_REQUEST;
206         }
207         NeutronRouter router = (isRouterGatewayPort(port) || isRouterInterfacePort(port)) ? NeutronRouterAware.getRouterForPort(port.getDeviceID()) : null;
208         if (router != null) {
209             return NeutronRouterAware.canAttachInterface(router, createNeutronRouter_InterfaceFrom(port), dataProvider);
210         }
211         return StatusCode.OK;
212     }
213
214     private static NeutronRouter_Interface createNeutronRouter_InterfaceFrom(NeutronPort port) {
215         NeutronRouter_Interface nri = new NeutronRouter_Interface();
216         if (port.getID() != null) {
217             nri.setID(port.getID());
218             nri.setPortUUID(port.getID());
219         }
220         if (port.getTenantID() != null) {
221             nri.setTenantID(port.getTenantID());
222         }
223         if (port.getFixedIPs() != null && port.getFixedIPs().size() == 1) {
224             // supported case
225             nri.setSubnetUUID(port.getFixedIPs().get(0).getSubnetUUID());
226         }
227         return nri;
228     }
229
230     @Override
231     public void created(NeutronPort port) {
232         LOG.trace("created port - {}", port);
233         if (isRouterInterfacePort(port) || isRouterGatewayPort(port)) {
234             NeutronRouter router = NeutronRouterAware.getRouterForPort(port.getDeviceID());
235             if (router != null) {
236                 NeutronRouterAware.neutronRouterInterfaceAttached(router, createNeutronRouter_InterfaceFrom(port),
237                         dataProvider, epService);
238                 return;
239             }
240         }
241         if (isFloatingIpPort(port)) {
242             LOG.trace("Port is floating ip - {} device id - {}", port.getID(), port.getDeviceID());
243             return;
244         }
245         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
246         TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
247         if (isDhcpPort(port)) {
248             LOG.trace("Port is DHCP port. - {}", port.getID());
249             Neutron_IPs firstIp = MappingUtils.getFirstIp(port.getFixedIPs());
250             if (firstIp == null) {
251                 LOG.warn("Illegal state - DHCP port does not have an IP address.");
252                 rwTx.cancel();
253                 return;
254             }
255         } else {
256             // this is here b/c stable/kilo sends sec-groups only with port
257             List<NeutronSecurityGroup> secGroups = port.getSecurityGroups();
258             if (secGroups != null) {
259                 for (NeutronSecurityGroup secGroup : secGroups) {
260                     EndpointGroupId epgId = new EndpointGroupId(secGroup.getSecurityGroupUUID());
261                     Optional<EndpointGroup> potentialEpg = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
262                             IidFactory.endpointGroupIid(tenantId, epgId), rwTx);
263                     if (!potentialEpg.isPresent()) {
264                         boolean isSecGroupCreated = secGrpAware.addNeutronSecurityGroup(secGroup, rwTx);
265                         if (!isSecGroupCreated) {
266                             rwTx.cancel();
267                             return;
268                         }
269                     } else {
270                         List<NeutronSecurityRule> secRules = secGroup.getSecurityRules();
271                         if (secRules != null) {
272                             for (NeutronSecurityRule secRule : secRules) {
273                                 secRuleAware.addNeutronSecurityRule(secRule, rwTx);
274                             }
275                         }
276                     }
277                 }
278             }
279         }
280         boolean isNeutronPortCreated = addNeutronPort(port, rwTx, epService);
281         if (!isNeutronPortCreated) {
282             rwTx.cancel();
283             return;
284         }
285
286         DataStoreHelper.submitToDs(rwTx);
287     }
288
289     public static boolean addNeutronPort(NeutronPort port, ReadWriteTransaction rwTx, EndpointService epService) {
290         TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
291         L2FloodDomainId l2FdId = new L2FloodDomainId(port.getNetworkUUID());
292         ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
293         boolean isFwCtxValid = validateForwardingCtx(fwCtx);
294         if (!isFwCtxValid) {
295             return false;
296         }
297         EndpointKey epKey = new EndpointKey(fwCtx.getL2BridgeDomain().getId(), new MacAddress(port.getMacAddress()));
298         addNeutronGbpMapping(port, epKey, rwTx);
299         try {
300             RegisterEndpointInput registerEpRpcInput = createRegisterEndpointInput(port, fwCtx);
301             RpcResult<Void> rpcResult = epService.registerEndpoint(registerEpRpcInput).get();
302             if (!rpcResult.isSuccessful()) {
303                 LOG.warn("Illegal state - RPC registerEndpoint failed. Input of RPC: {}", registerEpRpcInput);
304                 return false;
305             }
306         } catch (InterruptedException | ExecutionException e) {
307             LOG.error("addNeutronPort failed. {}", port, e);
308             return false;
309         }
310         return true;
311     }
312
313     private static void addNeutronGbpMapping(NeutronPort port, EndpointKey epKey, ReadWriteTransaction rwTx) {
314         UniqueId portId = new UniqueId(port.getID());
315         if (!isRouterInterfacePort(port) && !isRouterGatewayPort(port) && !isFloatingIpPort(port)) {
316             LOG.trace("Adding Port-Endpoint mapping for port {} (device owner {}) and endpoint {}", port.getID(),
317                     port.getDeviceOwner(), epKey);
318             EndpointByPort endpointByPort = MappingFactory.createEndpointByPort(epKey, portId);
319             rwTx.put(LogicalDatastoreType.OPERATIONAL, NeutronGbpIidFactory.endpointByPortIid(portId), endpointByPort,
320                     true);
321             PortByEndpoint portByEndpoint = MappingFactory.createPortByEndpoint(portId, epKey);
322             rwTx.put(LogicalDatastoreType.OPERATIONAL,
323                     NeutronGbpIidFactory.portByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()), portByEndpoint,
324                     true);
325         }
326     }
327
328     public static boolean addL3EndpointForExternalGateway(TenantId tenantId, L3ContextId l3ContextId,
329             IpAddress ipAddress, NetworkDomainId networkContainment, ReadWriteTransaction rwTx) {
330
331         EndpointL3Key epL3Key = new EndpointL3Key(ipAddress, l3ContextId);
332         addNeutronExtGwGbpMapping(epL3Key, rwTx);
333         List<EndpointGroupId> epgIds = new ArrayList<>();
334         epgIds.add(MappingUtils.EPG_EXTERNAL_ID);
335         EndpointL3 epL3 = createL3Endpoint(tenantId, epL3Key, epgIds, networkContainment);
336         InstanceIdentifier<EndpointL3> iid_l3 = IidFactory.l3EndpointIid(l3ContextId, ipAddress);
337         rwTx.put(LogicalDatastoreType.OPERATIONAL, iid_l3, epL3, true);
338         return true;
339     }
340
341     private static void addNeutronExtGwGbpMapping(EndpointL3Key epL3Key, ReadWriteTransaction rwTx) {
342         ExternalGatewayAsL3Endpoint externalGatewayL3Endpoint = MappingFactory.createExternalGatewayByL3Endpoint(epL3Key);
343         rwTx.put(LogicalDatastoreType.OPERATIONAL, NeutronGbpIidFactory.externalGatewayAsL3Endpoint(epL3Key.getL3Context(), epL3Key.getIpAddress()),
344                 externalGatewayL3Endpoint, true);
345     }
346
347     public static boolean addL3PrefixEndpoint(L3ContextId l3ContextId, IpPrefix ipPrefix, IpAddress ipAddress, TenantId tenantId,
348             EndpointService epService) {
349         EndpointL3PrefixKey epL3PrefixKey = new EndpointL3PrefixKey( ipPrefix, l3ContextId);
350         EndpointL3Key epL3Key = null;
351         List<EndpointL3Key> l3Gateways = new ArrayList<>();
352         if (ipAddress != null) {
353             epL3Key = new EndpointL3Key(ipAddress, l3ContextId);
354             l3Gateways.add(epL3Key);
355         }
356         try {
357             RegisterL3PrefixEndpointInput registerL3PrefixEpRpcInput = createRegisterL3PrefixEndpointInput(epL3PrefixKey, l3Gateways,tenantId);
358
359             RpcResult<Void> rpcResult = epService.registerL3PrefixEndpoint(registerL3PrefixEpRpcInput).get();
360             if (!rpcResult.isSuccessful()) {
361                 LOG.warn("Illegal state - RPC registerEndpoint failed. Input of RPC: {}", registerL3PrefixEpRpcInput);
362                 return false;
363             }
364         } catch (InterruptedException | ExecutionException e) {
365             LOG.error("addPort - RPC invocation failed.", e);
366             return false;
367         }
368         return true;
369
370     }
371
372     private static boolean validateForwardingCtx(ForwardingCtx fwCtx) {
373         if (fwCtx.getL2FloodDomain() == null) {
374             LOG.warn("Illegal state - l2-flood-domain does not exist.");
375             return false;
376         }
377         if (fwCtx.getL2BridgeDomain() == null) {
378             LOG.warn("Illegal state - l2-bridge-domain does not exist.");
379             return false;
380         }
381         if (fwCtx.getL3Context() == null) {
382             LOG.warn("Illegal state - l3-context does not exist.");
383             return false;
384         }
385         return true;
386     }
387
388     @Override
389     public int canUpdate(NeutronPort delta, NeutronPort original) {
390         LOG.trace("catUpdate port - delta: {} original: {}", delta, original);
391         if (delta.getFixedIPs() == null || delta.getFixedIPs().isEmpty()) {
392             return StatusCode.OK;
393         }
394         // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
395         List<Neutron_IPs> fixedIPs = delta.getFixedIPs();
396         if (fixedIPs != null && fixedIPs.size() > 1) {
397             LOG.warn("Neutron mapper does not support multiple IPs on the same port.");
398             return StatusCode.BAD_REQUEST;
399         }
400         boolean wasRouterPort = isRouterGatewayPort(original) || isRouterInterfacePort(original);
401         boolean isRouterPort = isRouterGatewayPort(delta) || isRouterInterfacePort(delta);
402         if (wasRouterPort || isRouterPort) {
403             NeutronRouter router = NeutronRouterAware.getRouterForPort(delta.getDeviceID());
404             if (router != null && !wasRouterPort && isRouterPort) {
405                 return NeutronRouterAware.
406                         canAttachInterface(router, createNeutronRouter_InterfaceFrom(delta), dataProvider);
407             } else if (router != null && wasRouterPort && !isRouterPort) {
408                 return NeutronRouterAware.canDetachInterface(router, createNeutronRouter_InterfaceFrom(delta));
409             }
410         }
411         return StatusCode.OK;
412     }
413
414     @Override
415     public void updated(NeutronPort port) {
416         LOG.trace("updated port - {}", port);
417         NeutronPort original = null;
418         Ports ports = NeutronListener.getNeutronDataBefore().getPorts();
419         boolean wasRouterPort = false;
420         if (ports != null) {
421             for (Port p : ports.getPort()) {
422                 if (p.getUuid().getValue().equals(port.getID())) {
423                     original = toNeutron(p);
424                     wasRouterPort = isRouterGatewayPort(original) || isRouterInterfacePort(original);
425                 }
426             }
427         }
428         boolean isRouterPort = isRouterGatewayPort(port) || isRouterInterfacePort(port);
429         if (original != null && (wasRouterPort || isRouterPort)) {
430             NeutronRouter router = NeutronRouterAware.getRouterForPort(port.getDeviceID());
431             if (router != null && (!wasRouterPort && isRouterPort)) {
432                 NeutronRouterAware.neutronRouterInterfaceAttached(router, createNeutronRouter_InterfaceFrom(port),
433                         dataProvider, epService);
434                 return;
435             } else if (router != null && (wasRouterPort && !isRouterPort)) {
436                 NeutronRouterAware.neutronRouterInterfaceAttached(router, createNeutronRouter_InterfaceFrom(port),
437                         dataProvider, epService);
438                 return;
439             }
440         }
441         if (isFloatingIpPort(port)) {
442             LOG.trace("Port is floating ip - {}", port.getID());
443             return;
444         }
445         if (Strings.isNullOrEmpty(port.getTenantID())) {
446             LOG.trace("REMOVE ME: Tenant is null - {}", port.getID());
447             return;
448         }
449
450         ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction();
451         TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
452         MacAddress macAddress = new MacAddress(port.getMacAddress());
453         L2FloodDomainId l2FdId = new L2FloodDomainId(port.getNetworkUUID());
454         ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rTx);
455         boolean isFwCtxValid = validateForwardingCtx(fwCtx);
456         if (!isFwCtxValid) {
457             rTx.close();
458             return;
459         }
460
461         Optional<Endpoint> potentionalEp = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
462                 IidFactory.endpointIid(fwCtx.getL2BridgeDomain().getId(), macAddress), rTx);
463         if (!potentionalEp.isPresent()) {
464             LOG.warn("Illegal state - endpoint {} does not exist.", new EndpointKey(fwCtx.getL2BridgeDomain().getId(),
465                     macAddress));
466             rTx.close();
467             return;
468         }
469
470         Endpoint ep = potentionalEp.get();
471         if (isEpIpDifferentThanPortFixedIp(ep, port) || isEpgDifferentThanSecGrp(ep, port)) {
472             UnregisterEndpointInput unregisterEpRpcInput = createUnregisterEndpointInput(ep);
473             RegisterEndpointInput registerEpRpcInput = createRegisterEndpointInput(port, fwCtx);
474             try {
475                 RpcResult<Void> rpcResult = epService.unregisterEndpoint(unregisterEpRpcInput).get();
476                 if (!rpcResult.isSuccessful()) {
477                     LOG.warn("Illegal state - RPC unregisterEndpoint failed. Input of RPC: {}", unregisterEpRpcInput);
478                     rTx.close();
479                     return;
480                 }
481                 rpcResult = epService.registerEndpoint(registerEpRpcInput).get();
482                 if (!rpcResult.isSuccessful()) {
483                     LOG.warn("Illegal state - RPC registerEndpoint failed. Input of RPC: {}", registerEpRpcInput);
484                     rTx.close();
485                     return;
486                 }
487             } catch (InterruptedException | ExecutionException e) {
488                 LOG.error("addPort - RPC invocation failed.", e);
489                 rTx.close();
490                 return;
491             }
492         }
493         rTx.close();
494     }
495
496     private boolean isEpIpDifferentThanPortFixedIp(Endpoint ep, NeutronPort port) {
497         List<L3Address> l3Addresses = ep.getL3Address();
498         List<Neutron_IPs> fixedIPs = port.getFixedIPs();
499         if ((l3Addresses == null || l3Addresses.isEmpty()) && (fixedIPs == null || fixedIPs.isEmpty())) {
500             return false;
501         }
502         if (l3Addresses != null && !l3Addresses.isEmpty() && fixedIPs != null && !fixedIPs.isEmpty()) {
503             if (fixedIPs.get(0).getIpAddress().equals(Utils.getStringIpAddress(l3Addresses.get(0).getIpAddress()))) {
504                 return false;
505             }
506         }
507         return true;
508     }
509
510     private boolean isEpgDifferentThanSecGrp(Endpoint ep, NeutronPort port) {
511         List<EndpointGroupId> epgIds = ep.getEndpointGroups();
512         List<NeutronSecurityGroup> secGroups = port.getSecurityGroups();
513         if ((epgIds == null || epgIds.isEmpty()) && (secGroups == null || secGroups.isEmpty())) {
514             return false;
515         }
516         if (epgIds != null && !epgIds.isEmpty() && secGroups != null && !secGroups.isEmpty()) {
517             if (epgIds.size() != secGroups.size()) {
518                 return true;
519             }
520             Collection<EndpointGroupId> epgIdsFromSecGroups = Collections2.transform(secGroups,
521                     new Function<NeutronSecurityGroup, EndpointGroupId>() {
522
523                         @Override
524                         public EndpointGroupId apply(NeutronSecurityGroup input) {
525                             return new EndpointGroupId(input.getSecurityGroupUUID());
526                         }
527                     });
528             // order independent equals
529             Set<EndpointGroupId> one = new HashSet<>(epgIds);
530             Set<EndpointGroupId> two = new HashSet<>(epgIdsFromSecGroups);
531             if (one.equals(two)) {
532                 return false;
533             }
534         }
535         return true;
536     }
537
538     @Override
539     public int canDelete(NeutronPort port) {
540         LOG.trace("canDelete port - {}", port);
541         NeutronRouter router = (isRouterGatewayPort(port) || isRouterInterfacePort(port)) ? NeutronRouterAware.getRouterForPort(port.getDeviceID()) : null;
542         if (router != null) {
543             return NeutronRouterAware.canDetachInterface(router, createNeutronRouter_InterfaceFrom(port));
544         }
545         return StatusCode.OK;
546     }
547
548     @Override
549     public void deleted(NeutronPort port) {
550         LOG.trace("deleted port - {}", port);
551         if (isRouterInterfacePort(port) || isRouterGatewayPort(port)) {
552             NeutronRouter router = NeutronRouterAware.getRouterForPort(port.getDeviceID());
553             if (router != null) {
554                 NeutronRouterAware.neutronRouterInterfaceDetached(router, createNeutronRouter_InterfaceFrom(port),
555                         dataProvider, epService);
556                 return;
557             }
558         }
559         if (isFloatingIpPort(port)) {
560             LOG.trace("Port is floating ip - {} device id - {}", port.getID(), port.getDeviceID());
561             return;
562         }
563         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
564         TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
565         L2FloodDomainId l2FdId = new L2FloodDomainId(port.getNetworkUUID());
566         ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
567         boolean isFwCtxValid = validateForwardingCtx(fwCtx);
568         if (!isFwCtxValid) {
569             rwTx.cancel();
570             return;
571         }
572
573         UnregisterEndpointInput unregisterEpRpcInput = createUnregisterEndpointInput(port, fwCtx);
574         boolean isEndpointUnregistered = false;
575         try {
576             isEndpointUnregistered = epService.unregisterEndpoint(unregisterEpRpcInput).get().isSuccessful();
577         } catch (InterruptedException | ExecutionException e) {
578             LOG.error("unregisterEndpoint - RPC invocation failed.", e);
579         }
580         if (isEndpointUnregistered) {
581             EndpointKey epKey = new EndpointKey(fwCtx.getL2BridgeDomain().getId(), new MacAddress(port.getMacAddress()));
582             deleteNeutronGbpMapping(port, epKey, rwTx);
583             DataStoreHelper.submitToDs(rwTx);
584         } else {
585             LOG.warn("Illegal state - RPC unregisterEndpoint failed. Input of RPC: {}", unregisterEpRpcInput);
586             rwTx.cancel();
587         }
588     }
589
590     private static void deleteNeutronGbpMapping(NeutronPort port, EndpointKey epKey, ReadWriteTransaction rwTx) {
591         UniqueId portId = new UniqueId(port.getID());
592         if (!isRouterInterfacePort(port) && !isRouterGatewayPort(port) && !isFloatingIpPort(port)) {
593             LOG.trace("Adding Port-Endpoint mapping for port {} (device owner {}) and endpoint {}", port.getID(),
594                     port.getDeviceOwner(), epKey);
595             DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
596                     NeutronGbpIidFactory.endpointByPortIid(portId), rwTx);
597             DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
598                     NeutronGbpIidFactory.portByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()), rwTx);
599         }
600     }
601
602     private static RegisterL3PrefixEndpointInput createRegisterL3PrefixEndpointInput(EndpointL3PrefixKey key, List<EndpointL3Key> endpointL3Keys, TenantId tenantId) {
603         List<EndpointL3Gateways> l3Gateways = new ArrayList<EndpointL3Gateways>();
604         for (EndpointL3Key epL3Key : endpointL3Keys) {
605             EndpointL3Gateways l3Gateway = new EndpointL3GatewaysBuilder().setIpAddress(epL3Key.getIpAddress())
606                 .setL3Context(epL3Key.getL3Context())
607                 .build();
608             l3Gateways.add(l3Gateway);
609         }
610         RegisterL3PrefixEndpointInputBuilder inputBuilder = new RegisterL3PrefixEndpointInputBuilder()
611                                                 .setL3Context(key.getL3Context())
612                                                 .setIpPrefix(key.getIpPrefix())
613                                                 .setEndpointGroup(MappingUtils.EPG_EXTERNAL_ID)
614                                                 .setTenant(tenantId)
615                                                 .setEndpointL3Gateways(l3Gateways)
616                                                 .setTimestamp(System.currentTimeMillis());
617         return inputBuilder.build();
618     }
619
620     private static EndpointL3 createL3Endpoint(TenantId tenantId, EndpointL3Key epL3Key,
621             List<EndpointGroupId> epgIds, NetworkDomainId containment) {
622
623         EndpointL3Builder epL3Builder = new EndpointL3Builder()
624         .setTenant(tenantId)
625         .setNetworkContainment(containment)
626         .setIpAddress(epL3Key.getIpAddress())
627         .setL3Context(epL3Key.getL3Context())
628         .setEndpointGroups(epgIds)
629         .setTimestamp(System.currentTimeMillis());
630
631         return epL3Builder.build();
632     }
633
634     private static RegisterEndpointInput createRegisterEndpointInput(NeutronPort port, ForwardingCtx fwCtx) {
635         List<EndpointGroupId> epgIds = new ArrayList<>();
636         if (isDhcpPort(port)) {
637             epgIds.add(NetworkService.EPG_ID);
638         }
639
640         List<NeutronSecurityGroup> securityGroups = port.getSecurityGroups();
641         if ((securityGroups == null || securityGroups.isEmpty())) {
642             if (!isDhcpPort(port)) {
643                 LOG.warn(
644                         "Port {} does not contain any security group. The port should belong to 'default' security group at least.",
645                         port.getID());
646             }
647         } else {
648             for (NeutronSecurityGroup secGrp : securityGroups) {
649                 epgIds.add(new EndpointGroupId(secGrp.getSecurityGroupUUID()));
650             }
651             epgIds.add(NetworkClient.EPG_ID);
652         }
653         RegisterEndpointInputBuilder inputBuilder = new RegisterEndpointInputBuilder().setL2Context(
654                 fwCtx.getL2BridgeDomain().getId())
655             .setMacAddress(new MacAddress(port.getMacAddress()))
656             .setTenant(new TenantId(Utils.normalizeUuid(port.getTenantID())))
657             .setEndpointGroups(epgIds)
658             .setTimestamp(System.currentTimeMillis());
659         List<Neutron_IPs> fixedIPs = port.getFixedIPs();
660         // TODO Li msunal this getting of just first IP has to be rewrite when OFOverlay renderer
661         // will support l3-endpoints. Then we will register L2 and L3 endpoints separately.
662         Neutron_IPs firstIp = MappingUtils.getFirstIp(fixedIPs);
663         if (firstIp != null) {
664             inputBuilder.setNetworkContainment(new SubnetId(firstIp.getSubnetUUID()));
665             L3Address l3Address = new L3AddressBuilder().setIpAddress(Utils.createIpAddress(firstIp.getIpAddress()))
666                 .setL3Context(fwCtx.getL3Context().getId())
667                 .build();
668             inputBuilder.setL3Address(ImmutableList.of(l3Address));
669         }
670         if (!Strings.isNullOrEmpty(port.getName())) {
671
672         }
673         return inputBuilder.build();
674     }
675
676     public static boolean isDhcpPort(NeutronPort port) {
677         return DEVICE_OWNER_DHCP.equals(port.getDeviceOwner());
678     }
679
680     public static boolean isRouterInterfacePort(NeutronPort port) {
681         return DEVICE_OWNER_ROUTER_IFACE.equals(port.getDeviceOwner());
682     }
683
684     public static boolean isRouterGatewayPort(NeutronPort port) {
685         return DEVICE_OWNER_ROUTER_GATEWAY.equals(port.getDeviceOwner());
686     }
687
688     public static boolean isFloatingIpPort(NeutronPort port) {
689         return DEVICE_OWNER_FLOATING_IP.equals(port.getDeviceOwner());
690     }
691
692     private UnregisterEndpointInput createUnregisterEndpointInput(Endpoint ep) {
693         UnregisterEndpointInputBuilder inputBuilder = new UnregisterEndpointInputBuilder();
694         L2 l2Ep = new L2Builder().setL2Context(ep.getL2Context()).setMacAddress(ep.getMacAddress()).build();
695         inputBuilder.setL2(ImmutableList.of(l2Ep));
696         // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
697         // Endpoint probably will not have l3-addresses anymore, because L2 and L3 endpoints should
698         // be registered separately.
699         if (ep.getL3Address() != null && !ep.getL3Address().isEmpty()) {
700             List<L3> l3Eps = new ArrayList<>();
701             for (L3Address ip : ep.getL3Address()) {
702                 l3Eps.add(new L3Builder().setL3Context(ip.getL3Context()).setIpAddress(ip.getIpAddress()).build());
703             }
704             inputBuilder.setL3(l3Eps);
705         }
706         return inputBuilder.build();
707     }
708
709     private UnregisterEndpointInput createUnregisterEndpointInput(NeutronPort port, ForwardingCtx fwCtx) {
710         UnregisterEndpointInputBuilder inputBuilder = new UnregisterEndpointInputBuilder();
711         L2 l2Ep = new L2Builder().setL2Context(fwCtx.getL2BridgeDomain().getId())
712             .setMacAddress(new MacAddress(port.getMacAddress()))
713             .build();
714         inputBuilder.setL2(ImmutableList.of(l2Ep));
715         // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
716         // Endpoint probably will not have l3-addresses anymore, because L2 and L3 endpoints should
717         // be registered separately.
718         if (port.getFixedIPs() != null && !port.getFixedIPs().isEmpty()) {
719             inputBuilder.setL3(createL3s(port.getFixedIPs(), fwCtx.getL3Context().getId()));
720         }
721         return inputBuilder.build();
722     }
723
724     private List<L3> createL3s(List<Neutron_IPs> neutronIps, L3ContextId l3ContextId) {
725         List<L3> l3s = new ArrayList<>();
726         for (Neutron_IPs fixedIp : neutronIps) {
727             String ip = fixedIp.getIpAddress();
728             L3 l3 = new L3Builder().setIpAddress(Utils.createIpAddress(ip)).setL3Context(l3ContextId).build();
729             l3s.add(l3);
730         }
731         return l3s;
732     }
733 }