Add INFO.yaml for GBP
[groupbasedpolicy.git] / neutron-mapper / src / main / java / org / opendaylight / groupbasedpolicy / neutron / mapper / NeutronMapper.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
3  *
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
7  */
8 package org.opendaylight.groupbasedpolicy.neutron.mapper;
9
10 import com.google.common.base.Function;
11 import com.google.common.base.Predicate;
12 import com.google.common.collect.FluentIterable;
13 import com.google.common.collect.Iterators;
14 import com.google.common.collect.PeekingIterator;
15
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.List;
19 import java.util.Set;
20
21 import javax.annotation.Nonnull;
22 import javax.annotation.Nullable;
23
24 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
27 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
28 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
29 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
30 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
31 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronAware;
32 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronFloatingIpAware;
33 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronNetworkAware;
34 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronPortAware;
35 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronRouterAware;
36 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronSecurityGroupAware;
37 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronSubnetAware;
38 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.rule.NeutronSecurityRuleAware;
39 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
40 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.NetworkUtils;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.BaseEndpointService;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionEgress;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionIngress;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeV4;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeV6;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.floatingips.Floatingip;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.NeutronBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.SecurityGroups;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.SecurityGroupsBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.security.groups.SecurityGroup;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.security.groups.SecurityGroupBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.SecurityRules;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.SecurityRulesBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.security.rules.SecurityRule;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.security.rules.SecurityRuleBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
64 import org.opendaylight.yangtools.concepts.ListenerRegistration;
65 import org.opendaylight.yangtools.yang.binding.DataObject;
66 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
67 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
68
69 public class NeutronMapper implements ClusteredDataTreeChangeListener<Neutron>, AutoCloseable {
70
71     private static final String EXC_MSG_UNKNOWN_MODIFICATION_TYPE_IN_DATA = "Unknown modification type within data ";
72
73     private static final SecurityRuleBuilder EIG_INGRESS_IPV4_SEC_RULE_BUILDER = new SecurityRuleBuilder()
74         .setUuid(new Uuid("0a629f80-2408-11e6-b67b-9e71128cae77"))
75         .setDirection(DirectionIngress.class)
76         .setEthertype(EthertypeV4.class)
77         .setSecurityGroupId(MappingUtils.EIG_UUID);
78     private static final SecurityRuleBuilder EIG_EGRESS_IPV4_SEC_RULE_BUILDER = new SecurityRuleBuilder()
79         .setUuid(new Uuid("0f1789be-2408-11e6-b67b-9e71128cae77"))
80         .setDirection(DirectionEgress.class)
81         .setEthertype(EthertypeV4.class)
82         .setSecurityGroupId(MappingUtils.EIG_UUID);
83     private static final SecurityRuleBuilder EIG_INGRESS_IPV6_SEC_RULE_BUILDER = new SecurityRuleBuilder()
84         .setUuid(new Uuid("139b7f90-2408-11e6-b67b-9e71128cae77"))
85         .setDirection(DirectionIngress.class)
86         .setEthertype(EthertypeV6.class)
87         .setSecurityGroupId(MappingUtils.EIG_UUID);
88     private static final SecurityRuleBuilder EIG_EGRESS_IPV6_SEC_RULE_BUILDER = new SecurityRuleBuilder()
89         .setUuid(new Uuid("17517202-2408-11e6-b67b-9e71128cae77"))
90         .setDirection(DirectionEgress.class)
91         .setEthertype(EthertypeV6.class)
92         .setSecurityGroupId(MappingUtils.EIG_UUID);
93     private static final SecurityGroupBuilder EIG_SEC_GROUP_BUILDER =
94             new SecurityGroupBuilder().setUuid(MappingUtils.EIG_UUID);
95
96     private final NeutronNetworkAware networkAware;
97     private final NeutronSecurityGroupAware securityGroupAware;
98     private final NeutronSecurityRuleAware securityRuleAware;
99     private final NeutronSubnetAware subnetAware;
100     private final NeutronPortAware portAware;
101     private final NeutronRouterAware routerAware;
102     private final NeutronFloatingIpAware floatingIpAware;
103
104     private final ListenerRegistration<NeutronMapper> registerDataTreeChangeListener;
105     private Neutron neutronBefore;
106     private Neutron neutronAfter;
107
108     public NeutronMapper(DataBroker dataProvider, EndpointService epService, BaseEndpointService baseEpService,
109         @Nullable IpPrefix metadataIpPrefix, long metadataTcpPort) {
110         EndpointRegistrator epRegistrator = new EndpointRegistrator(epService, baseEpService);
111         networkAware = new NeutronNetworkAware(dataProvider, metadataTcpPort);
112         securityRuleAware = new NeutronSecurityRuleAware(dataProvider, epRegistrator);
113         securityGroupAware = new NeutronSecurityGroupAware(dataProvider, securityRuleAware);
114         subnetAware = new NeutronSubnetAware(dataProvider, epRegistrator);
115         portAware = new NeutronPortAware(dataProvider, epRegistrator, metadataIpPrefix);
116         routerAware = new NeutronRouterAware(dataProvider, epRegistrator);
117         floatingIpAware = new NeutronFloatingIpAware(dataProvider);
118         registerDataTreeChangeListener =
119                 dataProvider.registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
120                         InstanceIdentifier.builder(Neutron.class).build()), this);
121     }
122
123     @Override
124     public void onDataTreeChanged(@Nonnull Collection<DataTreeModification<Neutron>> changes) {
125         for (DataTreeModification<Neutron> change : changes) {
126             DataObjectModification<Neutron> neutronModif = change.getRootNode();
127             resolveAndSetNeutron(neutronModif);
128             // network
129             List<DataObjectModification<Network>> networkModifs =
130                     findModifiedData(NeutronNetworkAware.NETWORK_WILDCARD_IID, neutronModif);
131             for (Uuid tenantFromCreatedRouterExternalNetwork : filterCreatedRouterExternalNetworksAndTransformToTenants(
132                     networkModifs)) {
133                 SecurityGroup eigSecGroup =
134                         EIG_SEC_GROUP_BUILDER.setTenantId(tenantFromCreatedRouterExternalNetwork).build();
135                 securityGroupAware.onCreated(eigSecGroup, neutronAfter);
136                 List<SecurityRule> eigSecRules = createEigSecurityRules(tenantFromCreatedRouterExternalNetwork);
137                 for (SecurityRule eigSecRule : eigSecRules) {
138                     securityRuleAware.onCreated(eigSecRule, neutronAfter);
139                 }
140             }
141             onDataObjectModification(networkModifs, networkAware);
142             // security group
143             List<DataObjectModification<SecurityGroup>> secGroupModifs =
144                     findModifiedData(NeutronSecurityGroupAware.SECURITY_GROUP_WILDCARD_IID, neutronModif);
145             onDataObjectModification(secGroupModifs, securityGroupAware);
146             // security rules
147             List<DataObjectModification<SecurityRule>> secRuleModifs =
148                     findModifiedData(NeutronSecurityRuleAware.SECURITY_RULE_WILDCARD_IID, neutronModif);
149             onDataObjectModification(secRuleModifs, securityRuleAware);
150             // subnet
151             List<DataObjectModification<Subnet>> subnetModifs =
152                 findModifiedData(NeutronSubnetAware.SUBNET_WILDCARD_IID, neutronModif);
153             onDataObjectModification(subnetModifs, subnetAware);
154             // port
155             List<DataObjectModification<Port>> portModifs =
156                 findModifiedData(NeutronPortAware.PORT_WILDCARD_IID, neutronModif);
157             onDataObjectModification(portModifs, portAware);
158             // router
159             List<DataObjectModification<Router>> routerModifs =
160                 findModifiedData(NeutronRouterAware.ROUTER_WILDCARD_IID, neutronModif);
161             onDataObjectModification(routerModifs, routerAware);
162             // floating IP
163             List<DataObjectModification<Floatingip>> floatingIpModifs =
164                 findModifiedData(NeutronFloatingIpAware.FLOATING_IP_WILDCARD_IID, neutronModif);
165             onDataObjectModification(floatingIpModifs, floatingIpAware);
166         }
167     }
168
169     private <T extends DataObject> void onDataObjectModification(List<DataObjectModification<T>> dataModifs,
170             NeutronAware<T> neutronAware) {
171         for (DataObjectModification<T> dataModif : dataModifs) {
172             final T dataBefore = dataModif.getDataBefore();
173             final T dataAfter = dataModif.getDataAfter();
174             if (dataBefore == null && dataAfter != null) {
175                 neutronAware.onCreated(dataAfter, neutronAfter);
176             } else if (dataBefore != null && dataAfter != null) {
177                 neutronAware.onUpdated(dataBefore, dataAfter, neutronBefore, neutronAfter);
178             } else if (dataBefore != null) {
179                 neutronAware.onDeleted(dataBefore, neutronBefore, neutronAfter);
180             } else {
181                 throw new IllegalStateException(EXC_MSG_UNKNOWN_MODIFICATION_TYPE_IN_DATA + dataModif);
182             }
183         }
184     }
185
186     private Set<Uuid> filterCreatedRouterExternalNetworksAndTransformToTenants(
187             List<DataObjectModification<Network>> modifiedNetworks) {
188         return FluentIterable.from(modifiedNetworks).filter(new Predicate<DataObjectModification<Network>>() {
189
190             @Override
191             public boolean apply(DataObjectModification<Network> modifiedNetwork) {
192                 return (ModificationType.WRITE == modifiedNetwork.getModificationType()
193                         && NetworkUtils.isRouterExternal(modifiedNetwork.getDataAfter()));
194             }
195         }).transform(new Function<DataObjectModification<Network>, Uuid>() {
196
197             @Override
198             public Uuid apply(DataObjectModification<Network> modifiedNetwork) {
199                 return modifiedNetwork.getDataAfter().getTenantId();
200             }
201         }).toSet();
202     }
203
204     private void resolveAndSetNeutron(DataObjectModification<Neutron> originalNeutron) {
205         Neutron oldNeutronBefore = originalNeutron.getDataBefore();
206         neutronBefore = resolveAndCreateNewNeutron(oldNeutronBefore);
207         Neutron oldNeutronAfter = originalNeutron.getDataAfter();
208         neutronAfter = resolveAndCreateNewNeutron(oldNeutronAfter);
209     }
210
211     private @Nullable Neutron resolveAndCreateNewNeutron(@Nullable Neutron originalNeutron) {
212         if (originalNeutron == null) {
213             return null;
214         }
215         NeutronBuilder newNeutronBuilder = new NeutronBuilder(originalNeutron);
216         resolveAndAddSecurityRulesAndGroups(originalNeutron, newNeutronBuilder);
217         return newNeutronBuilder.build();
218     }
219
220     private void resolveAndAddSecurityRulesAndGroups(Neutron originalNeutron, NeutronBuilder newNeutronBuilder) {
221         List<SecurityRule> eigSecRulesAndOriginalSecRules = new ArrayList<>();
222         List<SecurityGroup> eigSecGroupAndOriginalSecGroup = new ArrayList<>();
223         // resolve EIG sec rules and groups
224         List<Network> routerExternalNetworks = NetworkUtils.findRouterExternalNetworks(originalNeutron.getNetworks());
225         Set<Uuid> tenantsFromRouterExternalNetwork = resolveTenantsFromNetworks(routerExternalNetworks);
226         for (Uuid tenantFromRouterExternalNetwork : tenantsFromRouterExternalNetwork) {
227             eigSecRulesAndOriginalSecRules.addAll(createEigSecurityRules(tenantFromRouterExternalNetwork));
228             eigSecGroupAndOriginalSecGroup
229                 .add(EIG_SEC_GROUP_BUILDER.setTenantId(tenantFromRouterExternalNetwork).build());
230         }
231         // set new sec rules
232         SecurityRules newSecRules = null;
233         if (originalNeutron.getSecurityRules() != null) {
234             List<SecurityRule> originalSecRules = originalNeutron.getSecurityRules().getSecurityRule();
235             if (originalSecRules != null) {
236                 eigSecRulesAndOriginalSecRules.addAll(originalSecRules);
237             }
238             newSecRules = new SecurityRulesBuilder(originalNeutron.getSecurityRules())
239                 .setSecurityRule(eigSecRulesAndOriginalSecRules).build();
240         } else {
241             newSecRules = new SecurityRulesBuilder().setSecurityRule(eigSecRulesAndOriginalSecRules).build();
242         }
243         newNeutronBuilder.setSecurityRules(newSecRules);
244         // set new sec groups
245         SecurityGroups newSecGroups = null;
246         if (originalNeutron.getSecurityGroups() != null) {
247             List<SecurityGroup> originalSecGroups = originalNeutron.getSecurityGroups().getSecurityGroup();
248             if (originalSecGroups != null) {
249                 eigSecGroupAndOriginalSecGroup.addAll(originalSecGroups);
250             }
251             newSecGroups = new SecurityGroupsBuilder(originalNeutron.getSecurityGroups())
252                 .setSecurityGroup(eigSecGroupAndOriginalSecGroup).build();
253         } else {
254             newSecGroups = new SecurityGroupsBuilder().setSecurityGroup(eigSecGroupAndOriginalSecGroup).build();
255         }
256         newNeutronBuilder.setSecurityGroups(newSecGroups);
257     }
258
259     private Set<Uuid> resolveTenantsFromNetworks(List<Network> networks) {
260         return FluentIterable.from(networks).transform(new Function<Network, Uuid>() {
261
262             @Override
263             public Uuid apply(Network network) {
264                 return network.getTenantId();
265             }
266         }).toSet();
267     }
268
269     private List<SecurityRule> createEigSecurityRules(Uuid tenant) {
270         List<SecurityRule> eigSecRules = new ArrayList<>();
271         eigSecRules.add(EIG_INGRESS_IPV4_SEC_RULE_BUILDER.setTenantId(tenant).build());
272         eigSecRules.add(EIG_EGRESS_IPV4_SEC_RULE_BUILDER.setTenantId(tenant).build());
273         eigSecRules.add(EIG_INGRESS_IPV6_SEC_RULE_BUILDER.setTenantId(tenant).build());
274         eigSecRules.add(EIG_EGRESS_IPV6_SEC_RULE_BUILDER.setTenantId(tenant).build());
275         return eigSecRules;
276     }
277
278     /**
279      * Finds all modified subnodes of given type in {@link Neutron} node.
280      *
281      * @param <T> dataObject type
282      * @param iid path to data in root node
283      * @param rootNode modified data of {@link Neutron} node
284      * @return {@link List} of modified subnodes
285      */
286     private <T extends DataObject> List<DataObjectModification<T>> findModifiedData(InstanceIdentifier<T> iid,
287             DataObjectModification<Neutron> rootNode) {
288         List<DataObjectModification<T>> modDtos = new ArrayList<>();
289         PeekingIterator<PathArgument> pathArgs = Iterators.peekingIterator(iid.getPathArguments().iterator());
290         DataObjectModification<? extends DataObject> modifDto = rootNode;
291         while (pathArgs.hasNext()) {
292             pathArgs.next();
293             for (DataObjectModification<? extends DataObject> childDto : modifDto.getModifiedChildren()) {
294                 if (pathArgs.hasNext() && childDto.getDataType().equals(pathArgs.peek().getType())) {
295                     if (childDto.getDataType().equals(iid.getTargetType())) {
296                         modDtos.add((DataObjectModification<T>) childDto);
297                     } else {
298                         modifDto = childDto;
299                         break;
300                     }
301                 }
302             }
303         }
304         return modDtos;
305     }
306
307     @Override
308     public void close() {
309         registerDataTreeChangeListener.close();
310     }
311
312 }