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