2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping;
10 import static com.google.common.base.Preconditions.checkNotNull;
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;
19 import java.util.concurrent.ExecutionException;
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.ReadTransaction;
24 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.groupbasedpolicy.neutron.gbp.util.NeutronGbpIidFactory;
27 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
28 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils.ForwardingCtx;
29 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.NeutronUtils;
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.INeutronPortAware;
34 import org.opendaylight.neutron.spi.NeutronPort;
35 import org.opendaylight.neutron.spi.NeutronSecurityGroup;
36 import org.opendaylight.neutron.spi.NeutronSecurityRule;
37 import org.opendaylight.neutron.spi.Neutron_IPs;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.UniqueId;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInput;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterL3PrefixEndpointInput;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterL3PrefixEndpointInputBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInput;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInputBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3AddressBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.l3.prefix.fields.EndpointL3Gateways;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.l3.prefix.fields.EndpointL3GatewaysBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointKey;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Builder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Key;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3PrefixKey;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L2;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L2Builder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3Builder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.endpoints.by.floating.ip.ports.EndpointByFloatingIpPort;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.endpoints.by.ports.EndpointByPort;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.endpoints.by.router._interface.ports.EndpointByRouterInterfacePort;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.endpoints.by.router.gateway.ports.EndpointByRouterGatewayPort;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.external.gateways.as.l3.endpoints.ExternalGatewayAsL3Endpoint;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.floating.ip.ports.by.endpoints.FloatingIpPortByEndpoint;
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.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.router._interface.ports.by.endpoints.RouterInterfacePortByEndpoint;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.router.gateway.ports.by.endpoints.RouterGatewayPortByEndpoint;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.EndpointLocation.LocationType;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextInput;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextInputBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
83 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
84 import org.opendaylight.yangtools.yang.common.RpcResult;
85 import org.slf4j.Logger;
86 import org.slf4j.LoggerFactory;
88 import com.google.common.base.Function;
89 import com.google.common.base.Optional;
90 import com.google.common.base.Strings;
91 import com.google.common.collect.Collections2;
92 import com.google.common.collect.ImmutableList;
94 public class NeutronPortAware implements INeutronPortAware {
96 public static final Logger LOG = LoggerFactory.getLogger(NeutronPortAware.class);
97 private static final String DEVICE_OWNER_DHCP = "network:dhcp";
98 private static final String DEVICE_OWNER_ROUTER_IFACE = "network:router_interface";
99 private static final String DEVICE_OWNER_ROUTER_GATEWAY = "network:router_gateway";
100 private static final String DEVICE_OWNER_FLOATING_IP = "network:floatingip";
101 private static final int DHCP_SERVER_PORT = 67;
102 private static final int DNS_SERVER_PORT = 53;
103 private final DataBroker dataProvider;
104 private final EndpointService epService;
105 private final static Map<String, UniqueId> floatingIpPortByDeviceId = new HashMap<>();
107 public NeutronPortAware(DataBroker dataProvider, EndpointService epService) {
108 this.dataProvider = checkNotNull(dataProvider);
109 this.epService = checkNotNull(epService);
113 * @see org.opendaylight.neutron.spi.INeutronPortAware#canCreatePort(org.opendaylight.neutron.spi.NeutronPort)
116 public int canCreatePort(NeutronPort port) {
117 LOG.trace("canCreatePort - {}", port);
118 // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
119 List<Neutron_IPs> fixedIPs = port.getFixedIPs();
120 if (fixedIPs != null && fixedIPs.size() > 1) {
121 LOG.warn("Neutron mapper does not support multiple IPs on the same port.");
122 return StatusCode.BAD_REQUEST;
124 return StatusCode.OK;
128 * @see org.opendaylight.neutron.spi.INeutronPortAware#neutronPortCreated(org.opendaylight.neutron.spi.NeutronPort)
131 public void neutronPortCreated(NeutronPort port) {
132 LOG.trace("neutronPortCreated - {}", port);
133 if (isRouterInterfacePort(port)) {
134 LOG.trace("Port is router interface - {} does nothing. {} handles router iface.",
135 NeutronPortAware.class.getSimpleName(), NeutronRouterAware.class.getSimpleName());
138 if (isRouterGatewayPort(port)) {
139 LOG.trace("Port is router gateway - {} does nothing. {} handles router iface.",
140 NeutronPortAware.class.getSimpleName(), NeutronRouterAware.class.getSimpleName());
143 if (isFloatingIpPort(port)) {
144 LOG.trace("Port is floating ip - {} device id - {}", port.getID(), port.getDeviceID());
145 floatingIpPortByDeviceId.put(port.getDeviceID(), new UniqueId(port.getID()));
148 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
149 TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
150 if (isDhcpPort(port)) {
151 LOG.trace("Port is DHCP port. - {}", port.getID());
152 List<NeutronSecurityRule> dhcpSecRules = createDhcpSecRules(port, null, rwTx);
153 if (dhcpSecRules == null) {
158 for (NeutronSecurityRule dhcpSecRule : dhcpSecRules) {
159 boolean isDhcpSecRuleAdded = NeutronSecurityRuleAware.addNeutronSecurityRule(dhcpSecRule, rwTx);
160 if (!isDhcpSecRuleAdded) {
166 List<NeutronSecurityGroup> secGroups = port.getSecurityGroups();
167 if (secGroups != null) {
168 for (NeutronSecurityGroup secGroup : secGroups) {
169 EndpointGroupId epgId = new EndpointGroupId(secGroup.getSecurityGroupUUID());
170 Optional<EndpointGroup> potentialEpg = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
171 IidFactory.endpointGroupIid(tenantId, epgId), rwTx);
172 if (!potentialEpg.isPresent()) {
173 boolean isSecGroupCreated = NeutronSecurityGroupAware.addNeutronSecurityGroup(secGroup, rwTx);
174 if (!isSecGroupCreated) {
178 if (containsSecRuleWithRemoteSecGroup(secGroup)) {
179 List<NeutronSecurityRule> dhcpSecRules = createDhcpSecRules(port, epgId, rwTx);
180 if (dhcpSecRules == null) {
184 List<NeutronSecurityRule> routerSecRules = NeutronRouterAware.createRouterSecRules(port, epgId, rwTx);
185 if (routerSecRules == null) {
191 List<NeutronSecurityRule> secRules = secGroup.getSecurityRules();
192 if (secRules != null) {
193 for (NeutronSecurityRule secRule : secRules) {
194 NeutronSecurityRuleAware.addNeutronSecurityRule(secRule, rwTx);
201 boolean isNeutronPortCreated = addNeutronPort(port, rwTx, epService);
202 if (!isNeutronPortCreated) {
207 DataStoreHelper.submitToDs(rwTx);
210 public static boolean addNeutronPort(NeutronPort port, ReadWriteTransaction rwTx, EndpointService epService) {
211 TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
212 L2FloodDomainId l2FdId = new L2FloodDomainId(port.getNetworkUUID());
213 ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
214 boolean isFwCtxValid = validateForwardingCtx(fwCtx);
218 EndpointKey epKey = new EndpointKey(fwCtx.getL2BridgeDomain().getId(), new MacAddress(port.getMacAddress()));
219 addNeutronGbpMapping(port, epKey, rwTx);
222 RegisterEndpointInput registerEpRpcInput = createRegisterEndpointInput(port, fwCtx);
223 RpcResult<Void> rpcResult = epService.registerEndpoint(registerEpRpcInput).get();
224 if (!rpcResult.isSuccessful()) {
225 LOG.warn("Illegal state - RPC registerEndpoint failed. Input of RPC: {}", registerEpRpcInput);
228 } catch (InterruptedException | ExecutionException e) {
229 LOG.error("addNeutronPort failed. {}", port, e);
235 public static boolean addL3EndpointForExternalGateway(TenantId tenantId, L3ContextId l3ContextId,
236 IpAddress ipAddress, NetworkDomainId networkContainment, ReadWriteTransaction rwTx) {
238 EndpointL3Key epL3Key = new EndpointL3Key(ipAddress, l3ContextId);
239 addNeutronExtGwGbpMapping(epL3Key, rwTx);
240 List<EndpointGroupId> epgIds = new ArrayList<>();
241 // each EP has to be in EPG ANY, except dhcp and router
242 epgIds.add(MappingUtils.EPG_EXTERNAL_ID);
243 epgIds.add(MappingUtils.EPG_ROUTER_ID);
244 EndpointL3 epL3 = createL3Endpoint(tenantId, epL3Key, epgIds, networkContainment);
245 InstanceIdentifier<EndpointL3> iid_l3 = IidFactory.l3EndpointIid(l3ContextId, ipAddress);
246 rwTx.put(LogicalDatastoreType.OPERATIONAL, iid_l3, epL3, true);
250 private static void addNeutronExtGwGbpMapping(EndpointL3Key epL3Key, ReadWriteTransaction rwTx) {
251 ExternalGatewayAsL3Endpoint externalGatewayL3Endpoint = MappingFactory.createExternalGatewayByL3Endpoint(epL3Key);
252 rwTx.put(LogicalDatastoreType.OPERATIONAL, NeutronGbpIidFactory.externalGatewayAsL3Endpoint(epL3Key.getL3Context(), epL3Key.getIpAddress()),
253 externalGatewayL3Endpoint, true);
256 private static void addNeutronGbpMapping(NeutronPort port, EndpointKey epKey, ReadWriteTransaction rwTx) {
257 UniqueId portId = new UniqueId(port.getID());
258 if (isRouterInterfacePort(port)) {
259 LOG.trace("Adding RouterInterfacePort-Endpoint mapping for port {} and endpoint {}", port.getID(), epKey);
260 EndpointByRouterInterfacePort endpointByPort = MappingFactory.createEndpointByRouterInterfacePort(epKey,
262 rwTx.put(LogicalDatastoreType.OPERATIONAL, NeutronGbpIidFactory.endpointByRouterInterfacePortIid(portId),
263 endpointByPort, true);
264 RouterInterfacePortByEndpoint portByEndpoint = MappingFactory.createRouterInterfacePortByEndpoint(portId,
266 rwTx.put(LogicalDatastoreType.OPERATIONAL,
267 NeutronGbpIidFactory.routerInterfacePortByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()),
268 portByEndpoint, true);
269 } else if (isRouterGatewayPort(port)) {
270 LOG.trace("Adding RouterGatewayPort-Endpoint mapping for port {} and endpoint {}", port.getID(), epKey);
271 EndpointByRouterGatewayPort endpointByPort = MappingFactory.createEndpointByRouterGatewayPort(epKey, portId);
272 rwTx.put(LogicalDatastoreType.OPERATIONAL, NeutronGbpIidFactory.endpointByRouterGatewayPortIid(portId),
273 endpointByPort, true);
274 RouterGatewayPortByEndpoint portByEndpoint = MappingFactory.createRouterGatewayPortByEndpoint(portId, epKey);
275 rwTx.put(LogicalDatastoreType.OPERATIONAL,
276 NeutronGbpIidFactory.routerGatewayPortByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()),
277 portByEndpoint, true);
278 } else if (isFloatingIpPort(port)) {
279 LOG.trace("Adding FloatingIpPort-Endpoint mapping for port {} and endpoint {}", port.getID(), epKey);
280 EndpointByFloatingIpPort endpointByPort = MappingFactory.createEndpointByFloatingIpPort(epKey, portId);
281 rwTx.put(LogicalDatastoreType.OPERATIONAL, NeutronGbpIidFactory.endpointByFloatingIpPortIid(portId),
282 endpointByPort, true);
283 FloatingIpPortByEndpoint portByEndpoint = MappingFactory.createFloatingIpPortByEndpoint(portId, epKey);
284 rwTx.put(LogicalDatastoreType.OPERATIONAL,
285 NeutronGbpIidFactory.floatingIpPortByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()),
286 portByEndpoint, true);
288 LOG.trace("Adding Port-Endpoint mapping for port {} (device owner {}) and endpoint {}", port.getID(),
289 port.getDeviceOwner(), epKey);
290 EndpointByPort endpointByPort = MappingFactory.createEndpointByPort(epKey, portId);
291 rwTx.put(LogicalDatastoreType.OPERATIONAL, NeutronGbpIidFactory.endpointByPortIid(portId), endpointByPort, true);
292 PortByEndpoint portByEndpoint = MappingFactory.createPortByEndpoint(portId, epKey);
293 rwTx.put(LogicalDatastoreType.OPERATIONAL,
294 NeutronGbpIidFactory.portByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()), portByEndpoint, true);
298 public static boolean addL3PrefixEndpoint(L3ContextId l3ContextId, IpPrefix ipPrefix, IpAddress ipAddress, TenantId tenantId,
299 ReadWriteTransaction rwTx, EndpointService epService) {
301 EndpointL3PrefixKey epL3PrefixKey = new EndpointL3PrefixKey( ipPrefix, l3ContextId);
303 EndpointL3Key epL3Key = null;
304 List<EndpointL3Key> l3Gateways = new ArrayList<>();
305 if (ipAddress != null) {
306 epL3Key = new EndpointL3Key(ipAddress, l3ContextId);
307 l3Gateways.add(epL3Key);
312 RegisterL3PrefixEndpointInput registerL3PrefixEpRpcInput = createRegisterL3PrefixEndpointInput(epL3PrefixKey, l3Gateways,tenantId);
314 RpcResult<Void> rpcResult = epService.registerL3PrefixEndpoint(registerL3PrefixEpRpcInput).get();
315 if (!rpcResult.isSuccessful()) {
316 LOG.warn("Illegal state - RPC registerEndpoint failed. Input of RPC: {}", registerL3PrefixEpRpcInput);
319 } catch (InterruptedException | ExecutionException e) {
320 LOG.error("addPort - RPC invocation failed.", e);
327 private static boolean validateForwardingCtx(ForwardingCtx fwCtx) {
328 if (fwCtx.getL2FloodDomain() == null) {
329 LOG.warn("Illegal state - l2-flood-domain does not exist.");
332 if (fwCtx.getL2BridgeDomain() == null) {
333 LOG.warn("Illegal state - l2-bridge-domain does not exist.");
336 if (fwCtx.getL3Context() == null) {
337 LOG.warn("Illegal state - l3-context does not exist.");
343 private List<NeutronSecurityRule> createDhcpSecRules(NeutronPort port, EndpointGroupId consumerEpgId, ReadTransaction rTx) {
344 TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
345 Neutron_IPs firstIp = MappingUtils.getFirstIp(port.getFixedIPs());
346 if (firstIp == null) {
347 LOG.warn("Illegal state - DHCP port does not have an IP address.");
350 IpAddress ipAddress = Utils.createIpAddress(firstIp.getIpAddress());
351 boolean isIPv4Ethertype = ipAddress.getIpv4Address() == null ? false : true;
352 List<NeutronSecurityRule> rules = new ArrayList<>();
353 rules.add(createDhcpIngressSecRule(port.getID(), tenantId, isIPv4Ethertype, consumerEpgId));
354 rules.add(createDnsSecRule(port.getID(), tenantId, isIPv4Ethertype, consumerEpgId));
355 rules.add(createUdpEgressSecRule(port.getID(), tenantId, isIPv4Ethertype, consumerEpgId));
356 rules.add(createIcmpSecRule(port.getID(), tenantId, isIPv4Ethertype, consumerEpgId, true));
357 rules.add(createIcmpSecRule(port.getID(), tenantId, isIPv4Ethertype, consumerEpgId, false));
361 private NeutronSecurityRule createDhcpIngressSecRule(String ruleUuid, TenantId tenantId, boolean isIPv4Ethertype, EndpointGroupId consumerEpgId) {
362 NeutronSecurityRule dhcpSecRule = new NeutronSecurityRule();
363 dhcpSecRule.setSecurityRuleGroupID(MappingUtils.EPG_DHCP_ID.getValue());
364 dhcpSecRule.setSecurityRuleTenantID(tenantId.getValue());
365 if (consumerEpgId != null) {
366 dhcpSecRule.setSecurityRemoteGroupID(consumerEpgId.getValue());
368 dhcpSecRule.setSecurityRuleUUID(NeutronUtils.INGRESS + "_dhcp__" + ruleUuid);
369 dhcpSecRule.setSecurityRuleDirection(NeutronUtils.INGRESS);
370 dhcpSecRule.setSecurityRulePortMin(DHCP_SERVER_PORT);
371 dhcpSecRule.setSecurityRulePortMax(DHCP_SERVER_PORT);
372 dhcpSecRule.setSecurityRuleProtocol(NeutronUtils.UDP);
373 if (isIPv4Ethertype) {
374 dhcpSecRule.setSecurityRuleEthertype(NeutronUtils.IPv4);
376 dhcpSecRule.setSecurityRuleEthertype(NeutronUtils.IPv6);
381 private NeutronSecurityRule createUdpEgressSecRule(String ruleUuid, TenantId tenantId, boolean isIPv4Ethertype, EndpointGroupId consumerEpgId) {
382 NeutronSecurityRule dhcpSecRule = new NeutronSecurityRule();
383 dhcpSecRule.setSecurityRuleGroupID(MappingUtils.EPG_DHCP_ID.getValue());
384 dhcpSecRule.setSecurityRuleTenantID(tenantId.getValue());
385 if (consumerEpgId != null) {
386 dhcpSecRule.setSecurityRemoteGroupID(consumerEpgId.getValue());
388 dhcpSecRule.setSecurityRuleUUID(NeutronUtils.EGRESS + "_udp__" + ruleUuid);
389 dhcpSecRule.setSecurityRuleDirection(NeutronUtils.EGRESS);
390 dhcpSecRule.setSecurityRuleProtocol(NeutronUtils.UDP);
391 if (isIPv4Ethertype) {
392 dhcpSecRule.setSecurityRuleEthertype(NeutronUtils.IPv4);
394 dhcpSecRule.setSecurityRuleEthertype(NeutronUtils.IPv6);
399 private NeutronSecurityRule createDnsSecRule(String ruleUuid, TenantId tenantId, boolean isIPv4Ethertype, EndpointGroupId consumerEpgId) {
400 NeutronSecurityRule dnsSecRule = new NeutronSecurityRule();
401 dnsSecRule.setSecurityRuleGroupID(MappingUtils.EPG_DHCP_ID.getValue());
402 dnsSecRule.setSecurityRuleTenantID(tenantId.getValue());
403 if (consumerEpgId != null) {
404 dnsSecRule.setSecurityRemoteGroupID(consumerEpgId.getValue());
406 dnsSecRule.setSecurityRuleUUID(NeutronUtils.INGRESS + "_dns__" + ruleUuid);
407 dnsSecRule.setSecurityRuleDirection(NeutronUtils.INGRESS);
408 dnsSecRule.setSecurityRulePortMin(DNS_SERVER_PORT);
409 dnsSecRule.setSecurityRulePortMax(DNS_SERVER_PORT);
410 dnsSecRule.setSecurityRuleProtocol(NeutronUtils.UDP);
411 if (isIPv4Ethertype) {
412 dnsSecRule.setSecurityRuleEthertype(NeutronUtils.IPv4);
414 dnsSecRule.setSecurityRuleEthertype(NeutronUtils.IPv6);
419 private NeutronSecurityRule createIcmpSecRule(String ruleUuid, TenantId tenantId, boolean isIPv4Ethertype, EndpointGroupId consumerEpgId,
421 NeutronSecurityRule icmpSecRule = new NeutronSecurityRule();
422 icmpSecRule.setSecurityRuleGroupID(MappingUtils.EPG_DHCP_ID.getValue());
423 icmpSecRule.setSecurityRuleTenantID(tenantId.getValue());
424 if (consumerEpgId != null) {
425 icmpSecRule.setSecurityRemoteGroupID(consumerEpgId.getValue());
428 icmpSecRule.setSecurityRuleUUID(NeutronUtils.EGRESS + "_icmp__" + ruleUuid);
429 icmpSecRule.setSecurityRuleDirection(NeutronUtils.EGRESS);
431 icmpSecRule.setSecurityRuleUUID(NeutronUtils.INGRESS + "_icmp__" + ruleUuid);
432 icmpSecRule.setSecurityRuleDirection(NeutronUtils.INGRESS);
434 icmpSecRule.setSecurityRuleProtocol(NeutronUtils.ICMP);
435 if (isIPv4Ethertype) {
436 icmpSecRule.setSecurityRuleEthertype(NeutronUtils.IPv4);
438 icmpSecRule.setSecurityRuleEthertype(NeutronUtils.IPv6);
444 * @see org.opendaylight.neutron.spi.INeutronPortAware#canUpdatePort(org.opendaylight.neutron.spi.NeutronPort,
445 * org.opendaylight.neutron.spi.NeutronPort)
448 public int canUpdatePort(NeutronPort delta, NeutronPort original) {
449 LOG.trace("canUpdatePort - delta: {} original: {}", delta, original);
450 if (delta.getFixedIPs() == null || delta.getFixedIPs().isEmpty()) {
451 return StatusCode.OK;
453 // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
454 List<Neutron_IPs> fixedIPs = delta.getFixedIPs();
455 if (fixedIPs != null && fixedIPs.size() > 1) {
456 LOG.warn("Neutron mapper does not support multiple IPs on the same port.");
457 return StatusCode.BAD_REQUEST;
459 return StatusCode.OK;
463 * @see org.opendaylight.neutron.spi.INeutronPortAware#neutronPortUpdated(org.opendaylight.neutron.spi.NeutronPort)
466 public void neutronPortUpdated(NeutronPort port) {
467 LOG.trace("neutronPortUpdated - {}", port);
468 if (isRouterInterfacePort(port)) {
469 LOG.trace("Port is router interface - {} does nothing. {} handles router iface.",
470 NeutronPortAware.class.getSimpleName(), NeutronRouterAware.class.getSimpleName());
473 if (isRouterGatewayPort(port)) {
474 LOG.trace("Port is router gateway - {}", port.getID());
477 if (isFloatingIpPort(port)) {
478 LOG.trace("Port is floating ip - {}", port.getID());
481 if (Strings.isNullOrEmpty(port.getTenantID())) {
482 LOG.trace("REMOVE ME: Tenant is null - {}", port.getID());
486 ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction();
487 TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
488 MacAddress macAddress = new MacAddress(port.getMacAddress());
489 L2FloodDomainId l2FdId = new L2FloodDomainId(port.getNetworkUUID());
490 ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rTx);
491 boolean isFwCtxValid = validateForwardingCtx(fwCtx);
497 Optional<Endpoint> potentionalEp = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
498 IidFactory.endpointIid(fwCtx.getL2BridgeDomain().getId(), macAddress), rTx);
499 if (!potentionalEp.isPresent()) {
500 LOG.warn("Illegal state - endpoint {} does not exist.", new EndpointKey(fwCtx.getL2BridgeDomain().getId(),
506 Endpoint ep = potentionalEp.get();
507 if (isEpIpDifferentThanPortFixedIp(ep, port) || isEpgDifferentThanSecGrp(ep, port)) {
508 UnregisterEndpointInput unregisterEpRpcInput = createUnregisterEndpointInput(ep);
509 RegisterEndpointInput registerEpRpcInput = createRegisterEndpointInput(port, fwCtx);
511 RpcResult<Void> rpcResult = epService.unregisterEndpoint(unregisterEpRpcInput).get();
512 if (!rpcResult.isSuccessful()) {
513 LOG.warn("Illegal state - RPC unregisterEndpoint failed. Input of RPC: {}", unregisterEpRpcInput);
517 rpcResult = epService.registerEndpoint(registerEpRpcInput).get();
518 if (!rpcResult.isSuccessful()) {
519 LOG.warn("Illegal state - RPC registerEndpoint failed. Input of RPC: {}", registerEpRpcInput);
523 } catch (InterruptedException | ExecutionException e) {
524 LOG.error("addPort - RPC invocation failed.", e);
532 private boolean isEpIpDifferentThanPortFixedIp(Endpoint ep, NeutronPort port) {
533 List<L3Address> l3Addresses = ep.getL3Address();
534 List<Neutron_IPs> fixedIPs = port.getFixedIPs();
535 if ((l3Addresses == null || l3Addresses.isEmpty()) && (fixedIPs == null || fixedIPs.isEmpty())) {
538 if (l3Addresses != null && !l3Addresses.isEmpty() && fixedIPs != null && !fixedIPs.isEmpty()) {
539 if (fixedIPs.get(0).getIpAddress().equals(Utils.getStringIpAddress(l3Addresses.get(0).getIpAddress()))) {
546 private boolean isEpgDifferentThanSecGrp(Endpoint ep, NeutronPort port) {
547 List<EndpointGroupId> epgIds = ep.getEndpointGroups();
548 List<NeutronSecurityGroup> secGroups = port.getSecurityGroups();
549 if ((epgIds == null || epgIds.isEmpty()) && (secGroups == null || secGroups.isEmpty())) {
552 if (epgIds != null && !epgIds.isEmpty() && secGroups != null && !secGroups.isEmpty()) {
553 if (epgIds.size() != secGroups.size()) {
556 Collection<EndpointGroupId> epgIdsFromSecGroups = Collections2.transform(secGroups,
557 new Function<NeutronSecurityGroup, EndpointGroupId>() {
560 public EndpointGroupId apply(NeutronSecurityGroup input) {
561 return new EndpointGroupId(input.getSecurityGroupUUID());
564 // order independent equals
565 Set<EndpointGroupId> one = new HashSet<>(epgIds);
566 Set<EndpointGroupId> two = new HashSet<>(epgIdsFromSecGroups);
567 if (one.equals(two)) {
575 * @see org.opendaylight.neutron.spi.INeutronPortAware#canDeletePort(org.opendaylight.neutron.spi.NeutronPort)
578 public int canDeletePort(NeutronPort port) {
579 LOG.trace("canDeletePort - {}", port);
580 // nothing to consider
581 return StatusCode.OK;
585 * @see org.opendaylight.neutron.spi.INeutronPortAware#neutronPortDeleted(org.opendaylight.neutron.spi.NeutronPort)
588 public void neutronPortDeleted(NeutronPort port) {
589 LOG.trace("neutronPortDeleted - {}", port);
590 if (isRouterInterfacePort(port)) {
591 LOG.trace("Port is router interface - {} does nothing. {} handles router iface.",
592 NeutronPortAware.class.getSimpleName(), NeutronRouterAware.class.getSimpleName());
595 if (isRouterGatewayPort(port)) {
596 LOG.trace("Port is router gateway - {} does nothing. {} handles router iface.",
597 NeutronPortAware.class.getSimpleName(), NeutronRouterAware.class.getSimpleName());
600 if (isFloatingIpPort(port)) {
601 LOG.trace("Port is floating ip - {} device id - {}", port.getID(), port.getDeviceID());
602 floatingIpPortByDeviceId.remove(port.getDeviceID());
604 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
605 TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
606 L2FloodDomainId l2FdId = new L2FloodDomainId(port.getNetworkUUID());
607 ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
608 boolean isFwCtxValid = validateForwardingCtx(fwCtx);
614 EndpointKey epKey = new EndpointKey(fwCtx.getL2BridgeDomain().getId(), new MacAddress(port.getMacAddress()));
615 deleteNeutronGbpMapping(port, epKey, rwTx);
616 UnregisterEndpointInput unregisterEpRpcInput = createUnregisterEndpointInput(port, fwCtx);
618 RpcResult<Void> rpcResult = epService.unregisterEndpoint(unregisterEpRpcInput).get();
619 if (!rpcResult.isSuccessful()) {
620 LOG.warn("Illegal state - RPC unregisterEndpoint failed. Input of RPC: {}", unregisterEpRpcInput);
622 } catch (InterruptedException | ExecutionException e) {
623 LOG.error("addPort - RPC invocation failed.", e);
628 private static void deleteNeutronGbpMapping(NeutronPort port, EndpointKey epKey, ReadWriteTransaction rwTx) {
629 UniqueId portId = new UniqueId(port.getID());
630 if (isRouterInterfacePort(port)) {
631 LOG.trace("Adding RouterInterfacePort-Endpoint mapping for port {} and endpoint {}", port.getID(), epKey);
632 DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
633 NeutronGbpIidFactory.endpointByRouterInterfacePortIid(portId), rwTx);
634 DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
635 NeutronGbpIidFactory.routerInterfacePortByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()), rwTx);
636 } else if (isRouterGatewayPort(port)) {
637 LOG.trace("Adding RouterGatewayPort-Endpoint mapping for port {} and endpoint {}", port.getID(), epKey);
638 DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
639 NeutronGbpIidFactory.endpointByRouterGatewayPortIid(portId), rwTx);
640 DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
641 NeutronGbpIidFactory.routerGatewayPortByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()), rwTx);
642 } else if (isFloatingIpPort(port)) {
643 LOG.trace("Adding FloatingIpPort-Endpoint mapping for port {} and endpoint {}", port.getID(), epKey);
644 DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
645 NeutronGbpIidFactory.endpointByFloatingIpPortIid(portId), rwTx);
646 DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
647 NeutronGbpIidFactory.floatingIpPortByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()), rwTx);
649 LOG.trace("Adding Port-Endpoint mapping for port {} (device owner {}) and endpoint {}", port.getID(),
650 port.getDeviceOwner(), epKey);
651 DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL, NeutronGbpIidFactory.endpointByPortIid(portId), rwTx);
652 DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
653 NeutronGbpIidFactory.portByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()), rwTx);
657 private static RegisterL3PrefixEndpointInput createRegisterL3PrefixEndpointInput(EndpointL3PrefixKey key, List<EndpointL3Key> endpointL3Keys, TenantId tenantId) {
658 List<EndpointGroupId> epgIds = new ArrayList<>();
659 // each EP has to be in EPG ANY, except dhcp and router
660 epgIds.add(MappingUtils.EPG_ANY_ID);
662 List<EndpointL3Gateways> l3Gateways = new ArrayList<EndpointL3Gateways>();
663 for (EndpointL3Key epL3Key : endpointL3Keys) {
664 EndpointL3Gateways l3Gateway = new EndpointL3GatewaysBuilder().setIpAddress(epL3Key.getIpAddress())
665 .setL3Context(epL3Key.getL3Context())
667 l3Gateways.add(l3Gateway);
669 RegisterL3PrefixEndpointInputBuilder inputBuilder = new RegisterL3PrefixEndpointInputBuilder()
670 .setL3Context(key.getL3Context())
671 .setIpPrefix(key.getIpPrefix())
672 .setEndpointGroups(epgIds)
674 .setEndpointL3Gateways(l3Gateways)
675 .setTimestamp(System.currentTimeMillis());
676 return inputBuilder.build();
679 private static EndpointL3 createL3Endpoint(TenantId tenantId, EndpointL3Key epL3Key,
680 List<EndpointGroupId> epgIds, NetworkDomainId containment) {
682 EndpointL3Builder epL3Builder = new EndpointL3Builder()
684 .setNetworkContainment(containment)
685 .setIpAddress(epL3Key.getIpAddress())
686 .setL3Context(epL3Key.getL3Context())
687 .setEndpointGroups(epgIds)
688 .setTimestamp(System.currentTimeMillis());
690 return epL3Builder.build();
693 private static RegisterEndpointInput createRegisterEndpointInput(NeutronPort port, ForwardingCtx fwCtx) {
694 List<EndpointGroupId> epgIds = new ArrayList<>();
695 // each EP has to be in EPG ANY, except dhcp and router
696 if (isDhcpPort(port)) {
697 epgIds.add(MappingUtils.EPG_DHCP_ID);
698 } else if (!containsSecRuleWithRemoteSecGroup(port.getSecurityGroups())) {
699 epgIds.add(MappingUtils.EPG_ANY_ID);
702 List<NeutronSecurityGroup> securityGroups = port.getSecurityGroups();
703 if ((securityGroups == null || securityGroups.isEmpty())) {
704 if (isFloatingIpPort(port)) {
705 epgIds.add(MappingUtils.EPG_EXTERNAL_ID);
706 } else if (!isDhcpPort(port)) {
708 "Port {} does not contain any security group. The port should belong to 'default' security group at least.",
712 for (NeutronSecurityGroup secGrp : securityGroups) {
713 epgIds.add(new EndpointGroupId(secGrp.getSecurityGroupUUID()));
716 LocationType locationType = LocationType.Internal;
717 if(isRouterGatewayPort(port)) {
718 locationType = LocationType.External;
720 RegisterEndpointInputBuilder inputBuilder = new RegisterEndpointInputBuilder().setL2Context(
721 fwCtx.getL2BridgeDomain().getId())
722 .setMacAddress(new MacAddress(port.getMacAddress()))
723 .setTenant(new TenantId(Utils.normalizeUuid(port.getTenantID())))
724 .setEndpointGroups(epgIds)
725 .addAugmentation(OfOverlayContextInput.class,
726 new OfOverlayContextInputBuilder()
727 .setPortName(createTapPortName(port))
728 .setLocationType(locationType)
730 .setTimestamp(System.currentTimeMillis());
731 List<Neutron_IPs> fixedIPs = port.getFixedIPs();
732 // TODO Li msunal this getting of just first IP has to be rewrite when OFOverlay renderer
733 // will support l3-endpoints. Then we will register L2 and L3 endpoints separately.
734 Neutron_IPs firstIp = MappingUtils.getFirstIp(fixedIPs);
735 if (firstIp != null) {
736 inputBuilder.setNetworkContainment(new SubnetId(firstIp.getSubnetUUID()));
737 L3Address l3Address = new L3AddressBuilder().setIpAddress(Utils.createIpAddress(firstIp.getIpAddress()))
738 .setL3Context(fwCtx.getL3Context().getId())
740 inputBuilder.setL3Address(ImmutableList.of(l3Address));
742 if (!Strings.isNullOrEmpty(port.getName())) {
745 return inputBuilder.build();
748 private static boolean containsSecRuleWithRemoteSecGroup(List<NeutronSecurityGroup> secGroups) {
749 if (secGroups == null) {
752 for (NeutronSecurityGroup secGroup : secGroups) {
753 boolean containsSecRuleWithRemoteSecGroup = containsSecRuleWithRemoteSecGroup(secGroup);
754 if (containsSecRuleWithRemoteSecGroup) {
761 private static boolean containsSecRuleWithRemoteSecGroup(NeutronSecurityGroup secGroup) {
762 List<NeutronSecurityRule> secRules = secGroup.getSecurityRules();
763 if (secRules == null) {
766 for (NeutronSecurityRule secRule : secRules) {
767 if (!Strings.isNullOrEmpty(secRule.getSecurityRemoteGroupID())) {
774 private static Name createTapPortName(NeutronPort port) {
775 return new Name("tap" + port.getID().substring(0, 11));
778 private static boolean isDhcpPort(NeutronPort port) {
779 return DEVICE_OWNER_DHCP.equals(port.getDeviceOwner());
782 private static boolean isRouterInterfacePort(NeutronPort port) {
783 return DEVICE_OWNER_ROUTER_IFACE.equals(port.getDeviceOwner());
786 private static boolean isRouterGatewayPort(NeutronPort port) {
787 return DEVICE_OWNER_ROUTER_GATEWAY.equals(port.getDeviceOwner());
790 private static boolean isFloatingIpPort(NeutronPort port) {
791 return DEVICE_OWNER_FLOATING_IP.equals(port.getDeviceOwner());
794 private UnregisterEndpointInput createUnregisterEndpointInput(Endpoint ep) {
795 UnregisterEndpointInputBuilder inputBuilder = new UnregisterEndpointInputBuilder();
796 L2 l2Ep = new L2Builder().setL2Context(ep.getL2Context()).setMacAddress(ep.getMacAddress()).build();
797 inputBuilder.setL2(ImmutableList.of(l2Ep));
798 // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
799 // Endpoint probably will not have l3-addresses anymore, because L2 and L3 endpoints should
800 // be registered separately.
801 if (ep.getL3Address() != null && !ep.getL3Address().isEmpty()) {
802 List<L3> l3Eps = new ArrayList<>();
803 for (L3Address ip : ep.getL3Address()) {
804 l3Eps.add(new L3Builder().setL3Context(ip.getL3Context()).setIpAddress(ip.getIpAddress()).build());
806 inputBuilder.setL3(l3Eps);
808 return inputBuilder.build();
811 private UnregisterEndpointInput createUnregisterEndpointInput(NeutronPort port, ForwardingCtx fwCtx) {
812 UnregisterEndpointInputBuilder inputBuilder = new UnregisterEndpointInputBuilder();
813 L2 l2Ep = new L2Builder().setL2Context(fwCtx.getL2BridgeDomain().getId())
814 .setMacAddress(new MacAddress(port.getMacAddress()))
816 inputBuilder.setL2(ImmutableList.of(l2Ep));
817 // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
818 // Endpoint probably will not have l3-addresses anymore, because L2 and L3 endpoints should
819 // be registered separately.
820 if (port.getFixedIPs() != null && !port.getFixedIPs().isEmpty()) {
821 inputBuilder.setL3(createL3s(port.getFixedIPs(), fwCtx.getL3Context().getId()));
823 return inputBuilder.build();
826 private List<L3> createL3s(List<Neutron_IPs> neutronIps, L3ContextId l3ContextId) {
827 List<L3> l3s = new ArrayList<>();
828 for (Neutron_IPs fixedIp : neutronIps) {
829 String ip = fixedIp.getIpAddress();
830 L3 l3 = new L3Builder().setIpAddress(Utils.createIpAddress(ip)).setL3Context(l3ContextId).build();
836 public static UniqueId getFloatingIpPortIdByDeviceId(String deviceId) {
837 return floatingIpPortByDeviceId.get(deviceId);