Add yang generated packages in .gitignore
[groupbasedpolicy.git] / neutron-mapper / src / main / java / org / opendaylight / groupbasedpolicy / neutron / mapper / mapping / rule / NeutronSecurityRuleAware.java
1 package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.rule;
2
3 import static com.google.common.base.Preconditions.checkNotNull;
4
5 import java.util.Set;
6
7 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
8 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
9 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
10 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
11 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.StatusCode;
12 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.group.SecGroupDao;
13 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
14 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
15 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
16 import org.opendaylight.groupbasedpolicy.util.IidFactory;
17 import org.opendaylight.neutron.spi.INeutronSecurityRuleAware;
18 import org.opendaylight.neutron.spi.NeutronSecurityRule;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClauseName;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SelectorName;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Contract;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerNamedSelector;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerNamedSelectorBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderNamedSelector;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderNamedSelectorBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstance;
33 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 import com.google.common.annotations.VisibleForTesting;
38 import com.google.common.base.Strings;
39 import com.google.common.collect.HashMultiset;
40 import com.google.common.collect.ImmutableList;
41 import com.google.common.collect.Multiset;
42 import com.google.common.collect.Sets;
43
44 public class NeutronSecurityRuleAware implements INeutronSecurityRuleAware {
45
46     private static final Logger LOG = LoggerFactory.getLogger(NeutronSecurityRuleAware.class);
47     private static final String CONTRACT_PROVIDER = "Contract provider: ";
48     private final DataBroker dataProvider;
49     private final SecRuleDao secRuleDao;
50     private final SecGroupDao secGroupDao;
51     private final Multiset<InstanceIdentifier<ClassifierInstance>> createdClassifierInstances;
52     private final Multiset<InstanceIdentifier<ActionInstance>> createdActionInstances;
53     final static String PROVIDED_BY = "provided_by-";
54     final static String POSSIBLE_CONSUMER = "possible_consumer-";
55
56     public NeutronSecurityRuleAware(DataBroker dataProvider, SecRuleDao secRuleDao, SecGroupDao secGroupDao) {
57         this(dataProvider, secRuleDao, secGroupDao, HashMultiset.<InstanceIdentifier<ClassifierInstance>>create(),
58                 HashMultiset.<InstanceIdentifier<ActionInstance>>create());
59     }
60
61     @VisibleForTesting
62     NeutronSecurityRuleAware(DataBroker dataProvider, SecRuleDao secRuleDao, SecGroupDao secGroupDao,
63             Multiset<InstanceIdentifier<ClassifierInstance>> classifierInstanceNames,
64             Multiset<InstanceIdentifier<ActionInstance>> createdActionInstances) {
65         this.dataProvider = checkNotNull(dataProvider);
66         this.secRuleDao = checkNotNull(secRuleDao);
67         this.secGroupDao = checkNotNull(secGroupDao);
68         this.createdClassifierInstances = checkNotNull(classifierInstanceNames);
69         this.createdActionInstances = checkNotNull(createdActionInstances);
70     }
71
72     @Override
73     public int canCreateNeutronSecurityRule(NeutronSecurityRule securityRule) {
74         LOG.trace("canCreateNeutronSecurityRule - {}", securityRule);
75         // nothing to consider
76         return StatusCode.OK;
77     }
78
79     @Override
80     public void neutronSecurityRuleCreated(NeutronSecurityRule securityRule) {
81         LOG.trace("neutronSecurityRuleCreated - {}", securityRule);
82         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
83         boolean isNeutronSecurityRuleAdded = addNeutronSecurityRule(securityRule, rwTx);
84         if (isNeutronSecurityRuleAdded) {
85             DataStoreHelper.submitToDs(rwTx);
86         } else {
87             rwTx.cancel();
88         }
89     }
90
91     /**
92      * @param secRule this security group rule will be translate to single rule inside single
93      *        subject inside a contract
94      * @param rwTx GBP entities are stored to this transaction. This method NEVER submits or cancel
95      *        the transaction.
96      * @return {@code true} if operation was successful; {@code false} if an illegal state occurs -
97      *         the transaction may contain just partial result
98      */
99     public boolean addNeutronSecurityRule(NeutronSecurityRule secRule, ReadWriteTransaction rwTx) {
100         TenantId tenantId = SecRuleEntityDecoder.getTenantId(secRule);
101         EndpointGroupId providerEpgId = SecRuleEntityDecoder.getProviderEpgId(secRule);
102         secRuleDao.addSecRule(secRule);
103
104         Description contractDescription = new Description(CONTRACT_PROVIDER
105                 + secGroupDao.getNameOrIdOfSecGroup(providerEpgId));
106         SingleRuleContract singleRuleContract = createSingleRuleContract(secRule, contractDescription);
107         Contract contract = singleRuleContract.getContract();
108         rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.contractIid(tenantId, contract.getId()), contract, true);
109         SelectorName providerSelector = getSelectorNameWithConsumer(secRule);
110         writeProviderNamedSelectorToEpg(providerSelector, contract.getId(), new EgKey(tenantId, providerEpgId), rwTx);
111
112         if (SecRuleEntityDecoder.getConsumerEpgId(secRule) != null) {
113             EndpointGroupId consumerEpgId = SecRuleEntityDecoder.getConsumerEpgId(secRule);
114             designContractsBetweenProviderAndConsumer(tenantId, providerEpgId, consumerEpgId, rwTx);
115             designContractsBetweenProviderAndConsumer(tenantId, consumerEpgId, providerEpgId, rwTx);
116         } else {
117             for (EndpointGroupId consumerEpgId : secRuleDao.getAllOwnerSecGrps()) {
118                 designContractsBetweenProviderAndConsumer(tenantId, providerEpgId, consumerEpgId, rwTx);
119                 designContractsBetweenProviderAndConsumer(tenantId, consumerEpgId, providerEpgId, rwTx);
120             }
121         }
122
123         ClassifierInstance classifierInstance = singleRuleContract.getSingleClassifierRule().getClassifierInstance();
124         createClassifierInstanceIfNotExists(tenantId, classifierInstance, rwTx);
125         createAllowActionInstanceIfNotExists(tenantId, rwTx);
126         return true;
127     }
128
129     @VisibleForTesting
130     static SingleRuleContract createSingleRuleContract(NeutronSecurityRule secRule, Description contractDescription) {
131         if (Strings.isNullOrEmpty(secRule.getSecurityRuleRemoteIpPrefix())) {
132             return new SingleRuleContract(secRule, 0, contractDescription);
133         }
134         return new SingleRuleContract(secRule, 1, contractDescription);
135     }
136
137     @VisibleForTesting
138     void designContractsBetweenProviderAndConsumer(TenantId tenantId, EndpointGroupId provEpgId,
139             EndpointGroupId consEpgId, ReadWriteTransaction rwTx) {
140         Set<NeutronSecurityRule> provSecRules = getProvidedSecRulesBetween(provEpgId, consEpgId);
141         Set<NeutronSecurityRule> consSecRules = getProvidedSecRulesBetween(consEpgId, provEpgId);
142         for (NeutronSecurityRule provSecRule : provSecRules) {
143             if (isProviderSecRuleSuitableForConsumerSecRules(provSecRule, consSecRules)) {
144                 SelectorName consumerSelector = getSelectorNameWithProvider(provSecRule);
145                 ContractId contractId = SecRuleEntityDecoder.getContractId(provSecRule);
146                 writeConsumerNamedSelectorToEpg(consumerSelector, contractId, new EgKey(tenantId, consEpgId), rwTx);
147             }
148             // TODO add case when port ranges overlap
149         }
150     }
151
152     @VisibleForTesting
153     Set<NeutronSecurityRule> getProvidedSecRulesBetween(EndpointGroupId provEpgId, EndpointGroupId consEpgId) {
154         return Sets.union(secRuleDao.getSecRulesBySecGrpIdAndRemoteSecGrpId(provEpgId, consEpgId),
155                 secRuleDao.getSecRulesWithoutRemoteSecGrpBySecGrpId(provEpgId));
156     }
157
158     @VisibleForTesting
159     static boolean isProviderSecRuleSuitableForConsumerSecRules(NeutronSecurityRule provSecRule,
160             Set<NeutronSecurityRule> consSecRules) {
161         Direction directionProvSecRule = SecRuleEntityDecoder.getDirection(provSecRule);
162         for (NeutronSecurityRule consSecRule : consSecRules) {
163             Direction directionConsSecRule = SecRuleEntityDecoder.getDirection(consSecRule);
164             if (isDirectionOpposite(directionProvSecRule, directionConsSecRule)
165                     && isOneWithinTwo(provSecRule, consSecRule)) {
166                 return true;
167             }
168         }
169         return false;
170     }
171
172     private void writeProviderNamedSelectorToEpg(SelectorName providerSelector, ContractId contractId, EgKey epgKey,
173             WriteTransaction wTx) {
174         ProviderNamedSelector providerNamedSelector = new ProviderNamedSelectorBuilder().setName(providerSelector)
175             .setContract(ImmutableList.of(contractId))
176             .build();
177         wTx.put(LogicalDatastoreType.CONFIGURATION,
178                 IidFactory.providerNamedSelectorIid(epgKey.getTenantId(), epgKey.getEgId(),
179                         providerNamedSelector.getName()), providerNamedSelector, true);
180     }
181
182     private void writeConsumerNamedSelectorToEpg(SelectorName consumerSelector, ContractId contractId, EgKey epgKey,
183             WriteTransaction wTx) {
184         ConsumerNamedSelector consumerNamedSelector = new ConsumerNamedSelectorBuilder().setName(consumerSelector)
185             .setContract(ImmutableList.of(contractId))
186             .build();
187         wTx.put(LogicalDatastoreType.CONFIGURATION,
188                 IidFactory.consumerNamedSelectorIid(epgKey.getTenantId(), epgKey.getEgId(),
189                         consumerNamedSelector.getName()), consumerNamedSelector, true);
190     }
191
192     @VisibleForTesting
193     void createClassifierInstanceIfNotExists(TenantId tenantId, ClassifierInstance classifierInstance,
194             WriteTransaction wTx) {
195         InstanceIdentifier<ClassifierInstance> classifierInstanceIid = IidFactory.classifierInstanceIid(tenantId,
196                 classifierInstance.getName());
197         if (!createdClassifierInstances.contains(classifierInstanceIid)) {
198             wTx.put(LogicalDatastoreType.CONFIGURATION, classifierInstanceIid, classifierInstance, true);
199         }
200         createdClassifierInstances.add(classifierInstanceIid);
201     }
202
203     @VisibleForTesting
204     void createAllowActionInstanceIfNotExists(TenantId tenantId, ReadWriteTransaction rwTx) {
205         InstanceIdentifier<ActionInstance> actionInstanceIid = IidFactory.actionInstanceIid(tenantId,
206                 MappingUtils.ACTION_ALLOW.getName());
207         if (!createdActionInstances.contains(actionInstanceIid)) {
208             rwTx.put(LogicalDatastoreType.CONFIGURATION, actionInstanceIid, MappingUtils.ACTION_ALLOW, true);
209         }
210         createdActionInstances.add(actionInstanceIid);
211     }
212
213     @Override
214     public int canUpdateNeutronSecurityRule(NeutronSecurityRule delta, NeutronSecurityRule original) {
215         LOG.warn("canUpdateNeutronSecurityRule - Never should be called "
216                 + "- neutron API does not allow UPDATE on neutron security group rule. \nDelta: {} \nOriginal: {}",
217                 delta, original);
218         return StatusCode.BAD_REQUEST;
219     }
220
221     @Override
222     public void neutronSecurityRuleUpdated(NeutronSecurityRule securityRule) {
223         LOG.warn("neutronSecurityRuleUpdated - Never should be called "
224                 + "- neutron API does not allow UPDATE on neutron security group rule. \nSecurity group rule: {}",
225                 securityRule);
226     }
227
228     @Override
229     public int canDeleteNeutronSecurityRule(NeutronSecurityRule securityRule) {
230         LOG.trace("canDeleteNeutronSecurityRule - {}", securityRule);
231         // nothing to consider
232         return StatusCode.OK;
233     }
234
235     @Override
236     public void neutronSecurityRuleDeleted(NeutronSecurityRule secRule) {
237         LOG.trace("neutronSecurityRuleCreated - {}", secRule);
238         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
239         boolean isNeutronSecurityRuleDeleted = deleteNeutronSecurityRule(secRule, rwTx);
240         if (isNeutronSecurityRuleDeleted) {
241             DataStoreHelper.submitToDs(rwTx);
242         } else {
243             rwTx.cancel();
244         }
245     }
246
247     public boolean deleteNeutronSecurityRule(NeutronSecurityRule secRule, ReadWriteTransaction rwTx) {
248         TenantId tenantId = SecRuleEntityDecoder.getTenantId(secRule);
249         EndpointGroupId providerEpgId = SecRuleEntityDecoder.getProviderEpgId(secRule);
250
251         SelectorName providerSelector = getSelectorNameWithConsumer(secRule);
252         deleteProviderNamedSelectorFromEpg(providerSelector, new EgKey(tenantId, providerEpgId), rwTx);
253
254         if (SecRuleEntityDecoder.getConsumerEpgId(secRule) != null) {
255             EndpointGroupId consumerEpgId = SecRuleEntityDecoder.getConsumerEpgId(secRule);
256             undesignContractsBetweenProviderAndConsumer(tenantId, providerEpgId, consumerEpgId, secRule, rwTx);
257             undesignContractsBetweenProviderAndConsumer(tenantId, consumerEpgId, providerEpgId, secRule, rwTx);
258         } else {
259             for (EndpointGroupId consumerEpgId : secRuleDao.getAllOwnerSecGrps()) {
260                 undesignContractsBetweenProviderAndConsumer(tenantId, providerEpgId, consumerEpgId, secRule, rwTx);
261                 undesignContractsBetweenProviderAndConsumer(tenantId, consumerEpgId, providerEpgId, secRule, rwTx);
262             }
263         }
264
265         secRuleDao.removeSecRule(secRule);
266         ContractId contractId = SecRuleEntityDecoder.getContractId(secRule);
267         rwTx.delete(LogicalDatastoreType.CONFIGURATION, IidFactory.contractIid(tenantId, contractId));
268
269         ClassifierInstance classifierInstance = SecRuleEntityDecoder.getClassifierInstance(secRule);
270         deleteClassifierInstanceIfNotUsed(tenantId, classifierInstance, rwTx);
271         return true;
272     }
273
274     @VisibleForTesting
275     void undesignContractsBetweenProviderAndConsumer(TenantId tenantId, EndpointGroupId provEpgId,
276             EndpointGroupId consEpgId, NeutronSecurityRule removedSecRule, ReadWriteTransaction rwTx) {
277         Set<NeutronSecurityRule> provSecRules = getProvidedSecRulesBetween(provEpgId, consEpgId);
278         Set<NeutronSecurityRule> consSecRules = getProvidedSecRulesBetween(consEpgId, provEpgId);
279         for (NeutronSecurityRule provSecRule : provSecRules) {
280             if (isProvidersSecRuleSuitableForConsumersSecRulesAndGoodToRemove(provSecRule, consSecRules, removedSecRule)) {
281                 SelectorName consumerSelector = getSelectorNameWithProvider(provSecRule);
282                 deleteConsumerNamedSelector(consumerSelector, new EgKey(tenantId, consEpgId), rwTx);
283             }
284             // TODO add case when port ranges overlap
285         }
286     }
287
288     @VisibleForTesting
289     static boolean isProvidersSecRuleSuitableForConsumersSecRulesAndGoodToRemove(NeutronSecurityRule provSecRule,
290             Set<NeutronSecurityRule> consSecRules, NeutronSecurityRule removedSecRule) {
291         Direction directionProvSecRule = SecRuleEntityDecoder.getDirection(provSecRule);
292         for (NeutronSecurityRule consSecRule : consSecRules) {
293             if (isRuleIdEqual(removedSecRule, consSecRule) || isRuleIdEqual(removedSecRule, provSecRule)) {
294                 Direction directionConsSecRule = SecRuleEntityDecoder.getDirection(consSecRule);
295                 if (isDirectionOpposite(directionProvSecRule, directionConsSecRule)
296                         && isOneWithinTwo(provSecRule, consSecRule)) {
297                     return true;
298                 }
299             }
300         }
301         return false;
302     }
303
304     @VisibleForTesting
305     static boolean isRuleIdEqual(NeutronSecurityRule one, NeutronSecurityRule two) {
306         checkNotNull(one);
307         checkNotNull(two);
308         return one.getSecurityRuleUUID().equals(two.getSecurityRuleUUID());
309     }
310
311     private void deleteProviderNamedSelectorFromEpg(SelectorName providerSelector, EgKey providerEpgKey,
312             ReadWriteTransaction rwTx) {
313         InstanceIdentifier<ProviderNamedSelector> providerSelectorIid = IidFactory.providerNamedSelectorIid(
314                 providerEpgKey.getTenantId(), providerEpgKey.getEgId(), providerSelector);
315         DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION, providerSelectorIid, rwTx);
316     }
317
318     private void deleteConsumerNamedSelector(SelectorName consumerSelector, EgKey consumerEpgKey,
319             ReadWriteTransaction rwTx) {
320         InstanceIdentifier<ConsumerNamedSelector> consumerSelectorIid = IidFactory.consumerNamedSelectorIid(
321                 consumerEpgKey.getTenantId(), consumerEpgKey.getEgId(), consumerSelector);
322         DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION, consumerSelectorIid, rwTx);
323     }
324
325     private void deleteClassifierInstanceIfNotUsed(TenantId tenantId, ClassifierInstance classifierInstance,
326             ReadWriteTransaction rwTx) {
327         InstanceIdentifier<ClassifierInstance> classifierInstanceIid = IidFactory.classifierInstanceIid(tenantId,
328                 classifierInstance.getName());
329         createdClassifierInstances.remove(classifierInstanceIid);
330         if (!createdClassifierInstances.contains(classifierInstanceIid)) {
331             DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION, classifierInstanceIid, rwTx);
332         }
333     }
334
335     @VisibleForTesting
336     void deleteAllowActionInstanceIfNotUsed(TenantId tenantId, ReadWriteTransaction rwTx) {
337         InstanceIdentifier<ActionInstance> actionInstanceIid = IidFactory.actionInstanceIid(tenantId,
338                 MappingUtils.ACTION_ALLOW.getName());
339         createdActionInstances.remove(actionInstanceIid);
340         if (!createdActionInstances.contains(actionInstanceIid)) {
341             DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION, actionInstanceIid, rwTx);
342         }
343     }
344
345     private SelectorName getSelectorNameWithConsumer(NeutronSecurityRule secRule) {
346         ClauseName clauseName = SecRuleNameDecoder.getClauseName(secRule);
347         StringBuilder selectorNameBuilder = new StringBuilder().append(clauseName.getValue());
348         EndpointGroupId consumerEpgId = SecRuleEntityDecoder.getConsumerEpgId(secRule);
349         if (consumerEpgId != null) {
350             selectorNameBuilder.append(MappingUtils.NAME_DOUBLE_DELIMETER)
351                 .append(POSSIBLE_CONSUMER)
352                 .append(secGroupDao.getNameOrIdOfSecGroup(consumerEpgId));
353         }
354         return new SelectorName(selectorNameBuilder.toString());
355     }
356
357     private SelectorName getSelectorNameWithProvider(NeutronSecurityRule secRule) {
358         ClauseName clauseName = SecRuleNameDecoder.getClauseName(secRule);
359         EndpointGroupId providerEpgId = SecRuleEntityDecoder.getProviderEpgId(secRule);
360         String selectorName = new StringBuilder().append(clauseName.getValue())
361             .append(MappingUtils.NAME_DOUBLE_DELIMETER)
362             .append(PROVIDED_BY)
363             .append(secGroupDao.getNameOrIdOfSecGroup(providerEpgId))
364             .toString();
365         return new SelectorName(selectorName);
366     }
367
368     @VisibleForTesting
369     static boolean isDirectionOpposite(Direction one, Direction two) {
370         return (one == Direction.In && two == Direction.Out) || (one == Direction.Out && two == Direction.In);
371     }
372
373     @VisibleForTesting
374     static boolean isOneWithinTwo(NeutronSecurityRule one, NeutronSecurityRule two) {
375         if (!isOneGroupIdWithinTwoRemoteGroupId(one, two) || !isOneGroupIdWithinTwoRemoteGroupId(two, one))
376             return false;
377         if (!SecRuleEntityDecoder.isEtherTypeOfOneWithinTwo(one, two))
378             return false;
379         if (!SecRuleEntityDecoder.isProtocolOfOneWithinTwo(one, two))
380             return false;
381         if (!SecRuleEntityDecoder.isPortsOfOneWithinTwo(one, two))
382             return false;
383         if (!Strings.isNullOrEmpty(two.getSecurityRuleRemoteIpPrefix())
384                 && Strings.isNullOrEmpty(one.getSecurityRuleRemoteIpPrefix()))
385             return false;
386         return true;
387     }
388
389     @VisibleForTesting
390     static boolean isOneGroupIdWithinTwoRemoteGroupId(NeutronSecurityRule one, NeutronSecurityRule two) {
391         return (Strings.isNullOrEmpty(two.getSecurityRemoteGroupID()) || two.getSecurityRemoteGroupID().equals(
392                 one.getSecurityRuleGroupID()));
393     }
394
395 }