597860664139ce04e50d603079dbae03cbb9880f
[netvirt.git] /
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
12 import com.google.common.base.Optional;
13
14 import java.math.BigInteger;
15 import java.util.Collections;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Objects;
19 import java.util.stream.Collectors;
20 import java.util.stream.Stream;
21
22 import javax.inject.Inject;
23 import javax.inject.Singleton;
24
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;
45
46 /**
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
51  *
52  */
53 @SuppressWarnings("deprecation")
54 @Singleton
55 public class PolicyAceFlowProgrammer {
56     private static final Logger LOG = LoggerFactory.getLogger(PolicyAceFlowProgrammer.class);
57
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;
65
66     @Inject
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();
77     }
78
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());
83             return;
84         }
85
86         List<InstructionInfo> instructions = (addOrRemove == NwConstants.ADD_FLOW)
87                 ? getPolicyClassifierInstructions(policyClassifierOpt.get()) : null;
88         programAceFlows(ace, instructions, dpId, addOrRemove);
89     }
90
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);
96         });
97     }
98
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());
105                 return;
106             }
107
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);
112                 return;
113             }
114         }
115
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());
119             return;
120         }
121
122         coordinator.enqueueJob(ace.getRuleName(), () -> {
123             WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
124
125             aclFlowMap.forEach((flowName, matches) -> {
126                 String policyFlowName = "Policy_" + flowName;
127                 List<MatchInfoBase> policyMatches = matches;
128                 int policyPriority = PolicyServiceConstants.POLICY_FLOW_PRIOPITY;
129
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());
136                 }
137
138                 LOG.debug("{} policy ACE rule {} on DPN {} flow {}",
139                         addOrRemove == NwConstants.ADD_FLOW ? "Installing" : "Removing", ace.getRuleName(), dpId,
140                         policyFlowName);
141                 policyFlowUtil.updateFlowToTx(dpId, NwConstants.EGRESS_POLICY_CLASSIFIER_TABLE, policyFlowName,
142                         policyPriority, NwConstants.EGRESS_POLICY_CLASSIFIER_COOKIE, policyMatches, instructions,
143                         addOrRemove, tx);
144             });
145             return Collections.singletonList(tx.submit());
146         });
147     }
148
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();
154         }
155
156         return policyFlowUtil.getPolicyClassifierInstructions(policyClassifierId);
157     }
158
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;
165             }
166         }
167
168         Service service = matches.getAugmentation(Service.class);
169         if (service != null) {
170             Optional<PolicyAceFlowWrapper> serviceFlowOpt = getPolicyServiceFlow(service);
171             if (serviceFlowOpt.isPresent()) {
172                 return serviceFlowOpt;
173             }
174         }
175
176         return Optional.absent();
177     }
178
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();
184         }
185
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));
194             }
195
196             interfaceName = vlanMemberInterfaceOpt.get();
197             flowPriority = PolicyServiceConstants.POLICY_ACL_VLAN_INTERFACE_FLOW_PRIOPITY;
198         }
199
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));
204         }
205
206         BigInteger dpId = Optional.fromNullable(interfaceManager.getDpnForInterface(interfaceName)).or(BigInteger.ZERO);
207         return Optional.of(new PolicyAceFlowWrapper(flowName, matches, flowPriority, dpId));
208     }
209
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();
216         }
217
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));
223             }
224
225             return Optional.of(new PolicyAceFlowWrapper(flowName, elanMatches,
226                     PolicyServiceConstants.POLICY_ACL_L2VPN_FLOW_PRIOPITY));
227         }
228
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));
234             }
235
236             return Optional.of(new PolicyAceFlowWrapper(flowName, vpnMatches,
237                     PolicyServiceConstants.POLICY_ACL_L3VPN_FLOW_PRIOPITY));
238         }
239
240         return Optional.absent();
241     }
242 }