2 * Copyright (c) 2015 Intel, 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
9 package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping;
11 import static com.google.common.base.Preconditions.checkNotNull;
13 import java.util.List;
15 import javax.annotation.Nonnull;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
19 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.groupbasedpolicy.domain_extension.l2_l3.util.L2L3IidFactory;
22 import org.opendaylight.groupbasedpolicy.neutron.gbp.util.NeutronGbpIidFactory;
23 import org.opendaylight.groupbasedpolicy.neutron.mapper.EndpointRegistrator;
24 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
25 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.PortUtils;
26 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.SubnetUtils;
27 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
28 import org.opendaylight.groupbasedpolicy.util.IidFactory;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.NetworkContainmentBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.network.containment.containment.NetworkDomainContainmentBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.register.endpoint.input.AddressEndpointRegBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Key;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.IpPrefixType;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.SubnetAugmentForwarding;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.SubnetAugmentForwardingBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.has.subnet.Subnet;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.has.subnet.SubnetBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.forwarding.forwarding.by.tenant.ForwardingContext;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.forwarding.forwarding.by.tenant.ForwardingContextBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.forwarding.forwarding.by.tenant.NetworkDomain;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.forwarding.forwarding.by.tenant.NetworkDomainBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.forwarding.forwarding.by.tenant.NetworkDomainKey;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.external.gateways.as.endpoints.ExternalGatewayAsEndpoint;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.external.gateways.as.l3.endpoints.ExternalGatewayAsL3Endpoint;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2BridgeDomain;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2BridgeDomainBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L3Context;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L3ContextBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.Routers;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
65 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
69 import com.google.common.base.Optional;
70 import com.google.common.base.Strings;
71 import com.google.common.collect.ImmutableList;
73 public class NeutronRouterAware implements NeutronAware<Router> {
75 private static final Logger LOG = LoggerFactory.getLogger(NeutronRouterAware.class);
76 public static final InstanceIdentifier<Router> ROUTER_WILDCARD_IID =
77 InstanceIdentifier.builder(Neutron.class).child(Routers.class).child(Router.class).build();
78 private final DataBroker dataProvider;
79 private final EndpointRegistrator epRegistrator;
81 public NeutronRouterAware(DataBroker dataProvider, EndpointRegistrator epRegistrator) {
82 this.dataProvider = checkNotNull(dataProvider);
83 this.epRegistrator = checkNotNull(epRegistrator);
87 public void onCreated(Router router, Neutron neutron) {
88 LOG.trace("created router - {}", router);
90 ContextId routerl3ContextId = new ContextId(router.getUuid().getValue());
91 TenantId tenantId = new TenantId(router.getTenantId().getValue());
92 InstanceIdentifier<ForwardingContext> routerL3CtxIid = L2L3IidFactory.l3ContextIid(tenantId, routerl3ContextId);
93 ForwardingContextBuilder fwdCtxBuilder = new ForwardingContextBuilder();
94 Name routerName = null;
95 if (!Strings.isNullOrEmpty(router.getName())) {
97 routerName = new Name(router.getName());
98 fwdCtxBuilder.setName(routerName);
99 } catch (Exception e) {
100 LOG.info("Name '{}' of Neutron Subnet '{}' is ignored.", router.getName(),
101 router.getUuid().getValue());
102 LOG.debug("Name exception", e);
105 ForwardingContext routerl3Context = fwdCtxBuilder.setContextId(routerl3ContextId)
106 .setContextType(MappingUtils.L3_CONTEXT)
108 WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
109 wTx.put(LogicalDatastoreType.CONFIGURATION, routerL3CtxIid, routerl3Context, true);
110 createTenantL3Context(new L3ContextId(routerl3ContextId), tenantId, routerName, wTx);
111 DataStoreHelper.submitToDs(wTx);
115 private void createTenantL3Context(L3ContextId l3ContextId, TenantId tenantId, Name name, WriteTransaction wTx) {
116 L3ContextBuilder l3ContextBuilder = new L3ContextBuilder();
118 l3ContextBuilder.setName(name);
120 L3Context l3Context = l3ContextBuilder.setId(l3ContextId).build();
121 wTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l3ContextIid(tenantId, l3ContextId), l3Context);
125 public void onUpdated(Router oldRouter, Router newRouter, Neutron oldNeutron, Neutron newNeutron) {
126 LOG.trace("updated router - OLD: {}\nNEW: {}", oldRouter, newRouter);
128 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
129 TenantId tenantId = new TenantId(newRouter.getTenantId().getValue());
130 ContextId routerL3CtxId = new ContextId(newRouter.getUuid().getValue());
132 if (newRouter.getGatewayPortId() != null && oldRouter.getGatewayPortId() == null) {
133 // external network is attached to router
134 Uuid gatewayPortId = newRouter.getGatewayPortId();
135 Optional<Port> potentialGwPort = PortUtils.findPort(gatewayPortId, newNeutron.getPorts());
136 if (!potentialGwPort.isPresent()) {
137 LOG.warn("Illegal state - router gateway port {} does not exist for router {}.",
138 gatewayPortId.getValue(), newRouter);
143 Port gwPort = potentialGwPort.get();
144 List<FixedIps> fixedIpsFromGwPort = gwPort.getFixedIps();
145 if (fixedIpsFromGwPort == null || fixedIpsFromGwPort.isEmpty()) {
146 LOG.warn("Illegal state - router gateway port {} does not contain fixed IPs {}",
147 gatewayPortId.getValue(), gwPort);
152 // router can have only one external network
153 FixedIps ipWithSubnetFromGwPort = fixedIpsFromGwPort.get(0);
154 Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet> potentialSubnet = SubnetUtils.findSubnet(ipWithSubnetFromGwPort.getSubnetId(), newNeutron.getSubnets());
155 if (!potentialSubnet.isPresent()) {
156 LOG.warn("Illegal state - Subnet {} does not exist for router {}.",
157 ipWithSubnetFromGwPort.getSubnetId(), newRouter);
161 IpPrefix gatewayIp = MappingUtils.ipAddressToIpPrefix(potentialSubnet.get().getGatewayIp());
162 boolean registeredExternalGateway = registerExternalGateway(tenantId, gatewayIp,
163 routerL3CtxId, new NetworkDomainId(ipWithSubnetFromGwPort.getSubnetId().getValue()));
164 if (!registeredExternalGateway) {
165 LOG.warn("Could not add L3Prefix as gateway of default route. Gateway port {}", gwPort);
169 addNeutronExtGwGbpMapping(routerL3CtxId, gatewayIp, rwTx);
170 NetworkDomain subnetDomain = createSubnetWithVirtualRouterIp(gatewayIp, new NetworkDomainId(ipWithSubnetFromGwPort.getSubnetId()
172 rwTx.merge(LogicalDatastoreType.CONFIGURATION, L2L3IidFactory.subnetIid(tenantId, subnetDomain.getNetworkDomainId()),
174 ContextId l2BdId = new ContextId(potentialSubnet.get().getNetworkId().getValue());
175 Optional<ForwardingContext> optBd = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
176 L2L3IidFactory.l2BridgeDomainIid(tenantId, l2BdId), rwTx);
177 if (!optBd.isPresent()) {
179 "Could not read L2-Bridge-Domain {} Modifiaction of it's parent to L3-Context of router {} aborted.",
180 l2BdId, newRouter.getUuid());
184 ForwardingContext l2BdWithGw = new ForwardingContextBuilder(optBd.get())
185 .setParent(MappingUtils.createParent(routerL3CtxId, MappingUtils.L3_CONTEXT))
187 rwTx.put(LogicalDatastoreType.CONFIGURATION, L2L3IidFactory.l2BridgeDomainIid(tenantId, l2BdId),
190 updateTenantForwarding(newNeutron, oldRouter, newRouter, new L3ContextId(routerL3CtxId), tenantId, rwTx);
191 DataStoreHelper.submitToDs(rwTx);
194 private boolean registerExternalGateway(TenantId tenantId, IpPrefix ipPrefix, ContextId routerl3ContextId,
195 NetworkDomainId networkDomainId) {
196 AddressEndpointRegBuilder addrEpBuilder = new AddressEndpointRegBuilder();
197 addrEpBuilder.setAddressType(IpPrefixType.class);
198 addrEpBuilder.setAddress(MappingUtils.ipPrefixToStringIpAddress(ipPrefix));
199 addrEpBuilder.setContextId(routerl3ContextId);
200 addrEpBuilder.setContextType(MappingUtils.L3_CONTEXT);
201 addrEpBuilder.setTenant(tenantId);
202 addrEpBuilder.setNetworkContainment(new NetworkContainmentBuilder().setContainment(
203 new NetworkDomainContainmentBuilder().setNetworkDomainId(networkDomainId).build()).build());
204 addrEpBuilder.setEndpointGroup(ImmutableList.of(MappingUtils.EPG_EXTERNAL_ID));
205 addrEpBuilder.setTimestamp(System.currentTimeMillis());
206 return epRegistrator.registerEndpoint(addrEpBuilder.build());
209 private NetworkDomain createSubnetWithVirtualRouterIp(IpPrefix gatewayIp, NetworkDomainId subnetId) {
210 Subnet subnet = new SubnetBuilder().setVirtualRouterIp(MappingUtils.ipPrefixToIpAddress(gatewayIp.getValue())).build();
211 return new NetworkDomainBuilder().setKey(new NetworkDomainKey(subnetId, MappingUtils.SUBNET))
212 .addAugmentation(SubnetAugmentForwarding.class,
213 new SubnetAugmentForwardingBuilder().setSubnet(subnet).build())
218 private void updateTenantForwarding(Neutron newNeutron, Router oldRouter, Router newRouter, L3ContextId l3ContextId, TenantId tenantId, ReadWriteTransaction rwTx) {
219 InstanceIdentifier<L3Context> l3ContextIid =
220 IidFactory.l3ContextIid(tenantId, l3ContextId);
221 Optional<L3Context> optL3Context = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, l3ContextIid, rwTx);
222 L3Context l3Context = null;
223 if (optL3Context.isPresent()) {
224 l3Context = optL3Context.get();
225 } else { // add L3 context if missing
226 l3Context = createL3CtxFromRouter(newRouter);
227 rwTx.put(LogicalDatastoreType.CONFIGURATION, l3ContextIid, l3Context);
230 if (newRouter.getGatewayPortId() != null && oldRouter.getGatewayPortId() == null) {
231 // external network is attached to router
232 Uuid gatewayPortId = newRouter.getGatewayPortId();
233 Optional<Port> potentialGwPort = PortUtils.findPort(gatewayPortId, newNeutron.getPorts());
234 if (!potentialGwPort.isPresent()) {
235 LOG.warn("Illegal state - router gateway port {} does not exist for router {}.",
236 gatewayPortId.getValue(), newRouter);
241 Port gwPort = potentialGwPort.get();
242 List<FixedIps> fixedIpsFromGwPort = gwPort.getFixedIps();
243 if (fixedIpsFromGwPort == null || fixedIpsFromGwPort.isEmpty()) {
244 LOG.warn("Illegal state - router gateway port {} does not contain fixed IPs {}",
245 gatewayPortId.getValue(), gwPort);
250 // router can have only one external network
251 FixedIps ipWithSubnetFromGwPort = fixedIpsFromGwPort.get(0);
252 Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet> potentialSubnet = SubnetUtils.findSubnet(ipWithSubnetFromGwPort.getSubnetId(), newNeutron.getSubnets());
253 if (!potentialSubnet.isPresent()) {
254 LOG.warn("Illegal state - Subnet {} does not exist for router {}.",
255 ipWithSubnetFromGwPort.getSubnetId(), newRouter);
259 IpAddress gatewayIp = potentialSubnet.get().getGatewayIp();
260 boolean registeredExternalGateway = epRegistrator.registerL3EpAsExternalGateway(tenantId, gatewayIp,
261 l3ContextId, new NetworkDomainId(ipWithSubnetFromGwPort.getSubnetId().getValue()));
262 if (!registeredExternalGateway) {
263 LOG.warn("Could not add L3Prefix as gateway of default route. Gateway port {}", gwPort);
267 EndpointL3Key epL3Key = new EndpointL3Key(gatewayIp, l3ContextId);
268 addNeutronExtGwMapping(epL3Key, rwTx);
270 boolean registeredDefaultRoute = epRegistrator.registerExternalL3PrefixEndpoint(MappingUtils.DEFAULT_ROUTE,
271 l3ContextId, gatewayIp, tenantId);
272 if (!registeredDefaultRoute) {
273 LOG.warn("Could not add EndpointL3Prefix as default route. Gateway port {}", gwPort);
277 org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet subnetWithGw =
278 new org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.SubnetBuilder().setId(new SubnetId(ipWithSubnetFromGwPort.getSubnetId().getValue()))
279 .setVirtualRouterIp(gatewayIp)
281 rwTx.merge(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnetWithGw.getId()),
283 L2BridgeDomainId l2BdId = new L2BridgeDomainId(potentialSubnet.get().getNetworkId().getValue());
284 Optional<L2BridgeDomain> optBd = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
285 IidFactory.l2BridgeDomainIid(tenantId, l2BdId), rwTx);
286 if (!optBd.isPresent()) {
288 "Could not read L2-Bridge-Domain {} Modifiaction of it's parent to L3-Context of router {} aborted.",
289 l2BdId, newRouter.getUuid());
293 L2BridgeDomain l2BdWithGw = new L2BridgeDomainBuilder(optBd.get())
294 .setParent(new L3ContextId(l3ContextId.getValue()))
296 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BdId),
301 private static @Nonnull ForwardingContext createL3ContextFromRouter(
303 Name l3ContextName = null;
304 if (!Strings.isNullOrEmpty(router.getName())) {
305 l3ContextName = new Name(router.getName());
307 return new ForwardingContextBuilder().setContextId(new ContextId(router.getUuid().getValue()))
308 .setContextType(MappingUtils.L3_CONTEXT)
309 .setName(new Name(l3ContextName.getValue()))
314 private static @Nonnull L3Context createL3CtxFromRouter(Router router) {
315 Name l3ContextName = null;
316 if (!Strings.isNullOrEmpty(router.getName())) {
317 l3ContextName = new Name(router.getName());
319 return new L3ContextBuilder().setId(new L3ContextId(router.getUuid().getValue()))
320 .setName(l3ContextName)
321 .setDescription(new Description(MappingUtils.NEUTRON_ROUTER + router.getUuid().getValue()))
325 private static void addNeutronExtGwGbpMapping(ContextId contextId, IpPrefix ipPrefix, ReadWriteTransaction rwTx) {
326 ExternalGatewayAsEndpoint externalGatewayL3Endpoint = MappingFactory.createEaxternalGatewayAsEndpoint(
327 contextId, ipPrefix);
328 rwTx.put(LogicalDatastoreType.OPERATIONAL,
329 NeutronGbpIidFactory.externalGatewayAsEndpoint(contextId, ipPrefix, MappingUtils.L3_CONTEXT), externalGatewayL3Endpoint, true);
333 private static void addNeutronExtGwMapping(EndpointL3Key epL3Key, ReadWriteTransaction rwTx) {
334 ExternalGatewayAsL3Endpoint externalGatewayL3Endpoint =
335 MappingFactory.createExternalGatewayByL3Endpoint(epL3Key);
336 rwTx.put(LogicalDatastoreType.OPERATIONAL,
337 NeutronGbpIidFactory.externalGatewayAsL3Endpoint(epL3Key.getL3Context(), epL3Key.getIpAddress()),
338 externalGatewayL3Endpoint, true);
342 public void onDeleted(Router router, Neutron oldNeutron, Neutron newNeutron) {
343 LOG.trace("deleted router - {}", router);