Skip to content

Commit

Permalink
JunOS: Support As-Path-Group (#8613)
Browse files Browse the repository at this point in the history
Add support for `as-path-group` definition and use in `policy-statement`.
  • Loading branch information
ktaegyum committed Dec 6, 2022
1 parent 6b9b5be commit 1d7d56e
Show file tree
Hide file tree
Showing 11 changed files with 259 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,7 @@
import org.batfish.representation.juniper.PolicyStatement;
import org.batfish.representation.juniper.PrefixList;
import org.batfish.representation.juniper.PsFromAsPath;
import org.batfish.representation.juniper.PsFromAsPathGroup;
import org.batfish.representation.juniper.PsFromColor;
import org.batfish.representation.juniper.PsFromCommunity;
import org.batfish.representation.juniper.PsFromCommunityCount;
Expand Down Expand Up @@ -5504,10 +5505,9 @@ public void exitPopsf_as_path(Popsf_as_pathContext ctx) {
@Override
public void exitPopsf_as_path_group(Popsf_as_path_groupContext ctx) {
String name = toString(ctx.name);
_currentPsTerm.getFroms().addFromAsPathGroup(new PsFromAsPathGroup(name));
_configuration.referenceStructure(
AS_PATH_GROUP, name, POLICY_STATEMENT_FROM_AS_PATH_GROUP, getLine(ctx.getStart()));
_currentPsTerm.getFroms().setFromUnsupported(new PsFromUnsupported());
todo(ctx);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3141,6 +3141,10 @@ private BooleanExpr toGuard(PsFroms froms) {
if (!froms.getFromAsPaths().isEmpty()) {
conj.getConjuncts().add(new Disjunction(toBooleanExprs(froms.getFromAsPaths())));
}
if (!froms.getFromAsPathGroups().isEmpty()) {
// TODO: Figure out how it works when both as-path and as-path-group present
conj.getConjuncts().add(new Disjunction(toBooleanExprs(froms.getFromAsPathGroups())));
}
if (froms.getFromColor() != null) {
conj.getConjuncts().add(froms.getFromColor().toBooleanExpr(this, _c, _w));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.batfish.representation.juniper;

import static org.batfish.representation.juniper.parboiled.AsPathRegex.convertToJavaRegex;

import com.google.common.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import org.batfish.common.Warnings;
import org.batfish.datamodel.Configuration;
import org.batfish.datamodel.routing_policy.as_path.AsPathMatchRegex;
import org.batfish.datamodel.routing_policy.as_path.InputAsPath;
import org.batfish.datamodel.routing_policy.as_path.MatchAsPath;
import org.batfish.datamodel.routing_policy.expr.BooleanExpr;
import org.batfish.datamodel.routing_policy.expr.BooleanExprs;
import org.batfish.datamodel.routing_policy.expr.Disjunction;

public final class PsFromAsPathGroup extends PsFrom {
private final String _asPathGroupName;

public PsFromAsPathGroup(String asPathGroupName) {
_asPathGroupName = asPathGroupName;
}

@Override
public BooleanExpr toBooleanExpr(JuniperConfiguration jc, Configuration c, Warnings warnings) {
Map<String, AsPathGroup> asPathGroups = jc.getMasterLogicalSystem().getAsPathGroups();
return toBooleanExpr(asPathGroups.get(_asPathGroupName), warnings);
}

@VisibleForTesting
static BooleanExpr toBooleanExpr(@Nullable AsPathGroup asPathGroup, Warnings w) {
if (asPathGroup == null) {
// Undefined reference, return false.
return BooleanExprs.FALSE;
}
List<BooleanExpr> asPaths = new ArrayList<>();
for (NamedAsPath namedAsPath : asPathGroup.getAsPaths().values()) {
try {
String convertedVIRegex = convertToJavaRegex(namedAsPath.getRegex());
asPaths.add(MatchAsPath.of(InputAsPath.instance(), AsPathMatchRegex.of(convertedVIRegex)));
} catch (Exception e) {
w.redFlag(
String.format(
"Error converting Juniper as-path-group regex %s, will assume no paths match"
+ " instead: %s.",
asPathGroup.getName(), e.getMessage()));
/* Handle error, add false to the list instead */
asPaths.add(BooleanExprs.FALSE);
}
}
return new Disjunction(asPaths);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public final class PsFroms implements Serializable {
private boolean _atLeastOneFrom = false;

private final Set<PsFromAsPath> _fromAsPaths;
private final Set<PsFromAsPathGroup> _fromAsPathGroups;
private PsFromColor _fromColor;
private final Set<PsFromCommunity> _fromCommunities;
private PsFromCommunityCount _fromCommunityCount;
Expand All @@ -34,6 +35,7 @@ public final class PsFroms implements Serializable {

PsFroms() {
_fromAsPaths = new LinkedHashSet<>();
_fromAsPathGroups = new LinkedHashSet<>();
_fromCommunities = new LinkedHashSet<>();
_fromConditions = new LinkedHashSet<>();
_fromInterfaces = new LinkedHashSet<>();
Expand All @@ -52,6 +54,11 @@ public void addFromAsPath(@Nonnull PsFromAsPath fromAsPath) {
_fromAsPaths.add(fromAsPath);
}

public void addFromAsPathGroup(@Nonnull PsFromAsPathGroup fromAsPathGroup) {
_atLeastOneFrom = true;
_fromAsPathGroups.add(fromAsPathGroup);
}

public void addFromCommunity(@Nonnull PsFromCommunity fromCommunity) {
_atLeastOneFrom = true;
_fromCommunities.add(fromCommunity);
Expand Down Expand Up @@ -115,6 +122,11 @@ Set<PsFromAsPath> getFromAsPaths() {
return _fromAsPaths;
}

@Nonnull
Set<PsFromAsPathGroup> getFromAsPathGroups() {
return _fromAsPathGroups;
}

@VisibleForTesting
public @Nullable PsFromColor getFromColor() {
return _fromColor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4710,6 +4710,33 @@ FAMILY_POLICY should accept only inet6 (each set overwrites previous)
assertThat(result.getBooleanValue(), equalTo(true));
result = tagPolicy.call(Environment.builder(c).setOutputRoute(srb.setTag(3L)).build());
assertThat(result.getBooleanValue(), equalTo(false));

/*
AS_PATH_GROUP_POLICY should accept routes from as-path within as-path-group
set policy-options policy-statement AS_PATH_GROUP_POLICY term T1 from as-path-group AS_PATH_GROUP
*/
RoutingPolicy asPathGroupPolicy = c.getRoutingPolicies().get("AS_PATH_GROUP_POLICY");
Bgpv4Route.Builder test =
Bgpv4Route.testBuilder()
.setAdmin(100)
.setNetwork(testPrefix)
.setOriginatorIp(Ip.parse("2.2.2.2"))
.setOriginType(OriginType.INCOMPLETE)
.setProtocol(RoutingProtocol.BGP);
result =
asPathGroupPolicy.call(
envWithRoute(c, test.setAsPath(AsPath.ofSingletonAsSets(1L)).build()));
assertThat(result.getBooleanValue(), equalTo(true));

result =
asPathGroupPolicy.call(
envWithRoute(c, test.setAsPath(AsPath.ofSingletonAsSets(2L)).build()));
assertThat(result.getBooleanValue(), equalTo(true));

result =
asPathGroupPolicy.call(
envWithRoute(c, test.setAsPath(AsPath.ofSingletonAsSets(3L)).build()));
assertThat(result.getBooleanValue(), equalTo(false));
}

private static Environment envWithRoute(Configuration c, AbstractRoute route) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package org.batfish.representation.juniper;

import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

import com.google.common.collect.Iterables;
import org.batfish.common.Warnings;
import org.batfish.datamodel.routing_policy.expr.BooleanExpr;
import org.batfish.datamodel.routing_policy.expr.BooleanExprs;
import org.batfish.datamodel.routing_policy.expr.Disjunction;
import org.junit.Test;

/** Tests of {@link PsFromAsPathGroup}. */
public class PsFromAsPathGroupTest {

@Test
public void testUndefined() {
Warnings w = new Warnings(true, true, true);
BooleanExpr ret = PsFromAsPathGroup.toBooleanExpr(null, w);
assertThat(ret, is(BooleanExprs.FALSE));
assertThat(w.getRedFlagWarnings(), empty()); // Prefer undefined reference elsewhere
}

@Test
public void testConversionError() {
AsPathGroup asPathGroup = new AsPathGroup("Group");
asPathGroup
.getAsPaths()
.put("not-aspath", new NamedAsPath("not-aspath", "this is not a valid as-path regex"));

Warnings w = new Warnings(true, true, true);
BooleanExpr ret = PsFromAsPathGroup.toBooleanExpr(asPathGroup, w);

assertThat(ret, equalTo(new Disjunction(BooleanExprs.FALSE)));
assertThat(w.getRedFlagWarnings(), hasSize(1));
assertThat(
Iterables.getOnlyElement(w.getRedFlagWarnings()).getText(),
containsString("Error converting Juniper as-path-group regex Group"));
}

@Test
public void testConversionErrorWithValidRegex() {
AsPathGroup asPathGroup = new AsPathGroup("Group");
asPathGroup.getAsPaths().put("aspath1", new NamedAsPath("aspath1", "1 2"));
asPathGroup
.getAsPaths()
.put("not-aspath", new NamedAsPath("not-aspath", "this is not a valid as-path regex"));

Warnings w = new Warnings(true, true, true);
BooleanExpr ret = PsFromAsPathGroup.toBooleanExpr(asPathGroup, w);

assertThat(ret, instanceOf(Disjunction.class));
assertThat(w.getRedFlagWarnings(), hasSize(1));
}

@Test
public void testConversion() {
AsPathGroup asPathGroup = new AsPathGroup("Group");
asPathGroup.getAsPaths().put("aspath1", new NamedAsPath("aspath1", "1 2"));
asPathGroup.getAsPaths().put("aspath2", new NamedAsPath("aspath2", "3 4"));

Warnings w = new Warnings(true, true, true);
BooleanExpr ret = PsFromAsPathGroup.toBooleanExpr(asPathGroup, w);

assertThat(ret, instanceOf(Disjunction.class));
assertThat(w.getRedFlagWarnings(), empty());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ set policy-options community BGP1 members 1
set policy-options community BGP2 members 2
set policy-options community BGP3 members 3
#
set policy-options as-path-group AS_PATH_GROUP as-path ASN1 ".* 1$"
set policy-options as-path-group AS_PATH_GROUP as-path ASN2 ".* 2$"
#
set policy-options as-path AS1 1
set policy-options as-path AS2 2
set policy-options as-path AS3 3
Expand All @@ -19,6 +22,9 @@ set policy-options prefix-list PL4 4.4.4.0/24
set policy-options prefix-list PL5 5.5.5.0/24
set policy-options prefix-list PL6 6.6.6.0/24
#
set policy-options policy-statement AS_PATH_GROUP_POLICY term T1 from as-path-group AS_PATH_GROUP
set policy-options policy-statement AS_PATH_GROUP_POLICY term T1 then accept
#
# Untested until "set policy-options as-path AS1 1" is extracted
# set policy-options policy-statement AS_PATH_POLICY term T1 from as-path AS1
# set policy-options policy-statement AS_PATH_POLICY term T1 from as-path AS2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,5 @@ set policy-options policy-statement POLICY-NAME from protocol evpn
#
set policy-options as-path ORIGINATED_IN_65535 ".* 65535"
set policy-options as-path UNUSED_ORIGINATED_IN_65535 ".* 65535"
set policy-options as-path-group AS_PATH_GROUP as-path ASN65534 ".* 65534$"
set policy-options as-path-group AS_PATH_GROUP as-path ASN65535 ".* 65535$"
15 changes: 13 additions & 2 deletions tests/parsing-tests/unit-tests-unused.ref
Original file line number Diff line number Diff line change
Expand Up @@ -2888,6 +2888,17 @@
]
}
},
{
"Structure_Type" : "as-path-group",
"Structure_Name" : "AS_PATH_GROUP",
"Source_Lines" : {
"filename" : "configs/juniper_policy_statement",
"lines" : [
46,
47
]
}
},
{
"Structure_Type" : "policy-statement",
"Structure_Name" : "POLICY-NAME",
Expand Down Expand Up @@ -3772,10 +3783,10 @@
}
],
"summary" : {
"notes" : "Found 247 results",
"notes" : "Found 248 results",
"numFailed" : 0,
"numPassed" : 0,
"numResults" : 247
"numResults" : 248
}
}
]
11 changes: 2 additions & 9 deletions tests/parsing-tests/unit-tests-warnings.ref
Original file line number Diff line number Diff line change
Expand Up @@ -1358,13 +1358,6 @@
"Parser_Context" : "[oa_area_range o_area o_common p_ospf3 s_protocols s_common statement set_line_tail set_line flat_juniper_configuration]",
"Comment" : "This feature is not currently supported"
},
{
"Filename" : "configs/juniper_policy_statement",
"Line" : 4,
"Text" : "as-path-group AS_PATH_GROUP",
"Parser_Context" : "[popsf_as_path_group pops_from pops_common pops_term po_policy_statement s_policy_options s_common statement set_line_tail set_line flat_juniper_configuration]",
"Comment" : "This feature is not currently supported"
},
{
"Filename" : "configs/juniper_policy_statement",
"Line" : 18,
Expand Down Expand Up @@ -1444,10 +1437,10 @@
}
],
"summary" : {
"notes" : "Found 200 results",
"notes" : "Found 199 results",
"numFailed" : 0,
"numPassed" : 0,
"numResults" : 200
"numResults" : 199
}
}
]

0 comments on commit 1d7d56e

Please sign in to comment.