Introduced neutron-mapper
[groupbasedpolicy.git] / neutron-mapper / src / main / java / org / opendaylight / groupbasedpolicy / neutron / mapper / mapping / NeutronRouterAware.java
1 package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping;
2
3 import static com.google.common.base.Preconditions.checkNotNull;
4
5 import java.util.List;
6
7 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
8 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
9 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
10 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
11 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
12 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.DataStoreHelper;
13 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.IidFactory;
14 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
15 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.NeutronUtils;
16 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.Utils;
17 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils.ForwardingCtx;
18 import org.opendaylight.neutron.spi.INeutronPortCRUD;
19 import org.opendaylight.neutron.spi.INeutronRouterAware;
20 import org.opendaylight.neutron.spi.INeutronRouterCRUD;
21 import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
22 import org.opendaylight.neutron.spi.NeutronCRUDInterfaces;
23 import org.opendaylight.neutron.spi.NeutronPort;
24 import org.opendaylight.neutron.spi.NeutronRouter;
25 import org.opendaylight.neutron.spi.NeutronRouter_Interface;
26 import org.opendaylight.neutron.spi.NeutronSecurityRule;
27 import org.opendaylight.neutron.spi.NeutronSubnet;
28 import org.opendaylight.neutron.spi.Neutron_IPs;
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.opendaylight.groupbasedpolicy.common.rev140421.Description;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.network.mappings.NetworkMapping;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomain;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomainBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3ContextBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Subnet;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.SubnetBuilder;
46 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 import com.google.common.base.Optional;
51 import com.google.common.collect.ImmutableList;
52
53 public class NeutronRouterAware implements INeutronRouterAware {
54
55     private static final Logger LOG = LoggerFactory.getLogger(NeutronRouterAware.class);
56     private final DataBroker dataProvider;
57     private final EndpointService epService;
58
59     public NeutronRouterAware(DataBroker dataProvider, EndpointService epService) {
60         this.dataProvider = checkNotNull(dataProvider);
61         this.epService = checkNotNull(epService);
62     }
63
64     @Override
65     public int canCreateRouter(NeutronRouter router) {
66         LOG.trace("canCreateRouter - {}", router);
67         INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
68         if (routerInterface == null) {
69             LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
70             return StatusCode.INTERNAL_SERVER_ERROR;
71         }
72
73         List<NeutronRouter> allRouters = routerInterface.getAllRouters();
74         if (allRouters != null && !allRouters.isEmpty()) {
75             LOG.warn("Illegal state - Neutron mapper does not support multiple routers yet.");
76             return StatusCode.FORBIDDEN;
77         }
78         return StatusCode.OK;
79     }
80
81     @Override
82     public void neutronRouterCreated(NeutronRouter router) {
83         LOG.trace("neutronRouterCreated - {}", router);
84         // TODO Li msunal external gateway
85     }
86
87     @Override
88     public int canUpdateRouter(NeutronRouter delta, NeutronRouter original) {
89         LOG.trace("canUpdateRouter - delta: {} original: {}", delta, original);
90         // TODO Li msunal external gateway
91         return StatusCode.OK;
92     }
93
94     @Override
95     public void neutronRouterUpdated(NeutronRouter router) {
96         LOG.trace("neutronRouterUpdated - {}", router);
97         // TODO Li msunal external gateway
98     }
99
100     @Override
101     public int canDeleteRouter(NeutronRouter router) {
102         LOG.trace("canDeleteRouter - {}", router);
103         // nothing to consider
104         return StatusCode.OK;
105     }
106
107     @Override
108     public void neutronRouterDeleted(NeutronRouter router) {
109         LOG.trace("neutronRouterDeleted - {}", router);
110         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
111         TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
112         Optional<EndpointGroup> potentialEpg = DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
113                 IidFactory.endpointGroupIid(tenantId, MappingUtils.EPG_ROUTER_ID), rwTx);
114         if (!potentialEpg.isPresent()) {
115             LOG.warn("Illegal state - Endpoint group {} does not exist.", MappingUtils.EPG_ROUTER_ID.getValue());
116             rwTx.cancel();
117             return;
118         }
119         DataStoreHelper.submitToDs(rwTx);
120     }
121
122     @Override
123     public int canAttachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface) {
124         LOG.trace("canAttachInterface - router: {} interface: {}", router, routerInterface);
125         try (ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction()) {
126             L3ContextId l3ContextId = new L3ContextId(router.getID());
127             TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
128             SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
129             Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
130                     IidFactory.subnetIid(tenantId, subnetId), rTx);
131             if (!potentialSubnet.isPresent()) {
132                 LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
133                 return StatusCode.NOT_FOUND;
134             }
135             Subnet subnet = potentialSubnet.get();
136             L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
137             ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rTx);
138             if (fwCtx.getL3Context() != null && fwCtx.getL3Context().equals(l3ContextId)) {
139                 // TODO Be msunal
140                 LOG.warn("Illegal state - Neutron mapper does not support multiple router interfaces in the same subnet yet.");
141                 return StatusCode.FORBIDDEN;
142             }
143             return StatusCode.OK;
144         }
145     }
146
147     @Override
148     public void neutronRouterInterfaceAttached(NeutronRouter router, NeutronRouter_Interface routerInterface) {
149         LOG.trace("neutronRouterInterfaceAttached - router: {} interface: {}", router, routerInterface);
150         INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);
151         if (portInterface == null) {
152             LOG.warn("Illegal state - No provider for {}", INeutronPortCRUD.class.getName());
153             return;
154         }
155
156         INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
157         if (subnetInterface == null) {
158             LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
159             return;
160         }
161
162         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
163         TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
164         L3ContextId l3ContextId = new L3ContextId(router.getID());
165         InstanceIdentifier<L3Context> l3ContextIid = IidFactory.l3ContextIid(tenantId, l3ContextId);
166         Optional<L3Context> potentialL3Context = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
167                 l3ContextIid, rwTx);
168         // add L3 context if missing
169         if (!potentialL3Context.isPresent()) {
170             Name l3ContextName = null;
171             if (router.getName() != null) {
172                 l3ContextName = new Name(router.getName());
173             }
174             L3Context l3Context = new L3ContextBuilder().setId(l3ContextId)
175                 .setName(l3ContextName)
176                 .setDescription(new Description(MappingUtils.NEUTRON_ROUTER__ + router.getID()))
177                 .build();
178             rwTx.put(LogicalDatastoreType.CONFIGURATION, l3ContextIid, l3Context);
179         }
180
181         SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
182         Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
183                 IidFactory.subnetIid(tenantId, subnetId), rwTx);
184         if (!potentialSubnet.isPresent()) {
185             LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
186             rwTx.cancel();
187             return;
188         }
189
190         // Based on Neutron Northbound - Port representing router interface contains exactly on
191         // fixed IP
192         NeutronPort routerPort = portInterface.getPort(routerInterface.getPortUUID());
193         Subnet subnet = new SubnetBuilder(potentialSubnet.get()).setVirtualRouterIp(
194                 Utils.createIpAddress(routerPort.getFixedIPs().get(0).getIpAddress())).build();
195         rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnetId), subnet);
196         if (subnet.getParent() == null) {
197             LOG.warn("Illegal state - subnet {} does not have a parent.", subnetId.getValue());
198             rwTx.cancel();
199             return;
200         }
201
202         L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
203         ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
204         if (fwCtx.getL2BridgeDomain() == null) {
205             LOG.warn("Illegal state - l2-flood-domain {} does not have a parent.", l2FdId.getValue());
206             rwTx.cancel();
207             return;
208         }
209
210         L2BridgeDomain l2BridgeDomain = new L2BridgeDomainBuilder(fwCtx.getL2BridgeDomain()).setParent(l3ContextId)
211             .build();
212         rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BridgeDomain.getId()),
213                 l2BridgeDomain);
214
215         // create security rules for router
216         List<NeutronSecurityRule> routerSecRules = createRouterSecRules(routerPort, null, rwTx);
217         if (routerSecRules == null) {
218             rwTx.cancel();
219             return;
220         }
221         for (NeutronSecurityRule routerSecRule : routerSecRules) {
222             boolean isRouterSecRuleAdded = NeutronSecurityRuleAware.addNeutronSecurityRule(routerSecRule, rwTx);
223             if (!isRouterSecRuleAdded) {
224                 rwTx.cancel();
225                 return;
226             }
227         }
228
229         NeutronSubnet neutronSubnet = subnetInterface.getSubnet(subnetId.getValue());
230         List<NeutronPort> portsInNeutronSubnet = neutronSubnet.getPortsInSubnet();
231         for (NeutronPort port : portsInNeutronSubnet) {
232             boolean isPortAdded = NeutronPortAware.addNeutronPort(port, rwTx, epService);
233             if (!isPortAdded) {
234                 rwTx.cancel();
235                 return;
236             }
237         }
238
239         DataStoreHelper.submitToDs(rwTx);
240     }
241
242     public static List<NeutronSecurityRule> createRouterSecRules(NeutronPort port, EndpointGroupId consumerEpgId,
243             ReadTransaction rTx) {
244         TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
245         Neutron_IPs firstIp = getFirstIp(port.getFixedIPs());
246         if (firstIp == null) {
247             LOG.warn("Illegal state - Router port does not have an IP address.");
248             return null;
249         }
250         SubnetId routerSubnetId = new SubnetId(firstIp.getSubnetUUID());
251         Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
252                 IidFactory.subnetIid(tenantId, routerSubnetId), rTx);
253         if (!potentialSubnet.isPresent()) {
254             LOG.warn("Illegal state - Subnet {} where is router port does not exist.", routerSubnetId.getValue());
255             return null;
256         }
257         IpPrefix ipSubnet = potentialSubnet.get().getIpPrefix();
258         NeutronSecurityRule routerRuleEgress = createRouterSecRule(port.getID(), tenantId, ipSubnet, consumerEpgId,
259                 true);
260         NeutronSecurityRule routerRuleIngress = createRouterSecRule(port.getID(), tenantId, ipSubnet, consumerEpgId,
261                 false);
262         return ImmutableList.of(routerRuleEgress, routerRuleIngress);
263     }
264
265     private static Neutron_IPs getFirstIp(List<Neutron_IPs> fixedIPs) {
266         if (fixedIPs == null || fixedIPs.isEmpty()) {
267             return null;
268         }
269         Neutron_IPs neutron_Ip = fixedIPs.get(0);
270         if (fixedIPs.size() > 1) {
271             LOG.warn("Neutron mapper does not support multiple IPs on the same port. Only first IP is selected {}",
272                     neutron_Ip);
273         }
274         return neutron_Ip;
275     }
276
277     private static NeutronSecurityRule createRouterSecRule(String ruleUuid, TenantId tenantId, IpPrefix ipSubnet,
278             EndpointGroupId consumerEpgId, boolean isEgress) {
279         NeutronSecurityRule dhcpSecRule = new NeutronSecurityRule();
280         dhcpSecRule.setSecurityRuleGroupID(MappingUtils.EPG_ROUTER_ID.getValue());
281         dhcpSecRule.setSecurityRuleTenantID(tenantId.getValue());
282         dhcpSecRule.setSecurityRuleRemoteIpPrefix(Utils.getStringIpPrefix(ipSubnet));
283         if (isEgress) {
284             dhcpSecRule.setSecurityRuleUUID(NeutronUtils.EGRESS + "__" + ruleUuid);
285             dhcpSecRule.setSecurityRuleDirection(NeutronUtils.EGRESS);
286         } else {
287             dhcpSecRule.setSecurityRuleUUID(NeutronUtils.INGRESS + "__" + ruleUuid);
288             dhcpSecRule.setSecurityRuleDirection(NeutronUtils.INGRESS);
289         }
290         if (ipSubnet.getIpv4Prefix() != null) {
291             dhcpSecRule.setSecurityRuleEthertype(NeutronUtils.IPv4);
292         } else {
293             dhcpSecRule.setSecurityRuleEthertype(NeutronUtils.IPv6);
294         }
295         return dhcpSecRule;
296     }
297
298     @Override
299     public int canDetachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface) {
300         LOG.trace("canDetachInterface - router: {} interface: {}", router, routerInterface);
301         // nothing to consider
302         return StatusCode.OK;
303     }
304
305     @Override
306     public void neutronRouterInterfaceDetached(NeutronRouter router, NeutronRouter_Interface routerInterface) {
307         LOG.trace("neutronRouterInterfaceDetached - router: {} interface: {}", router, routerInterface);
308         INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
309         if (subnetInterface == null) {
310             LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
311             return;
312         }
313
314         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
315         TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
316         L3ContextId l3ContextId = new L3ContextId(router.getID());
317         SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
318         InstanceIdentifier<L3Context> l3ContextIid = IidFactory.l3ContextIid(tenantId, l3ContextId);
319         DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
320                 IidFactory.l3ContextIid(tenantId, l3ContextId), rwTx);
321
322         Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
323                 IidFactory.subnetIid(tenantId, subnetId), rwTx);
324         if (!potentialSubnet.isPresent()) {
325             LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
326             rwTx.cancel();
327             return;
328         }
329
330         Subnet subnet = new SubnetBuilder(potentialSubnet.get()).setVirtualRouterIp(null).build();
331         rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnetId), subnet);
332
333         L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
334         ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
335         if (fwCtx.getL2BridgeDomain() == null) {
336             LOG.warn("Illegal state - l2-flood-domain {} does not have a parent.", l2FdId.getValue());
337             rwTx.cancel();
338             return;
339         }
340
341         Optional<NetworkMapping> potentialNetworkMapping = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
342                 IidFactory.networkMappingIid(l2FdId), rwTx);
343         if (!potentialNetworkMapping.isPresent()) {
344             LOG.warn("Illegal state - network-mapping {} does not exist.", l2FdId.getValue());
345             rwTx.cancel();
346             return;
347         }
348
349         L2BridgeDomain l2BridgeDomain = new L2BridgeDomainBuilder(fwCtx.getL2BridgeDomain()).setParent(
350                 potentialNetworkMapping.get().getL3ContextId()).build();
351         rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BridgeDomain.getId()),
352                 l2BridgeDomain);
353
354         NeutronSubnet neutronSubnet = subnetInterface.getSubnet(subnetId.getValue());
355         List<NeutronPort> portsInNeutronSubnet = neutronSubnet.getPortsInSubnet();
356         for (NeutronPort port : portsInNeutronSubnet) {
357             boolean isPortAdded = NeutronPortAware.addNeutronPort(port, rwTx, epService);
358             if (!isPortAdded) {
359                 rwTx.cancel();
360                 return;
361             }
362         }
363     }
364
365 }