bf82b94925fc4cbc09c3906da235037801cfe674
[bgpcep.git] / bgp / openconfig-rp-spi / src / main / java / org / opendaylight / protocol / bgp / openconfig / routing / policy / spi / registry / BgpConditionsRegistry.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 package org.opendaylight.protocol.bgp.openconfig.routing.policy.spi.registry;
9
10 import com.google.common.base.Preconditions;
11 import java.util.HashMap;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Objects;
15 import javax.annotation.concurrent.GuardedBy;
16 import org.opendaylight.protocol.bgp.openconfig.routing.policy.spi.RouteEntryBaseAttributes;
17 import org.opendaylight.protocol.bgp.openconfig.routing.policy.spi.policy.condition.BgpConditionsAugmentationPolicy;
18 import org.opendaylight.protocol.bgp.openconfig.routing.policy.spi.policy.condition.BgpConditionsPolicy;
19 import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRouteEntryExportParameters;
20 import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRouteEntryImportParameters;
21 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.policy.rev151009.BgpMatchConditions;
22 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.policy.rev151009.Conditions1;
23 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.policy.rev151009.bgp.attribute.conditions.AsPathLength;
24 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.policy.rev151009.bgp.match.conditions.MatchAsPathSet;
25 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.policy.rev151009.bgp.match.conditions.MatchCommunitySet;
26 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.policy.rev151009.bgp.match.conditions.MatchExtCommunitySet;
27 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.policy.rev151009.routing.policy.policy.definitions.policy.definition.statements.statement.conditions.BgpConditions;
28 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.BgpOriginAttrType;
29 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.policy.types.rev151009.AttributeComparison;
30 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.policy.types.rev151009.AttributeEq;
31 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.policy.types.rev151009.AttributeGe;
32 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.policy.types.rev151009.AttributeLe;
33 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.routing.policy.rev151009.routing.policy.top.routing.policy.policy.definitions.policy.definition.statements.statement.Conditions;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.path.attributes.Attributes;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.path.attributes.attributes.AsPath;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.path.attributes.attributes.LocalPref;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.path.attributes.attributes.MultiExitDisc;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.path.attributes.attributes.Origin;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.path.attributes.attributes.as.path.Segments;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.AsPathSegment;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.CNextHop;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.c.next.hop.EmptyNextHopCase;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.c.next.hop.Ipv4NextHopCase;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.c.next.hop.Ipv6NextHopCase;
46 import org.opendaylight.yangtools.concepts.AbstractRegistration;
47 import org.opendaylight.yangtools.yang.binding.Augmentation;
48 import org.opendaylight.yangtools.yang.binding.ChildOf;
49 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
50
51 public final class BgpConditionsRegistry {
52     @GuardedBy("this")
53     private final Map<Class<? extends Augmentation<BgpConditions>>,
54             BgpConditionsAugmentationPolicy> bgpConditionsAugRegistry = new HashMap<>();
55     @GuardedBy("this")
56     private final Map<Class<? extends ChildOf<BgpMatchConditions>>,
57             BgpConditionsPolicy> bgpConditionsRegistry = new HashMap<>();
58
59     public AbstractRegistration registerBgpConditionsAugmentationPolicy(
60             final Class<? extends Augmentation<BgpConditions>> conditionPolicyClass,
61             final BgpConditionsAugmentationPolicy conditionPolicy) {
62         synchronized (this.bgpConditionsAugRegistry) {
63             final BgpConditionsAugmentationPolicy prev
64                     = this.bgpConditionsAugRegistry.putIfAbsent(conditionPolicyClass, conditionPolicy);
65             Preconditions.checkState(prev == null, "Condition Policy %s already registered %s",
66                     conditionPolicyClass, prev);
67             return new AbstractRegistration() {
68                 @Override
69                 protected void removeRegistration() {
70                     synchronized (BgpConditionsRegistry.this.bgpConditionsAugRegistry) {
71                         BgpConditionsRegistry.this.bgpConditionsAugRegistry.remove(conditionPolicyClass);
72                     }
73                 }
74             };
75         }
76     }
77
78     public <T extends ChildOf<BgpMatchConditions>, N> AbstractRegistration registerBgpConditionsPolicy(
79             final Class<T> conditionPolicyClass,
80             final BgpConditionsPolicy<T, N> conditionPolicy) {
81         synchronized (this.bgpConditionsRegistry) {
82             final BgpConditionsPolicy prev
83                     = this.bgpConditionsRegistry.putIfAbsent(conditionPolicyClass, conditionPolicy);
84             Preconditions.checkState(prev == null, "Condition Policy %s already registered %s",
85                     conditionPolicyClass, prev);
86             return new AbstractRegistration() {
87                 @Override
88                 protected void removeRegistration() {
89                     synchronized (BgpConditionsRegistry.this.bgpConditionsRegistry) {
90                         BgpConditionsRegistry.this.bgpConditionsRegistry.remove(conditionPolicyClass);
91                     }
92                 }
93             };
94         }
95     }
96
97     @SuppressWarnings("unchecked")
98     public boolean matchExportConditions(
99             final RouteEntryBaseAttributes entryInfo,
100             final BGPRouteEntryExportParameters routeEntryExportParameters,
101             final Attributes attributes,
102             final Conditions conditions) {
103         final Conditions1 bgpConditionsAug = conditions.getAugmentation(Conditions1.class);
104         if (bgpConditionsAug != null) {
105
106             final BgpConditions bgpConditions = bgpConditionsAug.getBgpConditions();
107             if (!matchExportCondition(entryInfo, routeEntryExportParameters, attributes,
108                     bgpConditions)) {
109                 return false;
110             }
111             final Map<Class<? extends Augmentation<?>>, Augmentation<?>> bgpAug = BindingReflections
112                     .getAugmentations(bgpConditions);
113             for (final Map.Entry<Class<? extends Augmentation<?>>, Augmentation<?>> entry : bgpAug.entrySet()) {
114                 final BgpConditionsAugmentationPolicy handler = this.bgpConditionsAugRegistry.get(entry.getKey());
115                 if (handler == null) {
116                     continue;
117                 }
118                 if (!handler.matchExportCondition(entryInfo, routeEntryExportParameters,
119                         handler.getConditionParameter(attributes), entry.getValue())) {
120                     return false;
121                 }
122             }
123         }
124         return true;
125     }
126
127
128     public boolean matchImportConditions(
129             final RouteEntryBaseAttributes entryInfo,
130             final BGPRouteEntryImportParameters routeEntryImportParameters,
131             final Attributes attributes,
132             final Conditions conditions) {
133
134         final Conditions1 bgpConditionsAug = conditions.getAugmentation(Conditions1.class);
135         if (bgpConditionsAug != null) {
136             final BgpConditions bgpConditions = bgpConditionsAug.getBgpConditions();
137             synchronized (this) {
138                 if (!matchImportCondition(entryInfo, routeEntryImportParameters, attributes,
139                         bgpConditions)) {
140                     return false;
141                 }
142             }
143             final Map<Class<? extends Augmentation<?>>, Augmentation<?>> bgpAug = BindingReflections
144                     .getAugmentations(bgpConditions);
145             for (final Map.Entry<Class<? extends Augmentation<?>>, Augmentation<?>> entry : bgpAug.entrySet()) {
146                 final BgpConditionsAugmentationPolicy handler = this.bgpConditionsAugRegistry.get(entry.getKey());
147                 if (handler == null) {
148                     continue;
149                 }
150                 if (!handler.matchImportCondition(entryInfo, routeEntryImportParameters,
151                         handler.getConditionParameter(attributes), entry.getValue())) {
152                     return false;
153                 }
154             }
155         }
156         return true;
157     }
158
159     @SuppressWarnings("unchecked")
160     private boolean matchImportCondition(
161             final RouteEntryBaseAttributes routeEntryInfo,
162             final BGPRouteEntryImportParameters routeEntryImportParameters,
163             final Attributes attributes,
164             final BgpConditions conditions) {
165
166         if (!matchAsPathLength(attributes.getAsPath(), conditions.getAsPathLength())) {
167             return false;
168         }
169
170         if (!matchMED(attributes.getMultiExitDisc(), conditions.getMedEq())) {
171             return false;
172         }
173
174         if (!matchOrigin(attributes.getOrigin(), conditions.getOriginEq())) {
175             return false;
176         }
177
178         if (!matchNextHopIn(attributes.getCNextHop(), conditions.getNextHopIn())) {
179             return false;
180         }
181
182         if (!matchLocalPref(attributes.getLocalPref(), conditions.getLocalPrefEq())) {
183             return false;
184         }
185
186         final MatchCommunitySet matchCond = conditions.getMatchCommunitySet();
187         if (matchCond != null) {
188             final BgpConditionsPolicy handler = this.bgpConditionsRegistry.get(MatchCommunitySet.class);
189             if (!handler.matchImportCondition(routeEntryInfo, routeEntryImportParameters,
190                     handler.getConditionParameter(attributes), matchCond)) {
191                 return false;
192             }
193         }
194
195         final MatchAsPathSet matchAsPathSet = conditions.getMatchAsPathSet();
196         if (matchCond != null) {
197             final BgpConditionsPolicy handler = this.bgpConditionsRegistry.get(MatchAsPathSet.class);
198             if (!handler.matchImportCondition(routeEntryInfo, routeEntryImportParameters,
199                     handler.getConditionParameter(attributes), matchAsPathSet)) {
200                 return false;
201             }
202         }
203
204         final MatchExtCommunitySet matchExtCommSet = conditions.getMatchExtCommunitySet();
205         if (matchExtCommSet != null) {
206             final BgpConditionsPolicy handler = this.bgpConditionsRegistry.get(MatchAsPathSet.class);
207             if (!handler.matchImportCondition(routeEntryInfo, routeEntryImportParameters,
208                     handler.getConditionParameter(attributes), matchExtCommSet)) {
209                 return false;
210             }
211         }
212
213         return true;
214     }
215
216     @SuppressWarnings("unchecked")
217     private boolean matchExportCondition(
218             final RouteEntryBaseAttributes routeEntryInfo,
219             final BGPRouteEntryExportParameters routeEntryExportParameters,
220             final Attributes attributes,
221             final BgpConditions conditions) {
222         if (!matchAsPathLength(attributes.getAsPath(), conditions.getAsPathLength())) {
223             return false;
224         }
225
226         if (!matchMED(attributes.getMultiExitDisc(), conditions.getMedEq())) {
227             return false;
228         }
229
230         if (!matchOrigin(attributes.getOrigin(), conditions.getOriginEq())) {
231             return false;
232         }
233
234         if (!matchNextHopIn(attributes.getCNextHop(), conditions.getNextHopIn())) {
235             return false;
236         }
237
238         if (!matchLocalPref(attributes.getLocalPref(), conditions.getLocalPrefEq())) {
239             return false;
240         }
241
242         final MatchCommunitySet matchCond = conditions.getMatchCommunitySet();
243         if (matchCond != null) {
244             final BgpConditionsPolicy handler = this.bgpConditionsRegistry.get(MatchCommunitySet.class);
245             if (!handler.matchExportCondition(routeEntryInfo, routeEntryExportParameters,
246                     handler.getConditionParameter(attributes), matchCond)) {
247                 return false;
248             }
249         }
250
251         final MatchAsPathSet matchAsPathSet = conditions.getMatchAsPathSet();
252         if (matchAsPathSet != null) {
253             final BgpConditionsPolicy handler = this.bgpConditionsRegistry.get(MatchAsPathSet.class);
254             if (!handler.matchExportCondition(routeEntryInfo, routeEntryExportParameters,
255                     handler.getConditionParameter(attributes), matchAsPathSet)) {
256                 return false;
257             }
258         }
259
260         final MatchExtCommunitySet matchExtCommSet = conditions.getMatchExtCommunitySet();
261         if (matchExtCommSet != null) {
262             final BgpConditionsPolicy handler = this.bgpConditionsRegistry.get(MatchExtCommunitySet.class);
263             if (!handler.matchExportCondition(routeEntryInfo, routeEntryExportParameters,
264                     handler.getConditionParameter(attributes), matchExtCommSet)) {
265                 return false;
266             }
267         }
268
269         return true;
270     }
271
272     private boolean matchMED(final MultiExitDisc multiExitDisc, final Long med) {
273         if (multiExitDisc == null || med == null) {
274             return true;
275         }
276
277         return multiExitDisc.getMed().equals(med);
278     }
279
280     private boolean matchOrigin(final Origin origin, final BgpOriginAttrType originEq) {
281         if (origin == null || originEq == null) {
282             return true;
283         }
284         return origin.getValue().getIntValue() == originEq.getIntValue();
285     }
286
287     private boolean matchAsPathLength(final AsPath asPath, final AsPathLength asPathLength) {
288         if (asPath == null || asPathLength == null) {
289             return true;
290         }
291
292         final List<Segments> segments = asPath.getSegments();
293         int total = segments.stream().map(AsPathSegment::getAsSequence)
294                 .filter(Objects::nonNull).mapToInt(List::size).sum();
295
296         if (total == 0) {
297             total = segments.stream().map(AsPathSegment::getAsSet)
298                     .filter(Objects::nonNull).mapToInt(List::size).sum();
299         }
300
301         final Class<? extends AttributeComparison> comp = asPathLength.getOperator();
302         final long asPathLenght = asPathLength.getValue();
303         if (comp == AttributeEq.class) {
304             return total == asPathLenght;
305         } else if (comp == AttributeGe.class) {
306             return total >= asPathLenght;
307         } else if (comp == AttributeLe.class) {
308             return total <= asPathLenght;
309         }
310         return false;
311     }
312
313
314     private boolean matchNextHopIn(final CNextHop nextHop, final List<IpAddress> nextHopIn) {
315         if (nextHop == null || nextHopIn == null || nextHop instanceof EmptyNextHopCase) {
316             return true;
317         }
318
319         IpAddress global;
320         if (nextHop instanceof Ipv4NextHopCase) {
321             global = new IpAddress(((Ipv4NextHopCase) nextHop).getIpv4NextHop().getGlobal());
322         } else {
323             global = new IpAddress(((Ipv6NextHopCase) nextHop).getIpv6NextHop().getGlobal());
324         }
325         return nextHopIn.contains(global);
326     }
327
328     private boolean matchLocalPref(final LocalPref localPref, final Long localPrefEq) {
329         if (localPref == null || localPrefEq == null) {
330             return true;
331         }
332         return localPref.getPref().equals(localPrefEq);
333     }
334 }