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