2 * Copyright (c) 2014 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.rule;
11 import static com.google.common.base.Preconditions.checkNotNull;
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
17 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.StatusCode;
20 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.group.SecGroupDao;
21 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
22 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
23 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
24 import org.opendaylight.groupbasedpolicy.util.IidFactory;
25 import org.opendaylight.neutron.spi.INeutronSecurityRuleAware;
26 import org.opendaylight.neutron.spi.NeutronSecurityRule;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClauseName;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SelectorName;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Contract;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerNamedSelector;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerNamedSelectorBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderNamedSelector;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderNamedSelectorBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstance;
41 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
45 import com.google.common.annotations.VisibleForTesting;
46 import com.google.common.base.Strings;
47 import com.google.common.collect.HashMultiset;
48 import com.google.common.collect.ImmutableList;
49 import com.google.common.collect.Multiset;
50 import com.google.common.collect.Sets;
52 public class NeutronSecurityRuleAware implements INeutronSecurityRuleAware {
54 private static final Logger LOG = LoggerFactory.getLogger(NeutronSecurityRuleAware.class);
55 private static final String CONTRACT_PROVIDER = "Contract provider: ";
56 private final DataBroker dataProvider;
57 private final SecRuleDao secRuleDao;
58 private final SecGroupDao secGroupDao;
59 private final Multiset<InstanceIdentifier<ClassifierInstance>> createdClassifierInstances;
60 private final Multiset<InstanceIdentifier<ActionInstance>> createdActionInstances;
61 final static String PROVIDED_BY = "provided_by-";
62 final static String POSSIBLE_CONSUMER = "possible_consumer-";
64 public NeutronSecurityRuleAware(DataBroker dataProvider, SecRuleDao secRuleDao, SecGroupDao secGroupDao) {
65 this(dataProvider, secRuleDao, secGroupDao, HashMultiset.<InstanceIdentifier<ClassifierInstance>>create(),
66 HashMultiset.<InstanceIdentifier<ActionInstance>>create());
70 NeutronSecurityRuleAware(DataBroker dataProvider, SecRuleDao secRuleDao, SecGroupDao secGroupDao,
71 Multiset<InstanceIdentifier<ClassifierInstance>> classifierInstanceNames,
72 Multiset<InstanceIdentifier<ActionInstance>> createdActionInstances) {
73 this.dataProvider = checkNotNull(dataProvider);
74 this.secRuleDao = checkNotNull(secRuleDao);
75 this.secGroupDao = checkNotNull(secGroupDao);
76 this.createdClassifierInstances = checkNotNull(classifierInstanceNames);
77 this.createdActionInstances = checkNotNull(createdActionInstances);
81 public int canCreateNeutronSecurityRule(NeutronSecurityRule securityRule) {
82 LOG.trace("canCreateNeutronSecurityRule - {}", securityRule);
83 // nothing to consider
88 public void neutronSecurityRuleCreated(NeutronSecurityRule securityRule) {
89 LOG.trace("neutronSecurityRuleCreated - {}", securityRule);
90 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
91 boolean isNeutronSecurityRuleAdded = addNeutronSecurityRule(securityRule, rwTx);
92 if (isNeutronSecurityRuleAdded) {
93 DataStoreHelper.submitToDs(rwTx);
100 * @param secRule this security group rule will be translate to single rule inside single
101 * subject inside a contract
102 * @param rwTx GBP entities are stored to this transaction. This method NEVER submits or cancel
104 * @return {@code true} if operation was successful; {@code false} if an illegal state occurs -
105 * the transaction may contain just partial result
107 public boolean addNeutronSecurityRule(NeutronSecurityRule secRule, ReadWriteTransaction rwTx) {
108 TenantId tenantId = SecRuleEntityDecoder.getTenantId(secRule);
109 EndpointGroupId providerEpgId = SecRuleEntityDecoder.getProviderEpgId(secRule);
110 secRuleDao.addSecRule(secRule);
112 Description contractDescription = new Description(CONTRACT_PROVIDER
113 + secGroupDao.getNameOrIdOfSecGroup(providerEpgId));
114 SingleRuleContract singleRuleContract = createSingleRuleContract(secRule, contractDescription);
115 Contract contract = singleRuleContract.getContract();
116 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.contractIid(tenantId, contract.getId()), contract, true);
117 SelectorName providerSelector = getSelectorNameWithConsumer(secRule);
118 writeProviderNamedSelectorToEpg(providerSelector, contract.getId(), new EgKey(tenantId, providerEpgId), rwTx);
120 if (SecRuleEntityDecoder.getConsumerEpgId(secRule) != null) {
121 EndpointGroupId consumerEpgId = SecRuleEntityDecoder.getConsumerEpgId(secRule);
122 designContractsBetweenProviderAndConsumer(tenantId, providerEpgId, consumerEpgId, rwTx);
123 designContractsBetweenProviderAndConsumer(tenantId, consumerEpgId, providerEpgId, rwTx);
125 for (EndpointGroupId consumerEpgId : secRuleDao.getAllOwnerSecGrps()) {
126 designContractsBetweenProviderAndConsumer(tenantId, providerEpgId, consumerEpgId, rwTx);
127 designContractsBetweenProviderAndConsumer(tenantId, consumerEpgId, providerEpgId, rwTx);
131 ClassifierInstance classifierInstance = singleRuleContract.getSingleClassifierRule().getClassifierInstance();
132 createClassifierInstanceIfNotExists(tenantId, classifierInstance, rwTx);
133 createAllowActionInstanceIfNotExists(tenantId, rwTx);
138 static SingleRuleContract createSingleRuleContract(NeutronSecurityRule secRule, Description contractDescription) {
139 if (Strings.isNullOrEmpty(secRule.getSecurityRuleRemoteIpPrefix())) {
140 return new SingleRuleContract(secRule, 0, contractDescription);
142 return new SingleRuleContract(secRule, 1, contractDescription);
146 void designContractsBetweenProviderAndConsumer(TenantId tenantId, EndpointGroupId provEpgId,
147 EndpointGroupId consEpgId, ReadWriteTransaction rwTx) {
148 Set<NeutronSecurityRule> provSecRules = getProvidedSecRulesBetween(provEpgId, consEpgId);
149 Set<NeutronSecurityRule> consSecRules = getProvidedSecRulesBetween(consEpgId, provEpgId);
150 for (NeutronSecurityRule provSecRule : provSecRules) {
151 if (isProviderSecRuleSuitableForConsumerSecRules(provSecRule, consSecRules)) {
152 SelectorName consumerSelector = getSelectorNameWithProvider(provSecRule);
153 ContractId contractId = SecRuleEntityDecoder.getContractId(provSecRule);
154 writeConsumerNamedSelectorToEpg(consumerSelector, contractId, new EgKey(tenantId, consEpgId), rwTx);
156 // TODO add case when port ranges overlap
161 Set<NeutronSecurityRule> getProvidedSecRulesBetween(EndpointGroupId provEpgId, EndpointGroupId consEpgId) {
162 return Sets.union(secRuleDao.getSecRulesBySecGrpIdAndRemoteSecGrpId(provEpgId, consEpgId),
163 secRuleDao.getSecRulesWithoutRemoteSecGrpBySecGrpId(provEpgId));
167 static boolean isProviderSecRuleSuitableForConsumerSecRules(NeutronSecurityRule provSecRule,
168 Set<NeutronSecurityRule> consSecRules) {
169 Direction directionProvSecRule = SecRuleEntityDecoder.getDirection(provSecRule);
170 for (NeutronSecurityRule consSecRule : consSecRules) {
171 Direction directionConsSecRule = SecRuleEntityDecoder.getDirection(consSecRule);
172 if (isDirectionOpposite(directionProvSecRule, directionConsSecRule)
173 && isOneWithinTwo(provSecRule, consSecRule)) {
180 private void writeProviderNamedSelectorToEpg(SelectorName providerSelector, ContractId contractId, EgKey epgKey,
181 WriteTransaction wTx) {
182 ProviderNamedSelector providerNamedSelector = new ProviderNamedSelectorBuilder().setName(providerSelector)
183 .setContract(ImmutableList.of(contractId))
185 wTx.put(LogicalDatastoreType.CONFIGURATION,
186 IidFactory.providerNamedSelectorIid(epgKey.getTenantId(), epgKey.getEgId(),
187 providerNamedSelector.getName()), providerNamedSelector, true);
190 private void writeConsumerNamedSelectorToEpg(SelectorName consumerSelector, ContractId contractId, EgKey epgKey,
191 WriteTransaction wTx) {
192 ConsumerNamedSelector consumerNamedSelector = new ConsumerNamedSelectorBuilder().setName(consumerSelector)
193 .setContract(ImmutableList.of(contractId))
195 wTx.put(LogicalDatastoreType.CONFIGURATION,
196 IidFactory.consumerNamedSelectorIid(epgKey.getTenantId(), epgKey.getEgId(),
197 consumerNamedSelector.getName()), consumerNamedSelector, true);
201 void createClassifierInstanceIfNotExists(TenantId tenantId, ClassifierInstance classifierInstance,
202 WriteTransaction wTx) {
203 InstanceIdentifier<ClassifierInstance> classifierInstanceIid = IidFactory.classifierInstanceIid(tenantId,
204 classifierInstance.getName());
205 if (!createdClassifierInstances.contains(classifierInstanceIid)) {
206 wTx.put(LogicalDatastoreType.CONFIGURATION, classifierInstanceIid, classifierInstance, true);
208 createdClassifierInstances.add(classifierInstanceIid);
212 void createAllowActionInstanceIfNotExists(TenantId tenantId, ReadWriteTransaction rwTx) {
213 InstanceIdentifier<ActionInstance> actionInstanceIid = IidFactory.actionInstanceIid(tenantId,
214 MappingUtils.ACTION_ALLOW.getName());
215 if (!createdActionInstances.contains(actionInstanceIid)) {
216 rwTx.put(LogicalDatastoreType.CONFIGURATION, actionInstanceIid, MappingUtils.ACTION_ALLOW, true);
218 createdActionInstances.add(actionInstanceIid);
222 public int canUpdateNeutronSecurityRule(NeutronSecurityRule delta, NeutronSecurityRule original) {
223 LOG.warn("canUpdateNeutronSecurityRule - Never should be called "
224 + "- neutron API does not allow UPDATE on neutron security group rule. \nDelta: {} \nOriginal: {}",
226 return StatusCode.BAD_REQUEST;
230 public void neutronSecurityRuleUpdated(NeutronSecurityRule securityRule) {
231 LOG.warn("neutronSecurityRuleUpdated - Never should be called "
232 + "- neutron API does not allow UPDATE on neutron security group rule. \nSecurity group rule: {}",
237 public int canDeleteNeutronSecurityRule(NeutronSecurityRule securityRule) {
238 LOG.trace("canDeleteNeutronSecurityRule - {}", securityRule);
239 // nothing to consider
240 return StatusCode.OK;
244 public void neutronSecurityRuleDeleted(NeutronSecurityRule secRule) {
245 LOG.trace("neutronSecurityRuleCreated - {}", secRule);
246 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
247 boolean isNeutronSecurityRuleDeleted = deleteNeutronSecurityRule(secRule, rwTx);
248 if (isNeutronSecurityRuleDeleted) {
249 DataStoreHelper.submitToDs(rwTx);
255 public boolean deleteNeutronSecurityRule(NeutronSecurityRule secRule, ReadWriteTransaction rwTx) {
256 TenantId tenantId = SecRuleEntityDecoder.getTenantId(secRule);
257 EndpointGroupId providerEpgId = SecRuleEntityDecoder.getProviderEpgId(secRule);
259 SelectorName providerSelector = getSelectorNameWithConsumer(secRule);
260 deleteProviderNamedSelectorFromEpg(providerSelector, new EgKey(tenantId, providerEpgId), rwTx);
262 if (SecRuleEntityDecoder.getConsumerEpgId(secRule) != null) {
263 EndpointGroupId consumerEpgId = SecRuleEntityDecoder.getConsumerEpgId(secRule);
264 undesignContractsBetweenProviderAndConsumer(tenantId, providerEpgId, consumerEpgId, secRule, rwTx);
265 undesignContractsBetweenProviderAndConsumer(tenantId, consumerEpgId, providerEpgId, secRule, rwTx);
267 for (EndpointGroupId consumerEpgId : secRuleDao.getAllOwnerSecGrps()) {
268 undesignContractsBetweenProviderAndConsumer(tenantId, providerEpgId, consumerEpgId, secRule, rwTx);
269 undesignContractsBetweenProviderAndConsumer(tenantId, consumerEpgId, providerEpgId, secRule, rwTx);
273 secRuleDao.removeSecRule(secRule);
274 ContractId contractId = SecRuleEntityDecoder.getContractId(secRule);
275 rwTx.delete(LogicalDatastoreType.CONFIGURATION, IidFactory.contractIid(tenantId, contractId));
277 ClassifierInstance classifierInstance = SecRuleEntityDecoder.getClassifierInstance(secRule);
278 deleteClassifierInstanceIfNotUsed(tenantId, classifierInstance, rwTx);
283 void undesignContractsBetweenProviderAndConsumer(TenantId tenantId, EndpointGroupId provEpgId,
284 EndpointGroupId consEpgId, NeutronSecurityRule removedSecRule, ReadWriteTransaction rwTx) {
285 Set<NeutronSecurityRule> provSecRules = getProvidedSecRulesBetween(provEpgId, consEpgId);
286 Set<NeutronSecurityRule> consSecRules = getProvidedSecRulesBetween(consEpgId, provEpgId);
287 for (NeutronSecurityRule provSecRule : provSecRules) {
288 if (isProvidersSecRuleSuitableForConsumersSecRulesAndGoodToRemove(provSecRule, consSecRules, removedSecRule)) {
289 SelectorName consumerSelector = getSelectorNameWithProvider(provSecRule);
290 deleteConsumerNamedSelector(consumerSelector, new EgKey(tenantId, consEpgId), rwTx);
292 // TODO add case when port ranges overlap
297 static boolean isProvidersSecRuleSuitableForConsumersSecRulesAndGoodToRemove(NeutronSecurityRule provSecRule,
298 Set<NeutronSecurityRule> consSecRules, NeutronSecurityRule removedSecRule) {
299 Direction directionProvSecRule = SecRuleEntityDecoder.getDirection(provSecRule);
300 for (NeutronSecurityRule consSecRule : consSecRules) {
301 if (isRuleIdEqual(removedSecRule, consSecRule) || isRuleIdEqual(removedSecRule, provSecRule)) {
302 Direction directionConsSecRule = SecRuleEntityDecoder.getDirection(consSecRule);
303 if (isDirectionOpposite(directionProvSecRule, directionConsSecRule)
304 && isOneWithinTwo(provSecRule, consSecRule)) {
313 static boolean isRuleIdEqual(NeutronSecurityRule one, NeutronSecurityRule two) {
316 return one.getSecurityRuleUUID().equals(two.getSecurityRuleUUID());
319 private void deleteProviderNamedSelectorFromEpg(SelectorName providerSelector, EgKey providerEpgKey,
320 ReadWriteTransaction rwTx) {
321 InstanceIdentifier<ProviderNamedSelector> providerSelectorIid = IidFactory.providerNamedSelectorIid(
322 providerEpgKey.getTenantId(), providerEpgKey.getEgId(), providerSelector);
323 DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION, providerSelectorIid, rwTx);
326 private void deleteConsumerNamedSelector(SelectorName consumerSelector, EgKey consumerEpgKey,
327 ReadWriteTransaction rwTx) {
328 InstanceIdentifier<ConsumerNamedSelector> consumerSelectorIid = IidFactory.consumerNamedSelectorIid(
329 consumerEpgKey.getTenantId(), consumerEpgKey.getEgId(), consumerSelector);
330 DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION, consumerSelectorIid, rwTx);
333 private void deleteClassifierInstanceIfNotUsed(TenantId tenantId, ClassifierInstance classifierInstance,
334 ReadWriteTransaction rwTx) {
335 InstanceIdentifier<ClassifierInstance> classifierInstanceIid = IidFactory.classifierInstanceIid(tenantId,
336 classifierInstance.getName());
337 createdClassifierInstances.remove(classifierInstanceIid);
338 if (!createdClassifierInstances.contains(classifierInstanceIid)) {
339 DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION, classifierInstanceIid, rwTx);
344 void deleteAllowActionInstanceIfNotUsed(TenantId tenantId, ReadWriteTransaction rwTx) {
345 InstanceIdentifier<ActionInstance> actionInstanceIid = IidFactory.actionInstanceIid(tenantId,
346 MappingUtils.ACTION_ALLOW.getName());
347 createdActionInstances.remove(actionInstanceIid);
348 if (!createdActionInstances.contains(actionInstanceIid)) {
349 DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION, actionInstanceIid, rwTx);
353 private SelectorName getSelectorNameWithConsumer(NeutronSecurityRule secRule) {
354 ClauseName clauseName = SecRuleNameDecoder.getClauseName(secRule);
355 StringBuilder selectorNameBuilder = new StringBuilder().append(clauseName.getValue());
356 EndpointGroupId consumerEpgId = SecRuleEntityDecoder.getConsumerEpgId(secRule);
357 if (consumerEpgId != null) {
358 selectorNameBuilder.append(MappingUtils.NAME_DOUBLE_DELIMETER)
359 .append(POSSIBLE_CONSUMER)
360 .append(secGroupDao.getNameOrIdOfSecGroup(consumerEpgId));
362 return new SelectorName(selectorNameBuilder.toString());
365 private SelectorName getSelectorNameWithProvider(NeutronSecurityRule secRule) {
366 ClauseName clauseName = SecRuleNameDecoder.getClauseName(secRule);
367 EndpointGroupId providerEpgId = SecRuleEntityDecoder.getProviderEpgId(secRule);
368 String selectorName = new StringBuilder().append(clauseName.getValue())
369 .append(MappingUtils.NAME_DOUBLE_DELIMETER)
371 .append(secGroupDao.getNameOrIdOfSecGroup(providerEpgId))
373 return new SelectorName(selectorName);
377 static boolean isDirectionOpposite(Direction one, Direction two) {
378 return (one == Direction.In && two == Direction.Out) || (one == Direction.Out && two == Direction.In);
382 static boolean isOneWithinTwo(NeutronSecurityRule one, NeutronSecurityRule two) {
383 if (!isOneGroupIdWithinTwoRemoteGroupId(one, two) || !isOneGroupIdWithinTwoRemoteGroupId(two, one))
385 if (!SecRuleEntityDecoder.isEtherTypeOfOneWithinTwo(one, two))
387 if (!SecRuleEntityDecoder.isProtocolOfOneWithinTwo(one, two))
389 if (!SecRuleEntityDecoder.isPortsOfOneWithinTwo(one, two))
391 if (!Strings.isNullOrEmpty(two.getSecurityRuleRemoteIpPrefix())
392 && Strings.isNullOrEmpty(one.getSecurityRuleRemoteIpPrefix()))
398 static boolean isOneGroupIdWithinTwoRemoteGroupId(NeutronSecurityRule one, NeutronSecurityRule two) {
399 return (Strings.isNullOrEmpty(two.getSecurityRemoteGroupID()) || two.getSecurityRemoteGroupID().equals(
400 one.getSecurityRuleGroupID()));