Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FRR: support route map set as-path exclude #7251

Merged
merged 7 commits into from
Sep 30, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ public static AsPath ofSingletonAsSets(List<Long> asNums) {
return of(asNums.stream().map(AsSet::of).collect(ImmutableList.toImmutableList()));
}

public static AsPath ofAsSets(AsSet... asSets) {
return of(Arrays.asList(asSets));
}

private final List<AsSet> _asSets;

// Soft values: let it be garbage collected in times of pressure.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
import org.batfish.datamodel.routing_policy.statement.BufferedStatement;
import org.batfish.datamodel.routing_policy.statement.CallStatement;
import org.batfish.datamodel.routing_policy.statement.Comment;
import org.batfish.datamodel.routing_policy.statement.ExcludeAsPath;
import org.batfish.datamodel.routing_policy.statement.If;
import org.batfish.datamodel.routing_policy.statement.PrependAsPath;
import org.batfish.datamodel.routing_policy.statement.SetAdministrativeCost;
Expand Down Expand Up @@ -678,6 +679,12 @@ public Void visitPrependAsPath(
return null;
}

@Override
public Void visitExcludeAsPath(
ExcludeAsPath excludeAsPath, CommunityStructuresVerifierContext arg) {
return null;
}

@Override
public Void visitSetAdministrativeCost(
SetAdministrativeCost setAdministrativeCost, CommunityStructuresVerifierContext arg) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.batfish.datamodel.routing_policy.statement.BufferedStatement;
import org.batfish.datamodel.routing_policy.statement.CallStatement;
import org.batfish.datamodel.routing_policy.statement.Comment;
import org.batfish.datamodel.routing_policy.statement.ExcludeAsPath;
import org.batfish.datamodel.routing_policy.statement.If;
import org.batfish.datamodel.routing_policy.statement.PrependAsPath;
import org.batfish.datamodel.routing_policy.statement.SetAdministrativeCost;
Expand Down Expand Up @@ -409,6 +410,12 @@ public Void visitPrependAsPath(
return null;
}

@Override
public Void visitExcludeAsPath(
ExcludeAsPath excludeAsPath, AsPathStructuresVerifierContext arg) {
return null;
}

@Override
public Void visitSetAdministrativeCost(
SetAdministrativeCost setAdministrativeCost, AsPathStructuresVerifierContext arg) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package org.batfish.datamodel.routing_policy.statement;

import static com.google.common.base.Preconditions.checkArgument;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Longs;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import org.batfish.datamodel.AsPath;
import org.batfish.datamodel.AsSet;
import org.batfish.datamodel.BgpRoute;
import org.batfish.datamodel.HasWritableAsPath;
import org.batfish.datamodel.routing_policy.Environment;
import org.batfish.datamodel.routing_policy.Result;
import org.batfish.datamodel.routing_policy.expr.AsPathListExpr;

/** Class to represent exclude as-path statement */
@ParametersAreNonnullByDefault
public final class ExcludeAsPath extends Statement {
private static final String PROP_EXPR = "expr";

/** Expression that holds the information of the statement */
@Nonnull private AsPathListExpr _expr;

@JsonCreator
private static ExcludeAsPath jsonCreator(@Nullable @JsonProperty(PROP_EXPR) AsPathListExpr expr) {
checkArgument(expr != null, "%s must be provided", PROP_EXPR);
return new ExcludeAsPath(expr);
}

public ExcludeAsPath(AsPathListExpr expr) {
_expr = expr;
}

@Override
public <T, U> T accept(StatementVisitor<T, U> visitor, U arg) {
return visitor.visitExcludeAsPath(this, arg);
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (!(obj instanceof ExcludeAsPath)) {
return false;
}
ExcludeAsPath other = (ExcludeAsPath) obj;
return _expr.equals(other._expr);
}

/**
* Function that executes the statement based on an {@link Environment}
*
* @param environment Network {@link Environment}
* @return {@link Result}
*/
@Override
public Result execute(Environment environment) {
if ((environment.getOutputRoute() instanceof HasWritableAsPath<?, ?>)) {
List<Long> asToExclude = new ArrayList<>(_expr.evaluate(environment));

HasWritableAsPath<?, ?> outputRoute = (HasWritableAsPath<?, ?>) environment.getOutputRoute();
outputRoute.setAsPath(
AsPath.of(
ImmutableList.<AsSet>builder()
.addAll(
outputRoute.getAsPath().getAsSets().stream()
.map(
currentAsSet ->
AsSet.of(
Longs.toArray(
currentAsSet.getAsns().stream()
.filter(currentAs -> !asToExclude.contains(currentAs))
.collect(Collectors.toList()))))
.filter(currentAsSet -> !currentAsSet.isEmpty())
.collect(Collectors.toList()))
.build()));

if (environment.getWriteToIntermediateBgpAttributes()) {
BgpRoute.Builder<?, ?> ir = environment.getIntermediateBgpAttributes();
ir.setAsPath(
AsPath.of(
ImmutableList.<AsSet>builder()
.addAll(
ir.getAsPath().getAsSets().stream()
.map(
currentAsSet ->
AsSet.of(
Longs.toArray(
currentAsSet.getAsns().stream()
.filter(
currentAs -> !asToExclude.contains(currentAs))
.collect(Collectors.toList()))))
.filter(currentAsSet -> !currentAsSet.isEmpty())
.collect(Collectors.toList()))
.build()));
}
}

return new Result();
}

@JsonProperty(PROP_EXPR)
@Nonnull
public AsPathListExpr getExpr() {
return _expr;
}

@Override
public int hashCode() {
return _expr.hashCode();
}

public void setExpr(AsPathListExpr expr) {
_expr = expr;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,7 @@ public Result execute(Environment environment) {
.build()));
}

Result result = new Result();
return result;
return new Result();
}

@JsonProperty(PROP_EXPR)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public interface StatementVisitor<T, U> {

T visitPrependAsPath(PrependAsPath prependAsPath, U arg);

T visitExcludeAsPath(ExcludeAsPath excludeAsPath, U arg);

T visitSetAdministrativeCost(SetAdministrativeCost setAdministrativeCost, U arg);

T visitSetCommunities(SetCommunities setCommunities, U arg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
import org.batfish.datamodel.routing_policy.statement.BufferedStatement;
import org.batfish.datamodel.routing_policy.statement.CallStatement;
import org.batfish.datamodel.routing_policy.statement.Comment;
import org.batfish.datamodel.routing_policy.statement.ExcludeAsPath;
import org.batfish.datamodel.routing_policy.statement.If;
import org.batfish.datamodel.routing_policy.statement.PrependAsPath;
import org.batfish.datamodel.routing_policy.statement.SetAdministrativeCost;
Expand Down Expand Up @@ -162,6 +163,8 @@ public void testStatementVerifierUnrelated() {
assertNull(new Comment("a").accept(STATEMENT_VERIFIER, ctx));
assertNull(
new PrependAsPath(new LiteralAsList(ImmutableList.of())).accept(STATEMENT_VERIFIER, ctx));
assertNull(
new ExcludeAsPath(new LiteralAsList(ImmutableList.of())).accept(STATEMENT_VERIFIER, ctx));
assertNull(new SetAdministrativeCost(new LiteralInt(1)).accept(STATEMENT_VERIFIER, ctx));
assertNull(new SetDefaultPolicy("a").accept(STATEMENT_VERIFIER, ctx));
assertNull(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
import org.batfish.datamodel.routing_policy.statement.BufferedStatement;
import org.batfish.datamodel.routing_policy.statement.CallStatement;
import org.batfish.datamodel.routing_policy.statement.Comment;
import org.batfish.datamodel.routing_policy.statement.ExcludeAsPath;
import org.batfish.datamodel.routing_policy.statement.If;
import org.batfish.datamodel.routing_policy.statement.PrependAsPath;
import org.batfish.datamodel.routing_policy.statement.SetAdministrativeCost;
Expand Down Expand Up @@ -150,6 +151,8 @@ public void testStatementVerifierUnrelated() {
assertNull(new Comment("a").accept(STATEMENT_VERIFIER, ctx));
assertNull(
new PrependAsPath(new LiteralAsList(ImmutableList.of())).accept(STATEMENT_VERIFIER, ctx));
assertNull(
new ExcludeAsPath(new LiteralAsList(ImmutableList.of())).accept(STATEMENT_VERIFIER, ctx));
assertNull(new SetAdministrativeCost(new LiteralInt(1)).accept(STATEMENT_VERIFIER, ctx));
assertNull(new SetCommunities(InputCommunities.instance()).accept(STATEMENT_VERIFIER, ctx));
assertNull(new SetDefaultPolicy("a").accept(STATEMENT_VERIFIER, ctx));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package org.batfish.datamodel.routing_policy.statement;

import static org.batfish.datamodel.AsPath.ofAsSets;
import static org.batfish.datamodel.AsPath.ofSingletonAsSets;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;

import com.google.common.collect.Lists;
import java.util.List;
import org.batfish.datamodel.AsSet;
import org.batfish.datamodel.Bgpv4Route;
import org.batfish.datamodel.Configuration;
import org.batfish.datamodel.ConfigurationFormat;
import org.batfish.datamodel.routing_policy.Environment;
import org.batfish.datamodel.routing_policy.expr.AsExpr;
import org.batfish.datamodel.routing_policy.expr.ExplicitAs;
import org.batfish.datamodel.routing_policy.expr.LiteralAsList;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public final class ExcludeAsPathTest {

private static Environment newTestEnvironment(Bgpv4Route.Builder outputRoute) {
Configuration c = new Configuration("host", ConfigurationFormat.CISCO_IOS);
return Environment.builder(c).setOutputRoute(outputRoute).build();
}

@Test
public void testExcludeMissingAsFromAsSet() {
List<AsExpr> exclude = Lists.newArrayList(new ExplicitAs(3L));
ExcludeAsPath operation = new ExcludeAsPath(new LiteralAsList(exclude));
Bgpv4Route.Builder builder = Bgpv4Route.testBuilder();
builder.setAsPath(ofSingletonAsSets(4L, 5L));
Environment env = newTestEnvironment(builder);

operation.execute(env);
assertThat(builder.getAsPath(), equalTo(ofSingletonAsSets(4L, 5L)));
}

@Test
public void testExcludeAsSet() {
List<AsExpr> exclude = Lists.newArrayList(new ExplicitAs(3L));
ExcludeAsPath operation = new ExcludeAsPath(new LiteralAsList(exclude));
Bgpv4Route.Builder builder = Bgpv4Route.testBuilder();
builder.setAsPath(ofAsSets(AsSet.of(3L), AsSet.of(3L, 4L)));
Environment env = newTestEnvironment(builder);

operation.execute(env);
assertThat(builder.getAsPath(), equalTo(ofSingletonAsSets(4L)));
}

@Test
public void testExcludeSingletonAsSet() {
List<AsExpr> exclude = Lists.newArrayList(new ExplicitAs(3L));
ExcludeAsPath operation = new ExcludeAsPath(new LiteralAsList(exclude));
Bgpv4Route.Builder builder = Bgpv4Route.testBuilder();
builder.setAsPath(ofSingletonAsSets(3L, 4L));
Environment env = newTestEnvironment(builder);

operation.execute(env);
assertThat(builder.getAsPath(), equalTo(ofSingletonAsSets(4L)));
}

@Test
public void testExcludeWithIntermediateAttributes() {
List<AsExpr> exclude = Lists.newArrayList(new ExplicitAs(3));
ExcludeAsPath operation = new ExcludeAsPath(new LiteralAsList(exclude));
Bgpv4Route.Builder outputRoute = Bgpv4Route.testBuilder();
outputRoute.setAsPath(ofSingletonAsSets(3L, 4L));

Bgpv4Route.Builder intermediateAttributes = Bgpv4Route.testBuilder();
intermediateAttributes.setAsPath(ofSingletonAsSets(3L, 5L));
Environment env = newTestEnvironment(outputRoute);
env.setIntermediateBgpAttributes(intermediateAttributes);
env.setWriteToIntermediateBgpAttributes(true);

operation.execute(env);
assertThat(outputRoute.getAsPath(), equalTo(ofSingletonAsSets(4L)));
assertThat(intermediateAttributes.getAsPath(), equalTo(ofSingletonAsSets(5L)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,8 @@ PREFIX_LIST

PREPEND: 'prepend';

EXCLUDE: 'exclude';

RA_INTERVAL: 'ra-interval';

RANGE: 'range';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ rmm_interface

rms_as_path
:
AS_PATH PREPEND as_path = literal_as_path NEWLINE
AS_PATH (EXCLUDE | PREPEND) as_path = literal_as_path NEWLINE
;

rm_on_match
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,14 @@
import org.batfish.representation.cumulus.RouteMapMatchSourceProtocol.Protocol;
import org.batfish.representation.cumulus.RouteMapMatchTag;
import org.batfish.representation.cumulus.RouteMapMetricType;
import org.batfish.representation.cumulus.RouteMapSetAsPath;
import org.batfish.representation.cumulus.RouteMapSetCommListDelete;
import org.batfish.representation.cumulus.RouteMapSetCommunity;
import org.batfish.representation.cumulus.RouteMapSetExcludeAsPath;
import org.batfish.representation.cumulus.RouteMapSetIpNextHopLiteral;
import org.batfish.representation.cumulus.RouteMapSetLocalPreference;
import org.batfish.representation.cumulus.RouteMapSetMetric;
import org.batfish.representation.cumulus.RouteMapSetMetricType;
import org.batfish.representation.cumulus.RouteMapSetPrependAsPath;
import org.batfish.representation.cumulus.RouteMapSetTag;
import org.batfish.representation.cumulus.RouteMapSetWeight;
import org.batfish.representation.cumulus.StaticRoute;
Expand Down Expand Up @@ -1575,7 +1576,13 @@ public void exitRmom_goto(Rmom_gotoContext ctx) {
public void exitRms_as_path(Rms_as_pathContext ctx) {
List<Long> asns =
ctx.as_path.asns.stream().map(this::toLong).collect(ImmutableList.toImmutableList());
_currentRouteMapEntry.setSetAsPath(new RouteMapSetAsPath(asns));

if (ctx.PREPEND() != null) {
_currentRouteMapEntry.setSetAsPath(new RouteMapSetPrependAsPath(asns));
} else {
assert ctx.EXCLUDE() != null;
_currentRouteMapEntry.setSetExcludeAsPath(new RouteMapSetExcludeAsPath(asns));
}
}

@Override
Expand Down