Policy classifier table ACL flows
[netvirt.git] / vpnservice / policyservice / impl / src / main / java / org / opendaylight / netvirt / policyservice / util / PolicyServiceUtil.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.util;
10
11 import com.google.common.base.Optional;
12
13 import java.math.BigInteger;
14 import java.util.Collections;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.stream.Collectors;
18
19 import javax.inject.Inject;
20 import javax.inject.Singleton;
21
22 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
23 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
26 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
27 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
28 import org.opendaylight.netvirt.elanmanager.api.IElanBridgeManager;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.AccessLists;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.AclBase;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.Acl;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.AclKey;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.AccessListEntries;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.Ace;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.AceKey;
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.Actions;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.PolicyAcl;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.PolicyProfiles;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.SetPolicyClassifier;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.UnderlayNetworks;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.policy.profiles.PolicyProfile;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.policy.profiles.PolicyProfileKey;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.policy.profiles.policy.profile.PolicyAclRule;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.policy.profiles.policy.profile.PolicyAclRuleKey;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.policy.profiles.policy.profile.PolicyRoute;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.policy.profiles.policy.profile.policy.acl.rule.AceRule;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.policy.profiles.policy.profile.policy.acl.rule.AceRuleBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.policy.profiles.policy.profile.policy.acl.rule.AceRuleKey;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.policy.profiles.policy.profile.policy.route.route.BasicRoute;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.UnderlayNetwork;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.UnderlayNetworkKey;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay.network.DpnToInterface;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay.network.DpnToInterfaceKey;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay.network.PolicyProfileBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay.network.dpn.to._interface.TunnelInterface;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay.network.dpn.to._interface.TunnelInterfaceBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay.network.dpn.to._interface.TunnelInterfaceKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionEgress;
60 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
61 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
62 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65
66 @Singleton
67 public class PolicyServiceUtil {
68     private static final Logger LOG = LoggerFactory.getLogger(PolicyServiceUtil.class);
69
70     private static final String LOCAL_IPS = "local_ips";
71
72     private final DataBroker dataBroker;
73     private final IElanBridgeManager bridgeManager;
74     private final DataStoreJobCoordinator coordinator;
75
76     @Inject
77     public PolicyServiceUtil(final DataBroker dataBroker, final IElanBridgeManager bridgeManager) {
78         this.dataBroker = dataBroker;
79         this.bridgeManager = bridgeManager;
80         this.coordinator = DataStoreJobCoordinator.getInstance();
81     }
82
83     public Optional<String> getAcePolicyClassifier(Ace ace) {
84         Actions actions = ace.getActions();
85         SetPolicyClassifier setPolicyClassifier = actions.getAugmentation(SetPolicyClassifier.class);
86         if (setPolicyClassifier == null) {
87             LOG.warn("No valid policy action found for ACE rule {}", ace.getRuleName());
88             return Optional.absent();
89         }
90
91         if (setPolicyClassifier.getDirection() == null
92                 || !setPolicyClassifier.getDirection().isAssignableFrom(DirectionEgress.class)) {
93             LOG.trace("Ignoring non egress policy ACE rule {}", ace.getRuleName());
94             return Optional.absent();
95         }
96
97         return Optional.of(setPolicyClassifier.getPolicyClassifier());
98
99     }
100
101     public Optional<Ace> getPolicyAce(String aclName, String ruleName) {
102         InstanceIdentifier<Ace> identifier = getAceIdentifier(aclName, ruleName);
103         try {
104             return SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
105                     identifier);
106         } catch (ReadFailedException e) {
107             LOG.warn("Failed to get policy ACE rule {} for ACL {}", ruleName, aclName);
108             return Optional.absent();
109         }
110     }
111
112     public List<String> getUnderlayNetworksForClassifier(String policyClassifier) {
113         InstanceIdentifier<PolicyProfile> identifier = getPolicyClassifierIdentifier(policyClassifier);
114         try {
115             Optional<PolicyProfile> optProfile = SingleTransactionDataBroker.syncReadOptional(dataBroker,
116                     LogicalDatastoreType.CONFIGURATION, identifier);
117             return optProfile.isPresent() ? getUnderlayNetworksFromPolicyRoutes(optProfile.get().getPolicyRoute())
118                     : Collections.emptyList();
119         } catch (ReadFailedException e) {
120             LOG.warn("Failed to get policy routes for classifier {}", policyClassifier);
121             return Collections.emptyList();
122         }
123     }
124
125     public List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay
126         .network.PolicyProfile> getUnderlayNetworkPolicyProfiles(String underlayNetwork) {
127         InstanceIdentifier<UnderlayNetwork> identifier = getUnderlyNetworkIdentifier(underlayNetwork);
128         try {
129             Optional<UnderlayNetwork> optUnderlayNet = SingleTransactionDataBroker.syncReadOptional(dataBroker,
130                     LogicalDatastoreType.OPERATIONAL, identifier);
131             return optUnderlayNet.isPresent() ? optUnderlayNet.get().getPolicyProfile() : Collections.emptyList();
132         } catch (ReadFailedException e) {
133             LOG.warn("Failed to get policy classifiers for underlay network {}", underlayNetwork);
134             return Collections.emptyList();
135         }
136     }
137
138     public List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.policy.profiles.policy.profile
139         .PolicyAclRule> getPolicyClassifierAclRules(String policyClassifier) {
140         InstanceIdentifier<PolicyProfile> identifier = getPolicyClassifierIdentifier(policyClassifier);
141         try {
142             Optional<PolicyProfile> optProfile = SingleTransactionDataBroker.syncReadOptional(dataBroker,
143                     LogicalDatastoreType.OPERATIONAL, identifier);
144             return optProfile.isPresent() ? optProfile.get().getPolicyAclRule() : Collections.emptyList();
145         } catch (ReadFailedException e) {
146             LOG.warn("Failed to get policy rules for policy classifier {}", policyClassifier);
147             return Collections.emptyList();
148         }
149     }
150
151     public void updateTunnelInterfaceForUnderlayNetwork(String underlayNetwork, BigInteger dpId, String tunnelInterface,
152             boolean isAdded) {
153         coordinator.enqueueJob(underlayNetwork, () -> {
154             InstanceIdentifier<TunnelInterface> identifier = getUnderlyNetworkTunnelIdentifier(underlayNetwork, dpId,
155                     tunnelInterface);
156             WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
157             if (isAdded) {
158                 tx.merge(LogicalDatastoreType.OPERATIONAL, identifier,
159                         new TunnelInterfaceBuilder().setInterfaceName(tunnelInterface).build(), true);
160                 LOG.info("Add tunnel {} on DPN {} to underlay network {}", tunnelInterface, dpId, underlayNetwork);
161             } else {
162                 tx.delete(LogicalDatastoreType.OPERATIONAL, identifier);
163                 LOG.info("Remove tunnel {} from DPN {} on underlay network {}", tunnelInterface, dpId, underlayNetwork);
164             }
165             return Collections.singletonList(tx.submit());
166         });
167     }
168
169     public void updatePolicyClassifierForUnderlayNetworks(List<String> underlayNetworks, String policyClassifier,
170             boolean isAdded) {
171         if (underlayNetworks == null || underlayNetworks.isEmpty()) {
172             LOG.debug("No underlay networks found for policy classifier {}", policyClassifier);
173         }
174
175         underlayNetworks.forEach(underlayNetwork -> {
176             coordinator.enqueueJob(underlayNetwork, () -> {
177                 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
178                 InstanceIdentifier<
179                         org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks
180                         .underlay.network.PolicyProfile> identifier = getUnderlayNetworkPolicyClassifierIdentifier(
181                                 policyClassifier, underlayNetwork);
182                 if (isAdded) {
183                     tx.merge(LogicalDatastoreType.OPERATIONAL, identifier,
184                             new PolicyProfileBuilder().setPolicyClassifier(policyClassifier).build(), true);
185                     LOG.info("Add policy classifier {} to underlay network {}", policyClassifier, underlayNetwork);
186                 } else {
187                     tx.delete(LogicalDatastoreType.OPERATIONAL, identifier);
188                     LOG.info("Remove policy classifier {} from underlay network {}", policyClassifier,
189                             underlayNetwork);
190                 }
191                 return Collections.singletonList(tx.submit());
192             });
193         });
194     }
195
196     public void updateAclRuleForPolicyClassifier(String policyClassifier, String aclName, String ruleName,
197             boolean isAdded) {
198         coordinator.enqueueJob(policyClassifier, () -> {
199             InstanceIdentifier<
200                     AceRule> identifier = getPolicyClassifierAceIdentifier(policyClassifier, aclName, ruleName);
201             WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
202             if (isAdded) {
203                 tx.merge(LogicalDatastoreType.OPERATIONAL, identifier,
204                         new AceRuleBuilder().setRuleName(ruleName).build(), true);
205                 LOG.info("Add ACL {} rule {} to policy classifier {}", aclName, ruleName, policyClassifier);
206             } else {
207                 tx.delete(LogicalDatastoreType.OPERATIONAL, identifier);
208                 LOG.info("Remove ACL {} rule {} from policy classifier {}", aclName, ruleName, policyClassifier);
209             }
210             return Collections.singletonList(tx.submit());
211         });
212     }
213
214     public List<BigInteger> getUnderlayNetworksDpns(List<String> underlayNetworks) {
215         if (underlayNetworks == null) {
216             return Collections.emptyList();
217         }
218
219         return underlayNetworks.stream().flatMap(t -> getUnderlayNetworkDpns(t).stream()).distinct()
220                 .collect(Collectors.toList());
221     }
222
223     public String getTunnelUnderlayNetwork(BigInteger dpId, IpAddress tunnelIp) {
224         Node ovsdbNode = bridgeManager.getBridgeNode(dpId);
225         if (ovsdbNode == null) {
226             LOG.error("Failed to get OVSDB node for DPN {}", dpId);
227             return null;
228         }
229
230         Map<String, String> localIpMap = bridgeManager.getOpenvswitchOtherConfigMap(ovsdbNode, LOCAL_IPS);
231         return localIpMap.get(String.valueOf(tunnelIp.getValue()));
232     }
233
234     public static List<BigInteger> getDpnsFromDpnToInterfaces(List<DpnToInterface> dpnToInterfaces) {
235         if (dpnToInterfaces == null) {
236             return Collections.emptyList();
237         }
238
239         return dpnToInterfaces.stream().map(t -> t.getDpId()).collect(Collectors.toList());
240     }
241
242     public static List<String> getUnderlayNetworksFromPolicyRoutes(List<PolicyRoute> policyRoutes) {
243         if (policyRoutes == null) {
244             return Collections.emptyList();
245         }
246
247         return policyRoutes.stream().map(policyRoute -> policyRoute.getRoute())
248                 .filter(route -> route instanceof BasicRoute).map(route -> ((BasicRoute) route).getNetworkName())
249                 .collect(Collectors.toList());
250     }
251
252     public static boolean isPolicyAcl(Class<? extends AclBase> aclType) {
253         return aclType != null && aclType.isAssignableFrom(PolicyAcl.class);
254     }
255
256     private List<BigInteger> getUnderlayNetworkDpns(String underlayNetwork) {
257         InstanceIdentifier<UnderlayNetwork> identifier = getUnderlyNetworkIdentifier(underlayNetwork);
258         try {
259             Optional<UnderlayNetwork> optUnderlayNetwork = SingleTransactionDataBroker.syncReadOptional(dataBroker,
260                     LogicalDatastoreType.OPERATIONAL, identifier);
261             return optUnderlayNetwork.isPresent()
262                     ? getDpnsFromDpnToInterfaces(optUnderlayNetwork.get().getDpnToInterface())
263                     : Collections.emptyList();
264         } catch (ReadFailedException e) {
265             LOG.warn("Failed to get DPNs for underlay network {}", underlayNetwork);
266             return Collections.emptyList();
267         }
268     }
269
270     private InstanceIdentifier<UnderlayNetwork> getUnderlyNetworkIdentifier(String underlayNetwork) {
271         return InstanceIdentifier.create(UnderlayNetworks.class).child(UnderlayNetwork.class,
272                 new UnderlayNetworkKey(underlayNetwork));
273     }
274
275     private InstanceIdentifier<TunnelInterface> getUnderlyNetworkTunnelIdentifier(String underlayNetwork,
276             BigInteger dpId, String tunnelInterface) {
277         return InstanceIdentifier.create(UnderlayNetworks.class)
278                 .child(UnderlayNetwork.class, new UnderlayNetworkKey(underlayNetwork))
279                 .child(DpnToInterface.class, new DpnToInterfaceKey(dpId))
280                 .child(TunnelInterface.class, new TunnelInterfaceKey(tunnelInterface));
281     }
282
283     private InstanceIdentifier<PolicyProfile> getPolicyClassifierIdentifier(String policyClassifier) {
284         return InstanceIdentifier.create(PolicyProfiles.class).child(PolicyProfile.class,
285                 new PolicyProfileKey(policyClassifier));
286     }
287
288     private InstanceIdentifier<Ace> getAceIdentifier(String aclName, String ruleName) {
289         return InstanceIdentifier.create(AccessLists.class).child(Acl.class, new AclKey(aclName, PolicyAcl.class))
290                 .child(AccessListEntries.class).child(Ace.class, new AceKey(ruleName));
291     }
292
293     private KeyedInstanceIdentifier<AceRule, AceRuleKey> getPolicyClassifierAceIdentifier(String policyClassifier,
294             String aclName, String ruleName) {
295         return InstanceIdentifier.create(PolicyProfiles.class)
296                 .child(PolicyProfile.class, new PolicyProfileKey(policyClassifier))
297                 .child(PolicyAclRule.class, new PolicyAclRuleKey(aclName))
298                 .child(AceRule.class, new AceRuleKey(ruleName));
299     }
300
301     private InstanceIdentifier<
302             org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay.network
303                     .PolicyProfile> getUnderlayNetworkPolicyClassifierIdentifier(String policyClassifier,
304                             String underlayNetwork) {
305         return InstanceIdentifier.create(UnderlayNetworks.class)
306                 .child(UnderlayNetwork.class, new UnderlayNetworkKey(underlayNetwork))
307                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks
308                         .underlay.network.PolicyProfile.class, new org.opendaylight.yang.gen.v1.urn.opendaylight
309                         .netvirt.policy.rev170207.underlay.networks.underlay.network
310                         .PolicyProfileKey(policyClassifier));
311     }
312 }