1 package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.rule;
3 import static com.google.common.base.Preconditions.checkNotNull;
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;
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;
44 public class NeutronSecurityRuleAware implements INeutronSecurityRuleAware {
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-";
56 public NeutronSecurityRuleAware(DataBroker dataProvider, SecRuleDao secRuleDao, SecGroupDao secGroupDao) {
57 this(dataProvider, secRuleDao, secGroupDao, HashMultiset.<InstanceIdentifier<ClassifierInstance>>create(),
58 HashMultiset.<InstanceIdentifier<ActionInstance>>create());
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);
73 public int canCreateNeutronSecurityRule(NeutronSecurityRule securityRule) {
74 LOG.trace("canCreateNeutronSecurityRule - {}", securityRule);
75 // nothing to consider
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);
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
96 * @return {@code true} if operation was successful; {@code false} if an illegal state occurs -
97 * the transaction may contain just partial result
99 public boolean addNeutronSecurityRule(NeutronSecurityRule secRule, ReadWriteTransaction rwTx) {
100 TenantId tenantId = SecRuleEntityDecoder.getTenantId(secRule);
101 EndpointGroupId providerEpgId = SecRuleEntityDecoder.getProviderEpgId(secRule);
102 secRuleDao.addSecRule(secRule);
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);
112 if (SecRuleEntityDecoder.getConsumerEpgId(secRule) != null) {
113 EndpointGroupId consumerEpgId = SecRuleEntityDecoder.getConsumerEpgId(secRule);
114 designContractsBetweenProviderAndConsumer(tenantId, providerEpgId, consumerEpgId, rwTx);
115 designContractsBetweenProviderAndConsumer(tenantId, consumerEpgId, providerEpgId, rwTx);
117 for (EndpointGroupId consumerEpgId : secRuleDao.getAllOwnerSecGrps()) {
118 designContractsBetweenProviderAndConsumer(tenantId, providerEpgId, consumerEpgId, rwTx);
119 designContractsBetweenProviderAndConsumer(tenantId, consumerEpgId, providerEpgId, rwTx);
123 ClassifierInstance classifierInstance = singleRuleContract.getSingleClassifierRule().getClassifierInstance();
124 createClassifierInstanceIfNotExists(tenantId, classifierInstance, rwTx);
125 createAllowActionInstanceIfNotExists(tenantId, rwTx);
130 static SingleRuleContract createSingleRuleContract(NeutronSecurityRule secRule, Description contractDescription) {
131 if (Strings.isNullOrEmpty(secRule.getSecurityRuleRemoteIpPrefix())) {
132 return new SingleRuleContract(secRule, 0, contractDescription);
134 return new SingleRuleContract(secRule, 1, contractDescription);
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);
148 // TODO add case when port ranges overlap
153 Set<NeutronSecurityRule> getProvidedSecRulesBetween(EndpointGroupId provEpgId, EndpointGroupId consEpgId) {
154 return Sets.union(secRuleDao.getSecRulesBySecGrpIdAndRemoteSecGrpId(provEpgId, consEpgId),
155 secRuleDao.getSecRulesWithoutRemoteSecGrpBySecGrpId(provEpgId));
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)) {
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))
177 wTx.put(LogicalDatastoreType.CONFIGURATION,
178 IidFactory.providerNamedSelectorIid(epgKey.getTenantId(), epgKey.getEgId(),
179 providerNamedSelector.getName()), providerNamedSelector, true);
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))
187 wTx.put(LogicalDatastoreType.CONFIGURATION,
188 IidFactory.consumerNamedSelectorIid(epgKey.getTenantId(), epgKey.getEgId(),
189 consumerNamedSelector.getName()), consumerNamedSelector, true);
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);
200 createdClassifierInstances.add(classifierInstanceIid);
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);
210 createdActionInstances.add(actionInstanceIid);
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: {}",
218 return StatusCode.BAD_REQUEST;
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: {}",
229 public int canDeleteNeutronSecurityRule(NeutronSecurityRule securityRule) {
230 LOG.trace("canDeleteNeutronSecurityRule - {}", securityRule);
231 // nothing to consider
232 return StatusCode.OK;
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);
247 public boolean deleteNeutronSecurityRule(NeutronSecurityRule secRule, ReadWriteTransaction rwTx) {
248 TenantId tenantId = SecRuleEntityDecoder.getTenantId(secRule);
249 EndpointGroupId providerEpgId = SecRuleEntityDecoder.getProviderEpgId(secRule);
251 SelectorName providerSelector = getSelectorNameWithConsumer(secRule);
252 deleteProviderNamedSelectorFromEpg(providerSelector, new EgKey(tenantId, providerEpgId), rwTx);
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);
259 for (EndpointGroupId consumerEpgId : secRuleDao.getAllOwnerSecGrps()) {
260 undesignContractsBetweenProviderAndConsumer(tenantId, providerEpgId, consumerEpgId, secRule, rwTx);
261 undesignContractsBetweenProviderAndConsumer(tenantId, consumerEpgId, providerEpgId, secRule, rwTx);
265 secRuleDao.removeSecRule(secRule);
266 ContractId contractId = SecRuleEntityDecoder.getContractId(secRule);
267 rwTx.delete(LogicalDatastoreType.CONFIGURATION, IidFactory.contractIid(tenantId, contractId));
269 ClassifierInstance classifierInstance = SecRuleEntityDecoder.getClassifierInstance(secRule);
270 deleteClassifierInstanceIfNotUsed(tenantId, classifierInstance, rwTx);
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);
284 // TODO add case when port ranges overlap
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)) {
305 static boolean isRuleIdEqual(NeutronSecurityRule one, NeutronSecurityRule two) {
308 return one.getSecurityRuleUUID().equals(two.getSecurityRuleUUID());
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);
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);
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);
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);
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));
354 return new SelectorName(selectorNameBuilder.toString());
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)
363 .append(secGroupDao.getNameOrIdOfSecGroup(providerEpgId))
365 return new SelectorName(selectorName);
369 static boolean isDirectionOpposite(Direction one, Direction two) {
370 return (one == Direction.In && two == Direction.Out) || (one == Direction.Out && two == Direction.In);
374 static boolean isOneWithinTwo(NeutronSecurityRule one, NeutronSecurityRule two) {
375 if (!isOneGroupIdWithinTwoRemoteGroupId(one, two) || !isOneGroupIdWithinTwoRemoteGroupId(two, one))
377 if (!SecRuleEntityDecoder.isEtherTypeOfOneWithinTwo(one, two))
379 if (!SecRuleEntityDecoder.isProtocolOfOneWithinTwo(one, two))
381 if (!SecRuleEntityDecoder.isPortsOfOneWithinTwo(one, two))
383 if (!Strings.isNullOrEmpty(two.getSecurityRuleRemoteIpPrefix())
384 && Strings.isNullOrEmpty(one.getSecurityRuleRemoteIpPrefix()))
390 static boolean isOneGroupIdWithinTwoRemoteGroupId(NeutronSecurityRule one, NeutronSecurityRule two) {
391 return (Strings.isNullOrEmpty(two.getSecurityRemoteGroupID()) || two.getSecurityRemoteGroupID().equals(
392 one.getSecurityRuleGroupID()));