Bug 8228 - metadata service fix made cleaner
[groupbasedpolicy.git] / renderers / vpp / src / main / java / org / opendaylight / groupbasedpolicy / renderer / vpp / policy / acl / AclManager.java
1 /*
2  * Copyright (c) 2017 Cisco Systems, Inc. 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.groupbasedpolicy.renderer.vpp.policy.acl;
10
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.stream.Collectors;
14
15 import javax.annotation.Nonnull;
16 import javax.annotation.Nullable;
17
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.groupbasedpolicy.renderer.util.AddressEndpointUtils;
20 import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.InterfaceManager;
21 import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.VppPathMapper;
22 import org.opendaylight.groupbasedpolicy.renderer.vpp.policy.PolicyContext;
23 import org.opendaylight.groupbasedpolicy.renderer.vpp.policy.acl.AccessListUtil.ACE_DIRECTION;
24 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.KeyFactory;
25 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;
26 import org.opendaylight.groupbasedpolicy.util.EndpointUtils;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpointKey;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCase;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.L2BridgeDomain;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpointKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.renderer.endpoint.PeerEndpointKey;
35 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
36 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 import com.google.common.base.Optional;
42 import com.google.common.base.Preconditions;
43 import com.google.common.collect.ImmutableList;
44 import com.google.common.collect.ImmutableSet;
45 import com.google.common.collect.ImmutableTable;
46 import com.google.common.collect.ImmutableTable.Builder;
47 import com.google.common.collect.Sets;
48
49 public class AclManager {
50
51     private static final Logger LOG = LoggerFactory.getLogger(AclManager.class);
52     private final MountedDataBrokerProvider mountDataProvider;
53
54     private static ImmutableTable<NodeId, InterfaceKey, ImmutableSet<AddressEndpointKey>> multipleEndpointsOnInterface;
55
56     public AclManager(@Nonnull MountedDataBrokerProvider mountDataProvider) {
57         this.mountDataProvider = Preconditions.checkNotNull(mountDataProvider);
58     }
59
60     public List<AccessListWrapper> resolveAclsOnInterface(RendererEndpointKey rEpKey, PolicyContext ctx) {
61         List<AccessListWrapper> aclWrappers = new ArrayList<>();
62         for (ACE_DIRECTION dir : new ACE_DIRECTION[] {ACE_DIRECTION.INGRESS, ACE_DIRECTION.EGRESS}) {
63             aclWrappers.add(buildAccessListWrappers(dir, ctx, rEpKey));
64         }
65         return aclWrappers;
66     }
67
68     /**
69      * @param policyDirection direction for which policy should be resolved. EP -> VPP = OUTBOUND, EP <- VPP = INBOUND 
70      * @param ctx with cached data
71      * @param rEpKey key of EP for which to create ACLs.
72      * @return synchronization futures, so that INGRESS and EGRESS ACLS can be resolved in parallel.
73      */
74     private static AccessListWrapper buildAccessListWrappers(ACE_DIRECTION policyDirection, PolicyContext ctx,
75             RendererEndpointKey rEpKey) {
76         LOG.trace("Resolving policy for VPP renderer endpoint {} in a separate thread in {} direction.", rEpKey,
77                 policyDirection);
78         AccessListWrapper aclWrapper = AccessListUtil.ACE_DIRECTION.INGRESS
79             .equals(policyDirection) ? new IngressAccessListWrapper() : new EgressAccessListWrapper();
80             AccessListUtil.configureLocalRules(ctx, rEpKey, policyDirection, aclWrapper);
81         // we support multiple IP end-points on a same interface
82        for (AddressEndpointKey aek : otherEndpointsOnTheSameInterface(ctx,
83                 AddressEndpointUtils.fromRendererEpKey(rEpKey))) {
84            AccessListUtil.configureLocalRules(ctx, AddressEndpointUtils.toRendererEpKey(aek), policyDirection, aclWrapper);
85         }
86         // resolve peers with no location
87         aclWrapper.writeRules(AccessListUtil.denyDomainSubnets(ctx, policyDirection));
88         // TODO currently any traffic heading to/from outside of managed domain is
89         // permitted for demonstration purposes
90         if (rEpKey.getContextType().isAssignableFrom(L2BridgeDomain.class) && AccessListUtil.findAddrEp(ctx, rEpKey) != null) {
91             Optional<GbpAceBuilder> allowExtAccess =
92                     AccessListUtil.allowExternalNetworksForEp(AccessListUtil.findAddrEp(ctx, rEpKey), policyDirection);
93             if (allowExtAccess.isPresent()) {
94                 aclWrapper.writeRule(allowExtAccess.get());
95             }
96         }
97         return aclWrapper;
98     }
99
100     public void updateAclsForPeers(PolicyContext policyCtx, RendererEndpointKey rEpKey) {
101         ImmutableSet<PeerEndpointKey> peers = policyCtx.getPolicyTable().row(rEpKey).keySet();
102         for (RendererEndpointKey peerRendEp : peers.stream()
103             .map(AddressEndpointUtils::fromPeerEpKey)
104             .collect(Collectors.toList())
105             .stream()
106             .map(AddressEndpointUtils::toRendererEpKey)
107             .collect(Collectors.toList())) {
108             updateAclsForRendEp(peerRendEp, policyCtx);
109         }
110     }
111
112     public void updateAclsForRendEp(RendererEndpointKey rEpKey, PolicyContext policyCtx) {
113         LOG.info("Updating policy for endpoint {}", rEpKey);
114         AddressEndpointWithLocation peerAddrEp = policyCtx.getAddrEpByKey().get(KeyFactory.addressEndpointKey(rEpKey));
115         ExternalLocationCase epLoc;
116         try {
117             epLoc = InterfaceManager.resolveAndValidateLocation(peerAddrEp);
118         } catch (NullPointerException | IllegalArgumentException e) {
119             //TODO investigate, don't just move on.
120             LOG.warn("Peer {} has no location. Moving on...", peerAddrEp, e.getMessage());
121             return;
122         }
123         InstanceIdentifier<?> vppNodeIid = epLoc.getExternalNodeMountPoint();
124         Optional<InstanceIdentifier<Interface>> optInterfaceIid =
125                 VppPathMapper.interfaceToInstanceIdentifier(epLoc.getExternalNodeConnector());
126         if (!optInterfaceIid.isPresent()) {
127             LOG.warn("Cannot  find interface for endpoint {}. ACLs for endpoint not updated {}. ", rEpKey);
128             return;
129         }
130         Optional<DataBroker> optMountPoint = mountDataProvider.getDataBrokerForMountPoint(vppNodeIid);
131         resolveAclsOnInterface(rEpKey, policyCtx).forEach(aclWrapper -> aclWrapper
132             .writeAcl(optMountPoint.get(), optInterfaceIid.get().firstKeyOf(Interface.class)));
133     }
134
135     /**
136      * Cache end-points accessible via a single interface for further processing.
137      */
138     public void cacheMultiInterfaces(@Nonnull PolicyContext ctx) {
139         Builder<NodeId, InterfaceKey, ImmutableSet<AddressEndpointKey>> resultBuilder = new Builder<>();
140         resolveEndpointsOnMultipleInterface(ImmutableList.copyOf(ctx.getAddrEpByKey().values()), resultBuilder);
141         multipleEndpointsOnInterface = resultBuilder.build();
142     }
143
144     private void resolveEndpointsOnMultipleInterface(@Nullable ImmutableList<AddressEndpointWithLocation> eps,
145             @Nonnull Builder<NodeId, InterfaceKey, ImmutableSet<AddressEndpointKey>> builder) {
146         if (eps == null || eps.isEmpty()) {
147             return;
148         }
149         eps.get(0);
150         ImmutableSet<AddressEndpointKey> copyOf = ImmutableSet.copyOf(eps.stream()
151             .filter(addrEp -> AddressEndpointUtils.sameExternalLocationCase(eps.get(0), addrEp))
152             .map(addrEp -> AddressEndpointUtils.fromAddressEndpointWithLocationKey(addrEp.getKey()))
153             .collect(Collectors.toSet()));
154         Optional<ExternalLocationCase> extLoc = EndpointUtils.getExternalLocationFrom(eps.get(0));
155         builder.put(extLoc.get().getExternalNodeMountPoint().firstKeyOf(Node.class).getNodeId(),
156                 new InterfaceKey(extLoc.get().getExternalNodeConnector()), copyOf);
157         ImmutableList<AddressEndpointWithLocation> lisst = ImmutableList.copyOf(eps.stream()
158             .filter(addrEp -> !AddressEndpointUtils.sameExternalLocationCase(eps.get(0), addrEp))
159             .collect(Collectors.toList()));
160         if (!lisst.isEmpty()) {
161             resolveEndpointsOnMultipleInterface(lisst, builder);
162         }
163     }
164
165     public @Nonnull static ImmutableSet<AddressEndpointKey> otherEndpointsOnTheSameInterface(@Nonnull PolicyContext ctx,
166             @Nonnull AddressEndpointKey key) {
167         if (multipleEndpointsOnInterface != null) {
168             for (InterfaceKey ifaceKey : multipleEndpointsOnInterface.columnKeySet()) {
169                 for (NodeId nodeId : multipleEndpointsOnInterface.column(ifaceKey).keySet()) {
170                     ImmutableSet<AddressEndpointKey> addrEps = multipleEndpointsOnInterface.get(nodeId, ifaceKey);
171                     if (addrEps != null && addrEps.contains(key) && addrEps.size() > 1) {
172                         return multipleEndpointsOnInterface.get(nodeId, ifaceKey);
173                     }
174                 }
175             }
176         }
177         return ImmutableSet.copyOf(Sets.newHashSet());
178     }
179 }