Provide Add Path support for all AFI/SAFI
[bgpcep.git] / bgp / openconfig-rp-spi / src / main / java / org / opendaylight / protocol / bgp / openconfig / routing / policy / spi / registry / GenericConditionPolicyHandler.java
1 /*
2  * Copyright (c) 2018 AT&T Intellectual Property. 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.protocol.bgp.openconfig.routing.policy.spi.registry;
10
11 import static java.util.Objects.requireNonNull;
12 import static org.opendaylight.yang.gen.v1.http.openconfig.net.yang.policy.types.rev151009.MatchSetOptionsRestrictedType.ANY;
13
14 import com.google.common.cache.CacheBuilder;
15 import com.google.common.cache.CacheLoader;
16 import com.google.common.cache.LoadingCache;
17 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.concurrent.ExecutionException;
23 import java.util.stream.Collectors;
24 import javax.annotation.Nonnull;
25 import org.apache.commons.lang3.StringUtils;
26 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
27 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
28 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
29 import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRouteEntryExportParameters;
30 import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRouteEntryImportParameters;
31 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.routing.policy.rev151009.GenericConditions;
32 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.routing.policy.rev151009.generic.conditions.MatchPrefixSet;
33 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.routing.policy.rev151009.generic.defined.sets.PrefixSets;
34 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.routing.policy.rev151009.prefix.set.PrefixSet;
35 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.routing.policy.rev151009.prefix.set.PrefixSetKey;
36 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.routing.policy.rev151009.prefix.set.prefix.set.Prefix;
37 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.routing.policy.rev151009.routing.policy.top.RoutingPolicy;
38 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.routing.policy.rev151009.routing.policy.top.routing.policy.DefinedSets;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev171207.ipv4.routes.ipv4.routes.Ipv4Route;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev171207.ipv6.routes.ipv6.routes.Ipv6Route;
44 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
45 import org.opendaylight.yangtools.yang.common.QName;
46 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
47
48 @SuppressFBWarnings("DLS_DEAD_LOCAL_STORE")
49 final class GenericConditionPolicyHandler {
50     private static final InstanceIdentifier<PrefixSets> PREFIXES_SET_IID
51             = InstanceIdentifier.create(RoutingPolicy.class).child(DefinedSets.class)
52             .child(PrefixSets.class);
53     private static final QName IPV4_PREFIX_QNAME = QName.create(Ipv4Route.QNAME, "prefix").intern();
54     private static final QName IPV6_PREFIX_QNAME = QName.create(Ipv6Route.QNAME, "prefix").intern();
55     private static final String EXACT = "exact";
56     private final DataBroker databroker;
57     private final LoadingCache<String, List<Prefix>> prefixSets = CacheBuilder.newBuilder()
58             .build(new CacheLoader<String, List<Prefix>>() {
59                 @Override
60                 public List<Prefix> load(final String key) throws ExecutionException, InterruptedException {
61                     return loadPrefixSets(key);
62                 }
63             });
64
65     private final LoadingCache<String, List<IpPrefix>> prefixes = CacheBuilder.newBuilder()
66             .build(new CacheLoader<String, List<IpPrefix>>() {
67                 @Override
68                 public List<IpPrefix> load(final String key) {
69                     final List<Prefix> prefixSet = GenericConditionPolicyHandler.this.prefixSets.getUnchecked(key);
70                     return prefixSet
71                             .stream().map(GenericConditionPolicyHandler::createPrefixes).flatMap(List::stream)
72                             .collect(Collectors.toList());
73                 }
74             });
75
76     GenericConditionPolicyHandler(final DataBroker databroker) {
77         this.databroker = requireNonNull(databroker);
78     }
79
80     private static List<IpPrefix> createPrefixes(final Prefix prefixContainer) {
81         final IpPrefix prefix = prefixContainer.getIpPrefix();
82         if (prefixContainer.getMasklengthRange().equals(EXACT)) {
83             return Collections.singletonList(prefix);
84         }
85
86         final String[] range = prefixContainer.getMasklengthRange().split("\\..");
87
88         boolean ipv4 = false;
89         final String prefixString;
90         if (prefix.getIpv4Prefix() != null) {
91             prefixString = prefix.getIpv4Prefix().getValue();
92             ipv4 = true;
93         } else {
94             prefixString = prefix.getIpv6Prefix().getValue();
95         }
96
97         int from = Integer.parseInt(range[0]);
98
99         final List<IpPrefix> prefixes = new ArrayList<>();
100         while (from <= Integer.parseInt(range[1])) {
101             final String prefixVal = StringUtils.replacePattern(prefixString,
102                     "[/][0-9]+", "/" + Integer.toString(from));
103             if (ipv4) {
104                 prefixes.add(new IpPrefix(new Ipv4Prefix(prefixVal)));
105             } else {
106                 prefixes.add(new IpPrefix(new Ipv6Prefix(prefixVal)));
107             }
108             from++;
109         }
110         return prefixes;
111     }
112
113     private List<Prefix> loadPrefixSets(final String key) throws ExecutionException, InterruptedException {
114         final ReadOnlyTransaction tr = this.databroker.newReadOnlyTransaction();
115         final com.google.common.base.Optional<PrefixSet> result =
116                 tr.read(LogicalDatastoreType.CONFIGURATION, PREFIXES_SET_IID
117                         .child(PrefixSet.class, new PrefixSetKey(key))).get();
118         if (!result.isPresent()) {
119             return Collections.emptyList();
120         }
121         return result.get().getPrefix();
122     }
123
124     public boolean matchImportCondition(final BGPRouteEntryImportParameters routeEntryImportParameters,
125             final GenericConditions conditions) {
126         final MatchPrefixSet prefixSet = conditions.getMatchPrefixSet();
127         //FIXME
128         return false;
129         /*return prefixSet == null
130                 || !matchPrefix(routeEntryImportParameters.getRouteId(), conditions.getMatchPrefixSet());*/
131     }
132
133     public boolean matchExportCondition(final BGPRouteEntryExportParameters routeEntryExportParameters,
134             final GenericConditions conditions) {
135         final MatchPrefixSet prefixSet = conditions.getMatchPrefixSet();
136         //FIXME
137         return false;
138         /*return prefixSet == null
139                 || matchPrefix(routeEntryExportParameters.getRouteId(), conditions.getMatchPrefixSet());*/
140     }
141
142     @SuppressFBWarnings("UPM_UNCALLED_PRIVATE_METHOD")
143     private boolean matchPrefix(
144             final NodeIdentifierWithPredicates routeId,
145             final MatchPrefixSet matchPrefixSet) {
146         final String prefixKey = StringUtils.substringBetween(matchPrefixSet.getPrefixSet(), "=\"", "\"");
147         final boolean any = matchPrefixSet.getMatchSetOptions().equals(ANY);
148         final boolean found = this.prefixes.getUnchecked(prefixKey).contains(extractPrefix(routeId));
149         return any && found || !any && !found;
150     }
151
152     @Nonnull
153     private IpPrefix extractPrefix(final NodeIdentifierWithPredicates routeId) {
154         final QName qName = routeId.getNodeType();
155         if (Ipv4Route.QNAME.equals(qName)) {
156             final Map<QName, Object> values = routeId.getKeyValues();
157             return new IpPrefix(new Ipv4Prefix((String) values.get(IPV4_PREFIX_QNAME)));
158         } else {
159             final Map<QName, Object> values = routeId.getKeyValues();
160             return new IpPrefix(new Ipv6Prefix((String) values.get(IPV6_PREFIX_QNAME)));
161         }
162     }
163 }