2bb8fc7b48681621369b0dcd2ea4e15f62404b1f
[netvirt.git] / policyservice / impl / src / main / java / org / opendaylight / netvirt / policyservice / PolicyAceFlowProgrammer.java
1 /*
2  * Copyright (c) 2017 Hewlett Packard Enterprise, Co. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.netvirt.policyservice;
10
11 import com.google.common.base.Optional;
12 import java.math.BigInteger;
13 import java.util.Collections;
14 import java.util.List;
15 import java.util.Map;
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;
41
42 /**
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
47  *
48  */
49 @Singleton
50 public class PolicyAceFlowProgrammer {
51     private static final Logger LOG = LoggerFactory.getLogger(PolicyAceFlowProgrammer.class);
52
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;
60
61     @Inject
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;
73     }
74
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());
79             return;
80         }
81
82         List<InstructionInfo> instructions = addOrRemove == NwConstants.ADD_FLOW
83                 ? getPolicyClassifierInstructions(policyClassifierOpt.get()) : null;
84         programAceFlows(ace, instructions, dpId, addOrRemove);
85     }
86
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));
91     }
92
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());
99                 return;
100             }
101
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);
106                 return;
107             }
108         }
109
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());
113             return;
114         }
115
116         coordinator.enqueueJob(ace.getRuleName(), () -> {
117             WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
118
119             aclFlowMap.forEach((flowName, matches) -> {
120                 String policyFlowName = "Policy_" + flowName;
121                 List<MatchInfoBase> policyMatches = matches;
122                 int policyPriority = PolicyServiceConstants.POLICY_FLOW_PRIOPITY;
123
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());
130                 }
131
132                 LOG.debug("{} policy ACE rule {} on DPN {} flow {}",
133                         addOrRemove == NwConstants.ADD_FLOW ? "Installing" : "Removing", ace.getRuleName(), dpId,
134                         policyFlowName);
135                 policyFlowUtil.updateFlowToTx(dpId, NwConstants.EGRESS_POLICY_CLASSIFIER_TABLE, policyFlowName,
136                         policyPriority, NwConstants.EGRESS_POLICY_CLASSIFIER_COOKIE, policyMatches, instructions,
137                         addOrRemove, tx);
138             });
139             return Collections.singletonList(tx.submit());
140         });
141     }
142
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();
148         }
149
150         return policyFlowUtil.getPolicyClassifierInstructions(policyClassifierId);
151     }
152
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;
159             }
160         }
161
162         Service service = matches.getAugmentation(Service.class);
163         if (service != null) {
164             Optional<PolicyAceFlowWrapper> serviceFlowOpt = getPolicyServiceFlow(service);
165             if (serviceFlowOpt.isPresent()) {
166                 return serviceFlowOpt;
167             }
168         }
169
170         return Optional.absent();
171     }
172
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();
178         }
179
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));
188             }
189
190             interfaceName = vlanMemberInterfaceOpt.get();
191             flowPriority = PolicyServiceConstants.POLICY_ACL_VLAN_INTERFACE_FLOW_PRIOPITY;
192         }
193
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));
198         }
199
200         BigInteger dpId = interfaceManager.getDpnForInterface(interfaceName);
201         if (dpId == null) {
202             dpId = BigInteger.ZERO;
203         }
204         return Optional.of(new PolicyAceFlowWrapper(flowName, matches, flowPriority, dpId));
205     }
206
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();
213         }
214
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));
220             }
221
222             return Optional.of(new PolicyAceFlowWrapper(flowName, elanMatches,
223                     PolicyServiceConstants.POLICY_ACL_L2VPN_FLOW_PRIOPITY));
224         }
225
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));
231             }
232
233             return Optional.of(new PolicyAceFlowWrapper(flowName, vpnMatches,
234                     PolicyServiceConstants.POLICY_ACL_L3VPN_FLOW_PRIOPITY));
235         }
236
237         return Optional.absent();
238     }
239 }