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