2 * Copyright (c) 2017 Hewlett Packard Enterprise, Co. 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.netvirt.policyservice;
11 import com.google.common.base.Optional;
12 import java.math.BigInteger;
13 import java.util.Collections;
14 import java.util.List;
16 import java.util.Objects;
17 import java.util.stream.Collectors;
18 import java.util.stream.Stream;
19 import javax.inject.Inject;
20 import javax.inject.Singleton;
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
23 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
24 import org.opendaylight.genius.mdsalutil.InstructionInfo;
25 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
26 import org.opendaylight.genius.mdsalutil.NwConstants;
27 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
28 import org.opendaylight.netvirt.aclservice.api.utils.IAclServiceUtil;
29 import org.opendaylight.netvirt.policyservice.util.PolicyServiceFlowUtil;
30 import org.opendaylight.netvirt.policyservice.util.PolicyServiceUtil;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.Ace;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.Matches;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.IngressInterface;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.L2vpnServiceType;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.L3vpnServiceType;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.Service;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.ServiceTypeBase;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
43 * Program POLICY_CLASSIFER_TABLE flows. Each flow is composed from<br>
44 * * OF matches - translated from set of {@link Ace} matches<br>
45 * * OF actions - set policy classifier bits in the metadata and goto
46 * POLICY_ROUTING_TABLE
50 public class PolicyAceFlowProgrammer {
51 private static final Logger LOG = LoggerFactory.getLogger(PolicyAceFlowProgrammer.class);
53 private final DataBroker dataBroker;
54 private final IAclServiceUtil aclServiceUtil;
55 private final IInterfaceManager interfaceManager;
56 private final PolicyIdManager policyIdManager;
57 private final PolicyServiceUtil policyServiceUtil;
58 private final PolicyServiceFlowUtil policyFlowUtil;
59 private final JobCoordinator coordinator;
62 public PolicyAceFlowProgrammer(final DataBroker dataBroker, final IAclServiceUtil aclServiceUtil,
63 final IInterfaceManager interfaceManager, final PolicyIdManager policyIdManager,
64 final PolicyServiceUtil policyServiceUtil, final PolicyServiceFlowUtil policyFlowUtil,
65 final JobCoordinator coordinator) {
66 this.dataBroker = dataBroker;
67 this.aclServiceUtil = aclServiceUtil;
68 this.interfaceManager = interfaceManager;
69 this.policyIdManager = policyIdManager;
70 this.policyServiceUtil = policyServiceUtil;
71 this.policyFlowUtil = policyFlowUtil;
72 this.coordinator = coordinator;
75 public void programAceFlows(Ace ace, BigInteger dpId, int addOrRemove) {
76 Optional<String> policyClassifierOpt = policyServiceUtil.getAcePolicyClassifier(ace);
77 if (!policyClassifierOpt.isPresent()) {
78 LOG.debug("No egress policy classifier found for ACE rule {}", ace.getRuleName());
82 List<InstructionInfo> instructions = addOrRemove == NwConstants.ADD_FLOW
83 ? getPolicyClassifierInstructions(policyClassifierOpt.get()) : null;
84 programAceFlows(ace, instructions, dpId, addOrRemove);
87 public void programAceFlows(Ace ace, String policyClassifierName, List<BigInteger> dpIds, int addOrRemove) {
88 List<InstructionInfo> instructions = addOrRemove == NwConstants.ADD_FLOW
89 ? getPolicyClassifierInstructions(policyClassifierName) : null;
90 dpIds.forEach(dpId -> programAceFlows(ace, instructions, dpId, addOrRemove));
93 public void programAceFlows(Ace ace, List<InstructionInfo> instructions, BigInteger dpId, int addOrRemove) {
94 Optional<PolicyAceFlowWrapper> policyFlowWrapperOpt = getPolicyAceFlowWrapper(ace.getMatches());
95 if (policyFlowWrapperOpt.isPresent()) {
96 PolicyAceFlowWrapper policyFlowWrapper = policyFlowWrapperOpt.get();
97 if (policyFlowWrapper.isPartial()) {
98 LOG.debug("Delaying policy ACE rule {} installation due to partial information", ace.getRuleName());
102 BigInteger policyFlowDpId = policyFlowWrapper.getDpId();
103 if (!BigInteger.ZERO.equals(policyFlowDpId) && !Objects.equals(dpId, policyFlowDpId)) {
104 LOG.trace("Ignoring policy ACE rule {} flow {} on DPN {}", ace.getRuleName(),
105 policyFlowWrapper.getFlowName(), dpId);
110 Map<String, List<MatchInfoBase>> aclFlowMap = aclServiceUtil.programIpFlow(ace.getMatches());
111 if (aclFlowMap == null || aclFlowMap.isEmpty()) {
112 LOG.warn("Failed to create flow matches for ACE rule {}", ace.getRuleName());
116 coordinator.enqueueJob(ace.getRuleName(), () -> {
117 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
119 aclFlowMap.forEach((flowName, matches) -> {
120 String policyFlowName = "Policy_" + flowName;
121 List<MatchInfoBase> policyMatches = matches;
122 int policyPriority = PolicyServiceConstants.POLICY_FLOW_PRIOPITY;
124 if (policyFlowWrapperOpt.isPresent()) {
125 PolicyAceFlowWrapper policyFlowWrapper = policyFlowWrapperOpt.get();
126 policyFlowName += '_' + policyFlowWrapper.getFlowName();
127 policyPriority = policyFlowWrapper.getPriority();
128 policyMatches = Stream.concat(matches.stream(), policyFlowWrapper.getMatches().stream())
129 .collect(Collectors.toList());
132 LOG.debug("{} policy ACE rule {} on DPN {} flow {}",
133 addOrRemove == NwConstants.ADD_FLOW ? "Installing" : "Removing", ace.getRuleName(), dpId,
135 policyFlowUtil.updateFlowToTx(dpId, NwConstants.EGRESS_POLICY_CLASSIFIER_TABLE, policyFlowName,
136 policyPriority, NwConstants.EGRESS_POLICY_CLASSIFIER_COOKIE, policyMatches, instructions,
139 return Collections.singletonList(tx.submit());
143 private List<InstructionInfo> getPolicyClassifierInstructions(String policyClassifierName) {
144 long policyClassifierId = policyIdManager.getPolicyClassifierId(policyClassifierName);
145 if (policyClassifierId == PolicyServiceConstants.INVALID_ID) {
146 LOG.error("Failed to get policy classifier id for classifier {}", policyClassifierName);
147 return Collections.emptyList();
150 return policyFlowUtil.getPolicyClassifierInstructions(policyClassifierId);
153 private Optional<PolicyAceFlowWrapper> getPolicyAceFlowWrapper(Matches matches) {
154 IngressInterface ingressInterface = matches.getAugmentation(IngressInterface.class);
155 if (ingressInterface != null) {
156 Optional<PolicyAceFlowWrapper> interfaceFlowOpt = getIngressInterfaceFlow(ingressInterface);
157 if (interfaceFlowOpt.isPresent()) {
158 return interfaceFlowOpt;
162 Service service = matches.getAugmentation(Service.class);
163 if (service != null) {
164 Optional<PolicyAceFlowWrapper> serviceFlowOpt = getPolicyServiceFlow(service);
165 if (serviceFlowOpt.isPresent()) {
166 return serviceFlowOpt;
170 return Optional.absent();
173 private Optional<PolicyAceFlowWrapper> getIngressInterfaceFlow(IngressInterface ingressInterface) {
174 String interfaceName = ingressInterface.getName();
175 if (interfaceName == null) {
176 LOG.error("Invalid ingress interface augmentation. missing interface name");
177 return Optional.absent();
180 String flowName = "INGRESS_INTERFACE_" + interfaceName;
181 int flowPriority = PolicyServiceConstants.POLICY_ACL_TRUNK_INTERFACE_FLOW_PRIOPITY;
182 VlanId vlanId = ingressInterface.getVlanId();
183 if (vlanId != null) {
184 Optional<String> vlanMemberInterfaceOpt = policyServiceUtil.getVlanMemberInterface(interfaceName, vlanId);
185 if (!vlanMemberInterfaceOpt.isPresent()) {
186 LOG.debug("Vlan member {} missing for trunk {}", vlanId.getValue(), interfaceName);
187 return Optional.of(new PolicyAceFlowWrapper(flowName, PolicyAceFlowWrapper.PARTIAL));
190 interfaceName = vlanMemberInterfaceOpt.get();
191 flowPriority = PolicyServiceConstants.POLICY_ACL_VLAN_INTERFACE_FLOW_PRIOPITY;
194 List<MatchInfoBase> matches = policyFlowUtil.getIngressInterfaceMatches(interfaceName);
195 if (matches == null || matches.isEmpty()) {
196 LOG.debug("Failed to get ingress interface {} matches", interfaceName);
197 return Optional.of(new PolicyAceFlowWrapper(flowName, PolicyAceFlowWrapper.PARTIAL));
200 BigInteger dpId = interfaceManager.getDpnForInterface(interfaceName);
202 dpId = BigInteger.ZERO;
204 return Optional.of(new PolicyAceFlowWrapper(flowName, matches, flowPriority, dpId));
207 private Optional<PolicyAceFlowWrapper> getPolicyServiceFlow(Service service) {
208 String serviceName = service.getServiceName();
209 Class<? extends ServiceTypeBase> serviceType = service.getServiceType();
210 if (serviceName == null || serviceType == null) {
211 LOG.error("Invalid policy service augmentation {}", service);
212 return Optional.absent();
215 if (serviceType.isAssignableFrom(L2vpnServiceType.class)) {
216 String flowName = "L2VPN_" + serviceName;
217 List<MatchInfoBase> elanMatches = policyFlowUtil.getElanInstanceMatches(serviceName);
218 if (elanMatches == null || elanMatches.isEmpty()) {
219 return Optional.of(new PolicyAceFlowWrapper(flowName, PolicyAceFlowWrapper.PARTIAL));
222 return Optional.of(new PolicyAceFlowWrapper(flowName, elanMatches,
223 PolicyServiceConstants.POLICY_ACL_L2VPN_FLOW_PRIOPITY));
226 if (serviceType.isAssignableFrom(L3vpnServiceType.class)) {
227 String flowName = "L3VPN_" + serviceName;
228 List<MatchInfoBase> vpnMatches = policyFlowUtil.getVpnInstanceMatches(serviceName);
229 if (vpnMatches == null || vpnMatches.isEmpty()) {
230 return Optional.of(new PolicyAceFlowWrapper(flowName, PolicyAceFlowWrapper.PARTIAL));
233 return Optional.of(new PolicyAceFlowWrapper(flowName, vpnMatches,
234 PolicyServiceConstants.POLICY_ACL_L3VPN_FLOW_PRIOPITY));
237 return Optional.absent();