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;
12 import com.google.common.base.Optional;
14 import java.math.BigInteger;
15 import java.util.Collections;
16 import java.util.List;
18 import java.util.Objects;
19 import java.util.stream.Collectors;
20 import java.util.stream.Stream;
22 import javax.inject.Inject;
23 import javax.inject.Singleton;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
27 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
28 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
29 import org.opendaylight.genius.mdsalutil.InstructionInfo;
30 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
31 import org.opendaylight.genius.mdsalutil.NwConstants;
32 import org.opendaylight.netvirt.aclservice.api.utils.IAclServiceUtil;
33 import org.opendaylight.netvirt.policyservice.util.PolicyServiceFlowUtil;
34 import org.opendaylight.netvirt.policyservice.util.PolicyServiceUtil;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.Ace;
36 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;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.IngressInterface;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.L2vpnServiceType;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.L3vpnServiceType;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.Service;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.ServiceTypeBase;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
47 * Program POLICY_CLASSIFER_TABLE flows. Each flow is composed from<br>
48 * * OF matches - translated from set of {@link Ace} matches<br>
49 * * OF actions - set policy classifier bits in the metadata and goto
50 * POLICY_ROUTING_TABLE
53 @SuppressWarnings("deprecation")
55 public class PolicyAceFlowProgrammer {
56 private static final Logger LOG = LoggerFactory.getLogger(PolicyAceFlowProgrammer.class);
58 private final DataBroker dataBroker;
59 private final IAclServiceUtil aclServiceUtil;
60 private final IInterfaceManager interfaceManager;
61 private final PolicyIdManager policyIdManager;
62 private final PolicyServiceUtil policyServiceUtil;
63 private final PolicyServiceFlowUtil policyFlowUtil;
64 private final DataStoreJobCoordinator coordinator;
67 public PolicyAceFlowProgrammer(final DataBroker dataBroker, final IAclServiceUtil aclServiceUtil,
68 final IInterfaceManager interfaceManager, final PolicyIdManager policyIdManager,
69 final PolicyServiceUtil policyServiceUtil, final PolicyServiceFlowUtil policyFlowUtil) {
70 this.dataBroker = dataBroker;
71 this.aclServiceUtil = aclServiceUtil;
72 this.interfaceManager = interfaceManager;
73 this.policyIdManager = policyIdManager;
74 this.policyServiceUtil = policyServiceUtil;
75 this.policyFlowUtil = policyFlowUtil;
76 this.coordinator = DataStoreJobCoordinator.getInstance();
79 public void programAceFlows(Ace ace, BigInteger dpId, int addOrRemove) {
80 Optional<String> policyClassifierOpt = policyServiceUtil.getAcePolicyClassifier(ace);
81 if (!policyClassifierOpt.isPresent()) {
82 LOG.debug("No egress policy classifier found for ACE rule {}", ace.getRuleName());
86 List<InstructionInfo> instructions = (addOrRemove == NwConstants.ADD_FLOW)
87 ? getPolicyClassifierInstructions(policyClassifierOpt.get()) : null;
88 programAceFlows(ace, instructions, dpId, addOrRemove);
91 public void programAceFlows(Ace ace, String policyClassifierName, List<BigInteger> dpIds, int addOrRemove) {
92 List<InstructionInfo> instructions = (addOrRemove == NwConstants.ADD_FLOW)
93 ? getPolicyClassifierInstructions(policyClassifierName) : null;
94 dpIds.forEach(dpId -> {
95 programAceFlows(ace, instructions, dpId, addOrRemove);
99 public void programAceFlows(Ace ace, List<InstructionInfo> instructions, BigInteger dpId, int addOrRemove) {
100 Optional<PolicyAceFlowWrapper> policyFlowWrapperOpt = getPolicyAceFlowWrapper(ace.getMatches());
101 if (policyFlowWrapperOpt.isPresent()) {
102 PolicyAceFlowWrapper policyFlowWrapper = policyFlowWrapperOpt.get();
103 if (policyFlowWrapper.isPartial()) {
104 LOG.debug("Delaying policy ACE rule {} installation due to partial information", ace.getRuleName());
108 BigInteger policyFlowDpId = policyFlowWrapper.getDpId();
109 if (!BigInteger.ZERO.equals(policyFlowDpId) && !Objects.equals(dpId, policyFlowDpId)) {
110 LOG.trace("Ignoring policy ACE rule {} flow {} on DPN {}", ace.getRuleName(),
111 policyFlowWrapper.getFlowName(), dpId);
116 Map<String, List<MatchInfoBase>> aclFlowMap = aclServiceUtil.programIpFlow(ace.getMatches());
117 if (aclFlowMap == null || aclFlowMap.isEmpty()) {
118 LOG.warn("Failed to create flow matches for ACE rule {}", ace.getRuleName());
122 coordinator.enqueueJob(ace.getRuleName(), () -> {
123 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
125 aclFlowMap.forEach((flowName, matches) -> {
126 String policyFlowName = "Policy_" + flowName;
127 List<MatchInfoBase> policyMatches = matches;
128 int policyPriority = PolicyServiceConstants.POLICY_FLOW_PRIOPITY;
130 if (policyFlowWrapperOpt.isPresent()) {
131 PolicyAceFlowWrapper policyFlowWrapper = policyFlowWrapperOpt.get();
132 policyFlowName += '_' + policyFlowWrapper.getFlowName();
133 policyPriority = policyFlowWrapper.getPriority();
134 policyMatches = Stream.concat(matches.stream(), policyFlowWrapper.getMatches().stream())
135 .collect(Collectors.toList());
138 LOG.debug("{} policy ACE rule {} on DPN {} flow {}",
139 addOrRemove == NwConstants.ADD_FLOW ? "Installing" : "Removing", ace.getRuleName(), dpId,
141 policyFlowUtil.updateFlowToTx(dpId, NwConstants.EGRESS_POLICY_CLASSIFIER_TABLE, policyFlowName,
142 policyPriority, NwConstants.EGRESS_POLICY_CLASSIFIER_COOKIE, policyMatches, instructions,
145 return Collections.singletonList(tx.submit());
149 private List<InstructionInfo> getPolicyClassifierInstructions(String policyClassifierName) {
150 long policyClassifierId = policyIdManager.getPolicyClassifierId(policyClassifierName);
151 if (policyClassifierId == PolicyServiceConstants.INVALID_ID) {
152 LOG.error("Failed to get policy classifier id for classifier {}", policyClassifierName);
153 return Collections.emptyList();
156 return policyFlowUtil.getPolicyClassifierInstructions(policyClassifierId);
159 private Optional<PolicyAceFlowWrapper> getPolicyAceFlowWrapper(Matches matches) {
160 IngressInterface ingressInterface = matches.getAugmentation(IngressInterface.class);
161 if (ingressInterface != null) {
162 Optional<PolicyAceFlowWrapper> interfaceFlowOpt = getIngressInterfaceFlow(ingressInterface);
163 if (interfaceFlowOpt.isPresent()) {
164 return interfaceFlowOpt;
168 Service service = matches.getAugmentation(Service.class);
169 if (service != null) {
170 Optional<PolicyAceFlowWrapper> serviceFlowOpt = getPolicyServiceFlow(service);
171 if (serviceFlowOpt.isPresent()) {
172 return serviceFlowOpt;
176 return Optional.absent();
179 private Optional<PolicyAceFlowWrapper> getIngressInterfaceFlow(IngressInterface ingressInterface) {
180 String interfaceName = ingressInterface.getName();
181 if (interfaceName == null) {
182 LOG.error("Invalid ingress interface augmentation. missing interface name");
183 return Optional.absent();
186 String flowName = "INGRESS_INTERFACE_" + interfaceName;
187 int flowPriority = PolicyServiceConstants.POLICY_ACL_TRUNK_INTERFACE_FLOW_PRIOPITY;
188 VlanId vlanId = ingressInterface.getVlanId();
189 if (vlanId != null) {
190 Optional<String> vlanMemberInterfaceOpt = policyServiceUtil.getVlanMemberInterface(interfaceName, vlanId);
191 if (!vlanMemberInterfaceOpt.isPresent()) {
192 LOG.debug("Vlan member {} missing for trunk {}", vlanId.getValue(), interfaceName);
193 return Optional.of(new PolicyAceFlowWrapper(flowName, PolicyAceFlowWrapper.PARTIAL));
196 interfaceName = vlanMemberInterfaceOpt.get();
197 flowPriority = PolicyServiceConstants.POLICY_ACL_VLAN_INTERFACE_FLOW_PRIOPITY;
200 List<MatchInfoBase> matches = policyFlowUtil.getIngressInterfaceMatches(interfaceName);
201 if (matches == null || matches.isEmpty()) {
202 LOG.debug("Failed to get ingress interface {} matches", interfaceName);
203 return Optional.of(new PolicyAceFlowWrapper(flowName, PolicyAceFlowWrapper.PARTIAL));
206 BigInteger dpId = Optional.fromNullable(interfaceManager.getDpnForInterface(interfaceName)).or(BigInteger.ZERO);
207 return Optional.of(new PolicyAceFlowWrapper(flowName, matches, flowPriority, dpId));
210 private Optional<PolicyAceFlowWrapper> getPolicyServiceFlow(Service service) {
211 String serviceName = service.getServiceName();
212 Class<? extends ServiceTypeBase> serviceType = service.getServiceType();
213 if (serviceName == null || serviceType == null) {
214 LOG.error("Invalid policy service augmentation {}", service);
215 return Optional.absent();
218 if (serviceType.isAssignableFrom(L2vpnServiceType.class)) {
219 String flowName = "L2VPN_" + serviceName;
220 List<MatchInfoBase> elanMatches = policyFlowUtil.getElanInstanceMatches(serviceName);
221 if (elanMatches == null || elanMatches.isEmpty()) {
222 return Optional.of(new PolicyAceFlowWrapper(flowName, PolicyAceFlowWrapper.PARTIAL));
225 return Optional.of(new PolicyAceFlowWrapper(flowName, elanMatches,
226 PolicyServiceConstants.POLICY_ACL_L2VPN_FLOW_PRIOPITY));
229 if (serviceType.isAssignableFrom(L3vpnServiceType.class)) {
230 String flowName = "L3VPN_" + serviceName;
231 List<MatchInfoBase> vpnMatches = policyFlowUtil.getVpnInstanceMatches(serviceName);
232 if (vpnMatches == null || vpnMatches.isEmpty()) {
233 return Optional.of(new PolicyAceFlowWrapper(flowName, PolicyAceFlowWrapper.PARTIAL));
236 return Optional.of(new PolicyAceFlowWrapper(flowName, vpnMatches,
237 PolicyServiceConstants.POLICY_ACL_L3VPN_FLOW_PRIOPITY));
240 return Optional.absent();