/* * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.groupbasedpolicy.util; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.opendaylight.groupbasedpolicy.dto.ConditionSet; import org.opendaylight.groupbasedpolicy.dto.EgKey; import org.opendaylight.groupbasedpolicy.dto.EndpointConstraint; import org.opendaylight.groupbasedpolicy.dto.Policy; import org.opendaylight.groupbasedpolicy.dto.RuleGroup; import org.opendaylight.groupbasedpolicy.util.ContractResolverUtils.ContractMatch; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.Matcher.MatchType; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.condition.matchers.ConditionMatcher; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.conditions.Condition; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.Contract; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.Clause; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.Subject; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.clause.consumer.matchers.GroupIdentificationConstraints; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.clause.consumer.matchers.group.identification.constraints.GroupRequirementConstraintCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.clause.consumer.matchers.group.identification.constraints.group.requirement.constraint._case.RequirementMatcher; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.clause.provider.matchers.group.identification.constraints.GroupCapabilityConstraintCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.clause.provider.matchers.group.identification.constraints.group.capability.constraint._case.CapabilityMatcher; import com.google.common.collect.HashBasedTable; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Table; import com.google.common.collect.Table.Cell; class SubjectResolverUtils { private SubjectResolverUtils() { throw new UnsupportedOperationException("Cannot create an instance"); } /** * Choose the set of subjects that in scope for each possible set of * endpoint conditions */ // TODO Li msunal do we really need contractMatches to be a type Table<EgKey, EgKey, List<ContractMatch>> // it should be sufficient to be just List<ContractMatch> static Table<EgKey, EgKey, Policy> selectSubjects( Table<EgKey, EgKey, List<ContractMatch>> contractMatches, Map<EgKey, Set<ConditionSet>> egConditions) { // TODO: Note that it's possible to further simplify the resulting // policy // in the case of things like repeated rules, condition sets that // cover other condition sets, etc. This would be a good thing to do // at some point Table<EgKey, EgKey, Policy> policy = HashBasedTable.create(); for (List<ContractMatch> matches : contractMatches.values()) { for (ContractMatch match : matches) { List<Clause> clauses = match.contract.getClause(); if (clauses == null) continue; List<Subject> subjectList = match.contract.getSubject(); if (subjectList == null) continue; EgKey ckey = new EgKey(match.consumerTenant.getId(), match.consumer.getId()); EgKey pkey = new EgKey(match.providerTenant.getId(), match.provider.getId()); Policy existing = policy.get(ckey, pkey); HashMap<SubjectName, Subject> subjects = new HashMap<>(); for (Subject s : subjectList) { subjects.put(s.getName(), s); } Table<EndpointConstraint, EndpointConstraint, List<Subject>> subjectMap = HashBasedTable.create(); for (Clause clause : clauses) { if (clause.getSubjectRefs() != null && clauseMatchesByGroupReqAndCapConstraints(clause, match)) { ConditionSet consCSet = buildConsConditionSet(clause); addConditionSet(ckey, consCSet, egConditions); EndpointConstraint consEpConstraint = new EndpointConstraint(consCSet, clause.getConsumerMatchers() == null ? null : clause.getConsumerMatchers() .getEndpointIdentificationConstraints()); ConditionSet provCSet = buildProvConditionSet(clause); addConditionSet(pkey, provCSet, egConditions); EndpointConstraint provEpConstraint = new EndpointConstraint(provCSet, clause.getProviderMatchers() == null ? null : clause.getProviderMatchers() .getEndpointIdentificationConstraints()); List<Subject> clauseSubjects = subjectMap.get(consEpConstraint, provEpConstraint); if (clauseSubjects == null) { clauseSubjects = new ArrayList<>(); subjectMap.put(consEpConstraint, provEpConstraint, clauseSubjects); } for (SubjectName sn : clause.getSubjectRefs()) { Subject s = subjects.get(sn); if (s != null) clauseSubjects.add(s); } } } policy.put(ckey, pkey, resolvePolicy(match.contractTenant, match.contract, existing, subjectMap)); } } return policy; } private static boolean clauseMatchesByGroupReqAndCapConstraints(Clause clause, ContractMatch match) { if (clause.getConsumerMatchers() != null) { GroupIdentificationConstraints groupIdentificationConstraintsConsumer = clause.getConsumerMatchers() .getGroupIdentificationConstraints(); if (groupIdentificationConstraintsConsumer instanceof GroupRequirementConstraintCase) { List<RequirementMatcher> reqMatchers = ((GroupRequirementConstraintCase) groupIdentificationConstraintsConsumer) .getRequirementMatcher(); if (reqMatchers != null) { for (RequirementMatcher reqMatcher : reqMatchers) { if (!MatcherUtils.applyReqMatcher(reqMatcher, match.consumerRelator)) { return false; } } } } } if (clause.getProviderMatchers() != null) { org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.clause.provider.matchers.GroupIdentificationConstraints groupIdentificationConstraintsProvider = clause .getProviderMatchers().getGroupIdentificationConstraints(); if (groupIdentificationConstraintsProvider instanceof GroupCapabilityConstraintCase) { List<CapabilityMatcher> capMatchers = ((GroupCapabilityConstraintCase) groupIdentificationConstraintsProvider) .getCapabilityMatcher(); if (capMatchers != null) { for (CapabilityMatcher capMatcher : capMatchers) { if (!MatcherUtils.applyCapMatcher(capMatcher, match.providerRelator)) { return false; } } } } } return true; } private static void addConditionSet(EgKey eg, ConditionSet cs, Map<EgKey, Set<ConditionSet>> egConditions) { if (egConditions == null) return; Set<ConditionSet> cset = egConditions.get(eg); if (cset == null) { egConditions.put(eg, cset = new HashSet<>()); } cset.add(cs); } private static ConditionSet buildConsConditionSet(Clause clause) { if (clause.getConsumerMatchers() != null) { List<ConditionMatcher> condMatchers = clause.getConsumerMatchers().getConditionMatcher(); return buildConditionSet(condMatchers); } return ConditionSet.EMPTY; } private static ConditionSet buildProvConditionSet(Clause clause) { if (clause.getProviderMatchers() != null) { List<ConditionMatcher> condMatchers = clause.getProviderMatchers().getConditionMatcher(); return buildConditionSet(condMatchers); } return ConditionSet.EMPTY; } private static ConditionSet buildConditionSet(List<ConditionMatcher> condMatchers) { if (condMatchers == null) return ConditionSet.EMPTY; ImmutableSet.Builder<ConditionName> allb = ImmutableSet.builder(); ImmutableSet.Builder<ConditionName> noneb = ImmutableSet.builder(); ImmutableSet.Builder<Set<ConditionName>> anyb = ImmutableSet.builder(); for (ConditionMatcher condMatcher : condMatchers) { if (condMatcher.getCondition() == null) continue; MatchType type = condMatcher.getMatchType(); if (type == null) type = MatchType.All; if (type.equals(MatchType.Any)) { ImmutableSet.Builder<ConditionName> a = ImmutableSet.builder(); for (Condition c : condMatcher.getCondition()) { a.add(c.getName()); } anyb.add(a.build()); } else { for (Condition c : condMatcher.getCondition()) { switch (type) { case Any: break; case None: noneb.add(c.getName()); break; case All: default: allb.add(c.getName()); break; } } } } return new ConditionSet(allb.build(), noneb.build(), anyb.build()); } private static Policy resolvePolicy(Tenant contractTenant, Contract contract, Policy merge, Table<EndpointConstraint, EndpointConstraint, List<Subject>> subjectMap) { Table<EndpointConstraint, EndpointConstraint, List<RuleGroup>> ruleMap = HashBasedTable.create(); if (merge != null) { ruleMap.putAll(merge.getRuleMap()); } for (Cell<EndpointConstraint, EndpointConstraint, List<Subject>> entry : subjectMap.cellSet()) { List<RuleGroup> rules = new ArrayList<>(); EndpointConstraint consEpConstraint = entry.getRowKey(); EndpointConstraint provEpConstraint = entry.getColumnKey(); List<RuleGroup> oldrules = ruleMap.get(consEpConstraint, provEpConstraint); if (oldrules != null) { rules.addAll(oldrules); } for (Subject s : entry.getValue()) { if (s.getRule() == null) continue; RuleGroup rg = new RuleGroup(s.getRule(), s.getOrder(), contractTenant, contract, s.getName()); rules.add(rg); } Collections.sort(rules); ruleMap.put(consEpConstraint, provEpConstraint, Collections.unmodifiableList(rules)); } return new Policy(ruleMap); } }