Skip to content

Commit

Permalink
FRR: implement route-map match ip address prefix-len (#6617)
Browse files Browse the repository at this point in the history
  • Loading branch information
dhalperi committed Feb 10, 2021
1 parent 0083db5 commit 4f1b7e9
Show file tree
Hide file tree
Showing 10 changed files with 213 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,11 @@ POINT_TO_POINT
'point-to-point'
;

PREFIX_LEN
:
'prefix-len'
;

PREFIX_LIST
:
'prefix-list' -> pushMode ( M_Word )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ ip_prefix_list_name
WORD
;

ip_prefix_length
:
// 0-32
UINT8
;

line_action
:
deny = DENY
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ pl_line_action
|
(
ip_prefix = prefix
(GE ge = ip_prefix_list_line_prefix_length)?
(LE le = ip_prefix_list_line_prefix_length)?
(GE ge = ip_prefix_length)?
(LE le = ip_prefix_length)?
NEWLINE
)
)
Expand All @@ -36,10 +36,4 @@ pl_line_action
pl_line_description
:
DESCRIPTION REMARK_TEXT NEWLINE
;

ip_prefix_list_line_prefix_length
:
// 1-32
UINT8
;
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,20 @@ rm_match
(
rmm_as_path
| rmm_community
// | rmm_evpn
// | rmm_extcommunity
| rmm_interface
| rmm_ip
| rmm_ipv6
// | rmm_large_community
// | rmm_local_preference
// | rmm_mac
// | rmm_metric
// | rmm_origin
// | rmm_peer
// | rmm_probability
// | rmm_source_protocol
// | rmm_source_vrf
| rmm_tag
)
;
Expand Down Expand Up @@ -99,7 +110,12 @@ rms_metric

rmm_ip
:
IP rmmip_address
IP
(
rmmip_address
// | rmmip_next_hop
// | rmmip_route_source
)
;

rmm_ipv6
Expand All @@ -114,7 +130,20 @@ rmm_tag

rmmip_address
:
ADDRESS rmmipa_prefix_list
ADDRESS
(
// rmmipa_access_list_standard
// rmmipa_access_list_extended
// rmmipa_access_list_name
rmmipa_prefix_len
| rmmipa_prefix_list
)
;

rmmipa_prefix_len
:
// len; 0-32
PREFIX_LEN len = ip_prefix_length NEWLINE
;

rmmipa_prefix_list
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Range;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
Expand All @@ -48,6 +49,7 @@
import org.batfish.common.Warnings;
import org.batfish.common.Warnings.ParseWarning;
import org.batfish.datamodel.ConcreteInterfaceAddress;
import org.batfish.datamodel.IntegerSpace;
import org.batfish.datamodel.Ip;
import org.batfish.datamodel.Ip6;
import org.batfish.datamodel.LineAction;
Expand All @@ -66,6 +68,7 @@
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Ip_addressContext;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Ip_as_pathContext;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Ip_community_list_nameContext;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Ip_prefix_lengthContext;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Ip_prefix_listContext;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Ip_routeContext;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Line_actionContext;
Expand All @@ -80,6 +83,7 @@
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Rmm_communityContext;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Rmm_interfaceContext;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Rmm_tagContext;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Rmmipa_prefix_lenContext;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Rmmipa_prefix_listContext;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Rmom_gotoContext;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Rmom_nextContext;
Expand Down Expand Up @@ -203,6 +207,7 @@
import org.batfish.representation.cumulus.RouteMapMatchAsPath;
import org.batfish.representation.cumulus.RouteMapMatchCommunity;
import org.batfish.representation.cumulus.RouteMapMatchInterface;
import org.batfish.representation.cumulus.RouteMapMatchIpAddressPrefixLen;
import org.batfish.representation.cumulus.RouteMapMatchIpAddressPrefixList;
import org.batfish.representation.cumulus.RouteMapMatchTag;
import org.batfish.representation.cumulus.RouteMapSetAsPath;
Expand All @@ -217,14 +222,17 @@
import org.batfish.representation.cumulus.Vrf;

public class CumulusFrrConfigurationBuilder extends CumulusFrrParserBaseListener {
private static final IntegerSpace PREFIX_LENGTH_SPACE =
IntegerSpace.of(Range.closed(0, Prefix.MAX_PREFIX_LENGTH));

private final CumulusConcatenatedConfiguration _c;
private final CumulusFrrConfiguration _frr;
private final CumulusFrrCombinedParser _parser;
private final Warnings _w;
private final String _text;

private @Nullable Vrf _currentVrf;
private @Nullable RouteMapEntry _currentRouteMapEntry;
private RouteMapEntry _currentRouteMapEntry;
private @Nullable BgpVrf _currentBgpVrf;
private @Nullable BgpNeighbor _currentBgpNeighbor;
private @Nullable IpPrefixList _currentIpPrefixList;
Expand Down Expand Up @@ -353,6 +361,33 @@ private static long toLong(TerminalNode t) {
return ctx.getText();
}

/**
* Convert a {@link ParserRuleContext} whose text is guaranteed to represent a valid signed 32-bit
* decimal integer to an {@link Integer} if it is contained in the provided {@code space}, or else
* {@link Optional#empty}.
*/
private @Nonnull Optional<Integer> toIntegerInSpace(
ParserRuleContext messageCtx, ParserRuleContext ctx, IntegerSpace space, String name) {
int num = Integer.parseInt(ctx.getText());
if (!space.contains(num)) {
_w.addWarning(
messageCtx,
getFullText(messageCtx),
_parser,
String.format("Expected %s in range %s, but got '%d'", name, space, num));
return Optional.empty();
}
return Optional.of(num);
}

private Integer toInteger(Interface_ospf_costContext ctx) {
return Integer.parseInt(ctx.getText());
}

private Optional<Integer> toInteger(ParserRuleContext ctx, Ip_prefix_lengthContext len) {
return toIntegerInSpace(ctx, len, PREFIX_LENGTH_SPACE, "prefix length");
}

private void clearOspfPassiveInterface() {
_frr.getInterfaces()
.values()
Expand Down Expand Up @@ -941,10 +976,6 @@ public void exitSiipo_cost(Siipo_costContext ctx) {
_currentInterface.getOrCreateOspf().setCost(toInteger(ctx.interface_ospf_cost()));
}

private Integer toInteger(Interface_ospf_costContext ctx) {
return Integer.parseInt(ctx.getText());
}

@Override
public void exitSbbb_aspath_multipath_relax(Sbbb_aspath_multipath_relaxContext ctx) {
_currentBgpVrf.setAsPathMultipathRelax(true);
Expand Down Expand Up @@ -1239,6 +1270,15 @@ public void exitRmm_as_path(Rmm_as_pathContext ctx) {
ctx.getStart().getLine());
}

@Override
public void exitRmmipa_prefix_len(Rmmipa_prefix_lenContext ctx) {
Optional<Integer> maybeLen = toInteger(ctx, ctx.len);
maybeLen.ifPresent(
len ->
_currentRouteMapEntry.setMatchIpAddressPrefixLen(
new RouteMapMatchIpAddressPrefixLen(len)));
}

@Override
public void exitRmmipa_prefix_list(Rmmipa_prefix_listContext ctx) {
String name = ctx.name.getText();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public final class RouteMapEntry implements Serializable {
private @Nullable RouteMapMatchAsPath _matchAsPath;
private @Nullable RouteMapMatchCommunity _matchCommunity;
private @Nullable RouteMapMatchInterface _matchInterface;
private @Nullable RouteMapMatchIpAddressPrefixLen _matchIpAddressPrefixLen;
private @Nullable RouteMapMatchIpAddressPrefixList _matchIpAddressPrefixList;
private @Nullable RouteMapMatchTag _matchTag;
private final int _number;
Expand Down Expand Up @@ -53,7 +54,12 @@ public void setCall(@Nullable RouteMapCall call) {
/** Return stream of match statements for this entry. */
public @Nonnull Stream<RouteMapMatch> getMatches() {
return Stream.of(
_matchAsPath, _matchInterface, _matchCommunity, _matchIpAddressPrefixList, _matchTag)
_matchAsPath,
_matchInterface,
_matchCommunity,
_matchIpAddressPrefixLen,
_matchIpAddressPrefixList,
_matchTag)
.filter(Objects::nonNull);
}

Expand All @@ -69,6 +75,15 @@ public void setCall(@Nullable RouteMapCall call) {
return _matchCommunity;
}

public @Nullable RouteMapMatchIpAddressPrefixLen getMatchIpAddressPrefixLen() {
return _matchIpAddressPrefixLen;
}

public void setMatchIpAddressPrefixLen(
@Nullable RouteMapMatchIpAddressPrefixLen matchIpAddressPrefixLen) {
_matchIpAddressPrefixLen = matchIpAddressPrefixLen;
}

public @Nullable RouteMapMatchIpAddressPrefixList getMatchIpAddressPrefixList() {
return _matchIpAddressPrefixList;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.batfish.representation.cumulus;

import javax.annotation.Nonnull;
import org.batfish.common.Warnings;
import org.batfish.datamodel.Configuration;
import org.batfish.datamodel.Prefix;
import org.batfish.datamodel.PrefixRange;
import org.batfish.datamodel.PrefixSpace;
import org.batfish.datamodel.SubRange;
import org.batfish.datamodel.routing_policy.expr.BooleanExpr;
import org.batfish.datamodel.routing_policy.expr.DestinationNetwork;
import org.batfish.datamodel.routing_policy.expr.ExplicitPrefixSet;
import org.batfish.datamodel.routing_policy.expr.MatchPrefixSet;

/**
* A {@link RouteMapMatch} that matches routes based on whether the route's network has the given
* prefix length.
*/
public final class RouteMapMatchIpAddressPrefixLen implements RouteMapMatch {

private final int _len;

public RouteMapMatchIpAddressPrefixLen(int len) {
_len = len;
}

@Override
public @Nonnull BooleanExpr toBooleanExpr(
Configuration c, CumulusNodeConfiguration vc, Warnings w) {
return new MatchPrefixSet(
DestinationNetwork.instance(),
new ExplicitPrefixSet(
new PrefixSpace(new PrefixRange(Prefix.ZERO, SubRange.singleton(_len)))));
}

public int getLen() {
return _len;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.hasToString;
import static org.hamcrest.Matchers.isA;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
Expand Down Expand Up @@ -1159,6 +1160,20 @@ public void testCumulusFrrVrfRouteMapMatchCommunity_multiline() {
contains(3));
}

@Test
public void testCumulusFrrVrfRouteMapMatchPrefixLen() {
String name = "ROUTE-MAP-NAME";
String match1 = "match ip address prefix-len 7";
String match2 = "match ip address prefix-len 8";

parse(String.format("route-map %s permit 10\n%s\n%s\n", name, match1, match2));

RouteMapEntry entry = _frr.getRouteMaps().get(name).getEntries().get(10);
assertThat(entry.getMatchIpAddressPrefixLen(), notNullValue());
// Multiple commands overwrite - last one wins.
assertThat(entry.getMatchIpAddressPrefixLen().getLen(), equalTo(8));
}

@Test
public void testCumulusFrrVrfRouteMapMatchPrefixList() {
String name = "ROUTE-MAP-NAME";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ public void testGetMatches_Community() {
assertThat(matches, contains(isA(RouteMapMatchCommunity.class)));
}

@Test
public void testGetMatches_PrefixLen() {
RouteMapEntry entry = new RouteMapEntry(10, LineAction.DENY);
entry.setMatchIpAddressPrefixLen(new RouteMapMatchIpAddressPrefixLen(3));

ImmutableList<RouteMapMatch> matches =
entry.getMatches().collect(ImmutableList.toImmutableList());

assertThat(matches, contains(isA(RouteMapMatchIpAddressPrefixLen.class)));
}

@Test
public void testGetMatches_PrefixList() {
RouteMapEntry entry = new RouteMapEntry(10, LineAction.DENY);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.batfish.representation.cumulus;

import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;

import org.batfish.common.Warnings;
import org.batfish.datamodel.Configuration;
import org.batfish.datamodel.Prefix;
import org.batfish.datamodel.StaticRoute;
import org.batfish.datamodel.routing_policy.Environment;
import org.batfish.datamodel.routing_policy.Result;
import org.batfish.datamodel.routing_policy.expr.BooleanExpr;
import org.junit.Test;

public class RouteMapMatchIpAddressPrefixLenTest {

@Test
public void testConstructionAndGetter() {
RouteMapMatchIpAddressPrefixLen match = new RouteMapMatchIpAddressPrefixLen(7);
assertThat(match.getLen(), equalTo(7));
}

@Test
public void testToBooleanExpr() {
RouteMapMatchIpAddressPrefixLen match = new RouteMapMatchIpAddressPrefixLen(7);
CumulusNcluConfiguration config = new CumulusNcluConfiguration();
Configuration c = Configuration.builder().setHostname("c").build();
BooleanExpr expr = match.toBooleanExpr(c, config, new Warnings());
for (Prefix p :
new Prefix[] {Prefix.ZERO, Prefix.parse("10.0.0.0/6"), Prefix.parse("10.0.0.0/8")}) {
StaticRoute route = StaticRoute.testBuilder().setNetwork(p).build();
assertThat(
expr.evaluate(Environment.builder(c).setOriginalRoute(route).build()),
equalTo(Result.builder().setBooleanValue(false).build()));
}
for (Prefix p : new Prefix[] {Prefix.parse("10.0.0.0/7"), Prefix.parse("20.0.0.0/7")}) {
StaticRoute route = StaticRoute.testBuilder().setNetwork(p).build();
assertThat(
expr.evaluate(Environment.builder(c).setOriginalRoute(route).build()),
equalTo(Result.builder().setBooleanValue(true).build()));
}
}
}

0 comments on commit 4f1b7e9

Please sign in to comment.