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: Adding OSPF to BGP Redistribution Route-Map Support #6052

Merged
merged 11 commits into from
Aug 28, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ s_bgp
| sb_neighbor
| sb_network
| sb_no
| sb_redistribute
| sbafi_neighbor
)*
;
Expand Down Expand Up @@ -87,6 +88,11 @@ sbbb_aspath_multipath_relax
AS_PATH MULTIPATH_RELAX NEWLINE
;

sb_redistribute
:
REDISTRIBUTE bgp_redist_type (ROUTE_MAP route_map_name)? NEWLINE
;

sbb_router_id
:
ROUTER_ID IP_ADDRESS NEWLINE
Expand Down Expand Up @@ -165,10 +171,9 @@ sbafi_network

sbafi_redistribute
:
REDISTRIBUTE (STATIC | CONNECTED) (ROUTE_MAP route_map_name)? NEWLINE
REDISTRIBUTE bgp_redist_type (ROUTE_MAP route_map_name)? NEWLINE
;


sbafl_advertise_all_vni
:
ADVERTISE_ALL_VNI NEWLINE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ route_map_name
WORD
;

bgp_redist_type
:
STATIC | CONNECTED | OSPF
;

standard_community
:
literal = literal_standard_community
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
import static org.batfish.datamodel.Configuration.DEFAULT_VRF_NAME;
import static org.batfish.grammar.cumulus_frr.CumulusFrrParser.Int_exprContext;
import static org.batfish.representation.cumulus.CumulusConversions.DEFAULT_MAX_MED;
import static org.batfish.representation.cumulus.CumulusRoutingProtocol.CONNECTED;
import static org.batfish.representation.cumulus.CumulusRoutingProtocol.STATIC;
import static org.batfish.representation.cumulus.CumulusStructureType.ABSTRACT_INTERFACE;
import static org.batfish.representation.cumulus.CumulusStructureType.IP_AS_PATH_ACCESS_LIST;
import static org.batfish.representation.cumulus.CumulusStructureType.IP_COMMUNITY_LIST;
Expand All @@ -16,6 +14,7 @@
import static org.batfish.representation.cumulus.CumulusStructureType.ROUTE_MAP;
import static org.batfish.representation.cumulus.CumulusStructureType.VRF;
import static org.batfish.representation.cumulus.CumulusStructureUsage.BGP_IPV4_UNICAST_REDISTRIBUTE_CONNECTED_ROUTE_MAP;
import static org.batfish.representation.cumulus.CumulusStructureUsage.BGP_IPV4_UNICAST_REDISTRIBUTE_OSPF_ROUTE_MAP;
import static org.batfish.representation.cumulus.CumulusStructureUsage.BGP_IPV4_UNICAST_REDISTRIBUTE_STATIC_ROUTE_MAP;
import static org.batfish.representation.cumulus.CumulusStructureUsage.ROUTE_MAP_CALL;
import static org.batfish.representation.cumulus.CumulusStructureUsage.ROUTE_MAP_MATCH_COMMUNITY_LIST;
Expand Down Expand Up @@ -54,6 +53,7 @@
import org.batfish.datamodel.routing_policy.expr.LiteralLong;
import org.batfish.datamodel.routing_policy.expr.LongExpr;
import org.batfish.grammar.UnrecognizedLineToken;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Bgp_redist_typeContext;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Icl_expandedContext;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Icl_standardContext;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Interface_ospf_costContext;
Expand Down Expand Up @@ -95,6 +95,7 @@
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.S_vrfContext;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Sb_neighborContext;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Sb_networkContext;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Sb_redistributeContext;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Sbaf_ipv4_unicastContext;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Sbaf_l2vpn_evpnContext;
import org.batfish.grammar.cumulus_frr.CumulusFrrParser.Sbafi_aggregate_addressContext;
Expand Down Expand Up @@ -372,33 +373,51 @@ public void enterSbaf_l2vpn_evpn(Sbaf_l2vpn_evpnContext ctx) {
_currentBgpVrf.setL2VpnEvpn(new BgpL2vpnEvpnAddressFamily());
}

@Override
public void exitSb_redistribute(Sb_redistributeContext ctx) {
String routeMap = ctx.route_map_name() == null ? null : ctx.route_map_name().getText();
handleOspfToBgpRedistribution(ctx, ctx.bgp_redist_type(), routeMap);
}

@Override
public void exitSbafi_redistribute(Sbafi_redistributeContext ctx) {
CumulusRoutingProtocol protocol;
String routeMap = ctx.route_map_name() == null ? null : ctx.route_map_name().getText();
handleOspfToBgpRedistribution(ctx, ctx.bgp_redist_type(), routeMap);
}

public void handleOspfToBgpRedistribution(
ParserRuleContext ctx,
Bgp_redist_typeContext bgpRedistTypeContext,
@Nullable String routeMap) {
CumulusRoutingProtocol srcProtocol;
CumulusStructureUsage usage;
if (ctx.STATIC() != null) {
protocol = STATIC;

if (bgpRedistTypeContext.STATIC() != null) {
usage = BGP_IPV4_UNICAST_REDISTRIBUTE_STATIC_ROUTE_MAP;
} else if (ctx.CONNECTED() != null) {
protocol = CONNECTED;
srcProtocol = CumulusRoutingProtocol.STATIC;
} else if (bgpRedistTypeContext.CONNECTED() != null) {
usage = BGP_IPV4_UNICAST_REDISTRIBUTE_CONNECTED_ROUTE_MAP;
srcProtocol = CumulusRoutingProtocol.CONNECTED;
} else if (bgpRedistTypeContext.OSPF() != null) {
usage = BGP_IPV4_UNICAST_REDISTRIBUTE_OSPF_ROUTE_MAP;
srcProtocol = CumulusRoutingProtocol.OSPF;
} else {
throw new BatfishException("Unexpected redistribution protocol");
}

String routeMap;
if (ctx.route_map_name() != null) {
routeMap = ctx.route_map_name().getText();
if (routeMap != null) {
_c.referenceStructure(ROUTE_MAP, routeMap, usage, ctx.getStart().getLine());
} else {
routeMap = null;
}

BgpRedistributionPolicy oldRedistributionPolicy =
BgpRedistributionPolicy oldRedistributionPolicy;

_currentBgpVrf.getOrCreateIpv4Unicast();

oldRedistributionPolicy =
_currentBgpVrf
.getIpv4Unicast()
.getRedistributionPolicies()
.put(protocol, new BgpRedistributionPolicy(protocol, routeMap));
.put(srcProtocol, new BgpRedistributionPolicy(srcProtocol, routeMap));

if (oldRedistributionPolicy != null) {
_w.addWarning(
Expand All @@ -407,7 +426,7 @@ public void exitSbafi_redistribute(Sbafi_redistributeContext ctx) {
_parser,
String.format(
"overwriting BgpRedistributionPolicy for vrf %s, protocol %s",
_currentBgpVrf.getVrfName(), protocol));
_currentBgpVrf.getVrfName(), srcProtocol));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.batfish.datamodel.Ip;
Expand All @@ -24,13 +25,16 @@ public class BgpVrf implements Serializable {
private final @Nonnull String _vrfName;
private @Nullable Long _confederationId;
private @Nullable Long _maxMedAdministrative;
private final @Nonnull Map<CumulusRoutingProtocol, BgpRedistributionPolicy>
_redistributionPolicies;

public BgpVrf(String vrfName) {
// the default is true unless explicitly disabled (via "no bgp default ipv4-unicast")
_defaultIpv4Unicast = true;
_vrfName = vrfName;
_neighbors = new HashMap<>();
_networks = ImmutableMap.of();
_redistributionPolicies = new TreeMap<>();
}

public boolean isIpv4UnicastActive() {
Expand Down Expand Up @@ -75,6 +79,14 @@ public void setMaxMedAdministrative(@Nullable Long maxMedAdministrative) {
return _ipv4Unicast;
}

public BgpIpv4UnicastAddressFamily getOrCreateIpv4Unicast() {
if (_ipv4Unicast != null) {
return _ipv4Unicast;
}
_ipv4Unicast = new BgpIpv4UnicastAddressFamily();
return _ipv4Unicast;
}

public @Nullable BgpL2vpnEvpnAddressFamily getL2VpnEvpn() {
return _l2VpnEvpn;
}
Expand Down Expand Up @@ -132,4 +144,8 @@ public void addNetwork(Prefix network) {
.put(network, new BgpNetwork(network))
.build();
}

public @Nonnull Map<CumulusRoutingProtocol, BgpRedistributionPolicy> getRedistributionPolicies() {
return _redistributionPolicies;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -957,27 +957,32 @@ private static List<BooleanExpr> getBgpExportConditions(
firstNonNull(bgpVrf.getIpv4Unicast(), new BgpIpv4UnicastAddressFamily());

// Add conditions to redistribute other protocols
for (BgpRedistributionPolicy redistributeProtocolPolicy :
bgpIpv4UnicastAddressFamily.getRedistributionPolicies().values()) {

// Get a match expression for the protocol to be redistributed
CumulusRoutingProtocol protocol = redistributeProtocolPolicy.getProtocol();
MatchProtocol matchProtocol = new MatchProtocol(VI_PROTOCOLS_MAP.get(protocol));

// Create a WithEnvironmentExpr with the redistribution route-map, if one is defined
BooleanExpr weInterior = BooleanExprs.TRUE;
String mapName = redistributeProtocolPolicy.getRouteMap();
if (mapName != null && routeMaps.keySet().contains(mapName)) {
weInterior = new CallExpr(mapName);
}
BooleanExpr we = bgpRedistributeWithEnvironmentExpr(weInterior, OriginType.INCOMPLETE);
Stream.concat(
bgpVrf.getRedistributionPolicies().values().stream(),
bgpIpv4UnicastAddressFamily.getRedistributionPolicies().values().stream())
.forEach(
redistributeProtocolPolicy -> {

// Export routes that match the protocol and WithEnvironmentExpr
Conjunction exportProtocolConditions = new Conjunction(ImmutableList.of(matchProtocol, we));
exportProtocolConditions.setComment(
String.format("Redistribute %s routes into BGP", protocol));
exportConditions.add(exportProtocolConditions);
}
// Get a match expression for the protocol to be redistributed
CumulusRoutingProtocol protocol = redistributeProtocolPolicy.getProtocol();
MatchProtocol matchProtocol = new MatchProtocol(VI_PROTOCOLS_MAP.get(protocol));

// Create a WithEnvironmentExpr with the redistribution route-map, if one is defined
BooleanExpr weInterior = BooleanExprs.TRUE;
String mapName = redistributeProtocolPolicy.getRouteMap();
if (mapName != null && routeMaps.keySet().contains(mapName)) {
weInterior = new CallExpr(mapName);
}
BooleanExpr we =
bgpRedistributeWithEnvironmentExpr(weInterior, OriginType.INCOMPLETE);

// Export routes that match the protocol and WithEnvironmentExpr
Conjunction exportProtocolConditions =
new Conjunction(ImmutableList.of(matchProtocol, we));
exportProtocolConditions.setComment(
String.format("Redistribute %s routes into BGP", protocol));
exportConditions.add(exportProtocolConditions);
});

// create origination prefilter from listed advertised networks
Sets.union(bgpVrf.getNetworks().keySet(), bgpIpv4UnicastAddressFamily.getNetworks().keySet())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import org.batfish.datamodel.RoutingProtocol;

public enum CumulusRoutingProtocol {
OSPF,
BGP,
CONNECTED,
STATIC;

Expand All @@ -15,6 +17,13 @@ public enum CumulusRoutingProtocol {
*/
public static final Map<CumulusRoutingProtocol, Set<RoutingProtocol>> VI_PROTOCOLS_MAP =
ImmutableMap.of(
BGP, ImmutableSet.of(RoutingProtocol.BGP, RoutingProtocol.IBGP),
OSPF,
ImmutableSet.of(
RoutingProtocol.OSPF,
RoutingProtocol.OSPF_E1,
RoutingProtocol.OSPF_E2,
RoutingProtocol.OSPF_IA),
CONNECTED, ImmutableSet.of(RoutingProtocol.CONNECTED),
STATIC, ImmutableSet.of(RoutingProtocol.STATIC));
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public enum CumulusStructureUsage implements StructureUsage {
BGP_IPV4_UNICAST_REDISTRIBUTE_CONNECTED_ROUTE_MAP(
"bgp ipv4 unicast redistribute connected route-map"),
BGP_IPV4_UNICAST_REDISTRIBUTE_STATIC_ROUTE_MAP("bgp ipv4 unicast redistribute static route-map"),
BGP_IPV4_UNICAST_REDISTRIBUTE_OSPF_ROUTE_MAP("bgp ipv4 unicast redistribute ospf route-map"),
BGP_IPV4_UNICAST_NEIGHBOR_ROUTE_MAP_IN("bgp ipv4 unicast neighbor route-map in"),
BGP_IPV4_UNICAST_NEIGHBOR_ROUTE_MAP_OUT("bgp ipv4 unicast neighbor route-map out"),
BGP_NEIGHBOR_INTERFACE("bgp neighbor interface"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static org.batfish.datamodel.routing_policy.Environment.Direction.OUT;
import static org.batfish.grammar.cumulus_frr.CumulusFrrConfigurationBuilder.nextMultipleOfFive;
import static org.batfish.representation.cumulus.CumulusRoutingProtocol.CONNECTED;
import static org.batfish.representation.cumulus.CumulusRoutingProtocol.OSPF;
import static org.batfish.representation.cumulus.CumulusRoutingProtocol.STATIC;
import static org.batfish.representation.cumulus.CumulusStructureType.IP_AS_PATH_ACCESS_LIST;
import static org.batfish.representation.cumulus.CumulusStructureType.IP_COMMUNITY_LIST;
Expand Down Expand Up @@ -244,6 +245,47 @@ public void testBgpAddressFamilyIpv4UnicastRedistributeRouteMap() {
assertThat(policy.getRouteMap(), equalTo("foo"));
}

@Test
public void testBgpRedistributeOspfRouteMap() {
parseLines("router bgp 1", "redistribute ospf route-map foo");
BgpRedistributionPolicy policy =
_frr.getBgpProcess().getDefaultVrf().getIpv4Unicast().getRedistributionPolicies().get(OSPF);
assertNotNull(policy);
assertThat(policy.getRouteMap(), equalTo("foo"));
}

@Test
public void testBgpRedistributeOspf() {
parseLines("router bgp 1", "redistribute ospf");
BgpRedistributionPolicy policy =
_frr.getBgpProcess().getDefaultVrf().getIpv4Unicast().getRedistributionPolicies().get(OSPF);
assertNotNull(policy);
assertNull(policy.getRouteMap());
}

@Test
public void testBgpAddressFamilyIpv4UnicastRedistributeOspfRouteMap() {
parseLines(
"router bgp 1",
"address-family ipv4 unicast",
"redistribute ospf route-map foo",
"exit-address-family");
BgpRedistributionPolicy policy =
_frr.getBgpProcess().getDefaultVrf().getIpv4Unicast().getRedistributionPolicies().get(OSPF);
assertNotNull(policy);
assertThat(policy.getRouteMap(), equalTo("foo"));
}

@Test
public void testBgpAddressFamilyIpv4UnicastRedistributeOspf() {
parseLines(
"router bgp 1", "address-family ipv4 unicast", "redistribute ospf", "exit-address-family");
BgpRedistributionPolicy policy =
_frr.getBgpProcess().getDefaultVrf().getIpv4Unicast().getRedistributionPolicies().get(OSPF);
assertNotNull(policy);
assertNull(policy.getRouteMap());
}

@Test
public void testBgpAddressFamilyIpv4UnicastRedistributeStatic() {
parseLines(
Expand Down Expand Up @@ -1799,4 +1841,47 @@ public void testBgpcommunityMatchSetTagAndWeight_behavior() throws IOException {
.setTag(10000L)
.build())));
}

@Test
public void testBgpRedistribution_behavior() throws IOException {
/*
There are four nodes in the topology arranged in a line.
- frr-ospf-originator -- frr-redistributor -- frr-listener

frr-ospf-originator spawns routes into ospf and is ospf adjacent with frr-redistributor

frr-redistributor will redist a single OSPF route into BGP and advertise to frr-listener
*/

String snapshotName = "redistribution-test";
List<String> configurationNames =
ImmutableList.of("frr-ospf-originator", "frr-redistributor", "frr-listener");
Batfish batfish =
BatfishTestUtils.getBatfishFromTestrigText(
TestrigText.builder()
.setConfigurationFiles(SNAPSHOTS_PREFIX + snapshotName, configurationNames)
.build(),
_folder);

NetworkSnapshot snapshot = batfish.getSnapshot();
batfish.computeDataPlane(snapshot);
DataPlane dp = batfish.loadDataPlane(snapshot);

assertThat(
dp.getRibs().get("frr-listener").get(DEFAULT_VRF_NAME).getRoutes(),
hasItem(
equalTo(
Bgpv4Route.builder()
.setNetwork(Prefix.parse("2.2.2.2/32"))
.setNextHopIp(Ip.parse("10.1.1.1"))
.setReceivedFromIp(Ip.parse("10.1.1.1"))
.setOriginatorIp(Ip.parse("1.1.1.1"))
.setOriginType(OriginType.INCOMPLETE)
.setProtocol(RoutingProtocol.BGP)
.setSrcProtocol(RoutingProtocol.BGP)
.setAsPath(AsPath.ofSingletonAsSets(1L))
.setAdmin(20)
.setLocalPreference(100)
.build())));
}
}