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

Cisco IOS: convert VRF leaking config to VI model #6556

Merged
merged 3 commits into from
Jan 11, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
Expand Up @@ -15,6 +15,7 @@
import static org.batfish.datamodel.routing_policy.Common.suppressSummarizedPrefixes;
import static org.batfish.representation.cisco.CiscoConversions.computeDistributeListPolicies;
import static org.batfish.representation.cisco.CiscoConversions.convertCryptoMapSet;
import static org.batfish.representation.cisco.CiscoConversions.convertVrfLeakingConfig;
import static org.batfish.representation.cisco.CiscoConversions.generateBgpExportPolicy;
import static org.batfish.representation.cisco.CiscoConversions.generateBgpImportPolicy;
import static org.batfish.representation.cisco.CiscoConversions.generateEigrpPolicy;
Expand Down Expand Up @@ -54,6 +55,7 @@
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
Expand Down Expand Up @@ -1210,6 +1212,16 @@ private org.batfish.datamodel.BgpProcess toBgpProcess(
new BgpConfederation(confederation, proc.getConfederationMembers()));
}

/**
* Create BGP redistribution policy. This should only capture network statements and
* redistribute commands (at this time)
*/
RoutingPolicy.Builder redistributionPolicyBuilder =
RoutingPolicy.builder()
.setOwner(c)
.setName(String.format("~BGP_REDISTRIBUTION~%s~", vrfName));
List<BooleanExpr> redistributeConditions = new LinkedList<>();

/*
* Create common bgp export policy. This policy encompasses network
* statements, aggregate-address with/without summary-only, redistribution
Expand All @@ -1218,6 +1230,7 @@ private org.batfish.datamodel.BgpProcess toBgpProcess(
RoutingPolicy bgpCommonExportPolicy =
new RoutingPolicy(Names.generatedBgpCommonExportPolicyName(vrfName), c);
c.getRoutingPolicies().put(bgpCommonExportPolicy.getName(), bgpCommonExportPolicy);

List<Statement> bgpCommonExportStatements = bgpCommonExportPolicy.getStatements();

// Never export routes suppressed because they are more specific than summary-only aggregate
Expand Down Expand Up @@ -1325,6 +1338,7 @@ private org.batfish.datamodel.BgpProcess toBgpProcess(
BooleanExpr we = bgpRedistributeWithEnvironmentExpr(weInterior, OriginType.INCOMPLETE);
exportRipConditions.getConjuncts().add(we);
exportConditions.add(exportRipConditions);
redistributeConditions.add(exportRipConditions);
}

// Export static routes that should be redistributed.
Expand All @@ -1345,6 +1359,7 @@ private org.batfish.datamodel.BgpProcess toBgpProcess(
BooleanExpr we = bgpRedistributeWithEnvironmentExpr(weInterior, OriginType.INCOMPLETE);
exportStaticConditions.getConjuncts().add(we);
exportConditions.add(exportStaticConditions);
redistributeConditions.add(exportStaticConditions);
}

// Export connected routes that should be redistributed.
Expand All @@ -1365,6 +1380,7 @@ private org.batfish.datamodel.BgpProcess toBgpProcess(
BooleanExpr we = bgpRedistributeWithEnvironmentExpr(weInterior, OriginType.INCOMPLETE);
exportConnectedConditions.getConjuncts().add(we);
exportConditions.add(exportConnectedConditions);
redistributeConditions.add(exportConnectedConditions);
}

// Export OSPF routes that should be redistributed.
Expand Down Expand Up @@ -1395,6 +1411,7 @@ private org.batfish.datamodel.BgpProcess toBgpProcess(
BooleanExpr we = bgpRedistributeWithEnvironmentExpr(weInterior, OriginType.INCOMPLETE);
exportOspfConditions.getConjuncts().add(we);
exportConditions.add(exportOspfConditions);
redistributeConditions.add(exportOspfConditions);
}

// Export EIGRP routes that should be redistributed.
Expand All @@ -1417,6 +1434,7 @@ private org.batfish.datamodel.BgpProcess toBgpProcess(
Conjunction eigrp = new Conjunction(exportEigrpConditions.build());
eigrp.setComment("Redistribute EIGRP routes into BGP");
exportConditions.add(eigrp);
redistributeConditions.add(eigrp);
}

// cause ip peer groups to inherit unset fields from owning named peer
Expand Down Expand Up @@ -1462,6 +1480,7 @@ private org.batfish.datamodel.BgpProcess toBgpProcess(
RoutingProtocol.AGGREGATE)));
exportNetworkConditions.getConjuncts().add(we);
exportConditions.add(exportNetworkConditions);
redistributeConditions.add(exportNetworkConditions);
});
if (!proc.getIpv6Networks().isEmpty()) {
String localFilter6Name = "~BGP_NETWORK6_NETWORKS_FILTER:" + vrfName + "~";
Expand Down Expand Up @@ -1503,6 +1522,18 @@ private org.batfish.datamodel.BgpProcess toBgpProcess(
c.getRoute6FilterLists().put(localFilter6Name, localFilter6);
}

// Finalize redistribution policy and attach to process
newBgpProcess.setRedistributionPolicy(
redistributionPolicyBuilder
.addStatement(
new If(
"Redistribute routes into BGP",
new Disjunction(redistributeConditions),
ImmutableList.of(Statements.ExitAccept.toStaticStatement()),
ImmutableList.of(Statements.ExitReject.toStaticStatement())))
.build()
.getName());

// Export BGP and IBGP routes.
exportConditions.add(new MatchProtocol(RoutingProtocol.BGP, RoutingProtocol.IBGP));

Expand Down Expand Up @@ -2949,6 +2980,13 @@ public List<Configuration> toVendorIndependentConfigurations() {
// initialize vrfs
for (String vrfName : _vrfs.keySet()) {
c.getVrfs().put(vrfName, new org.batfish.datamodel.Vrf(vrfName));
// inherit address family props
Vrf vrf = _vrfs.get(vrfName);
VrfAddressFamily ip4uaf = vrf.getIpv4UnicastAddressFamily();
if (ip4uaf == null) {
continue;
}
ip4uaf.inherit(vrf.getGenericAddressFamilyConfig());
}

// snmp server
Expand Down Expand Up @@ -3442,6 +3480,8 @@ public List<Configuration> toVendorIndependentConfigurations() {
}
});

convertVrfLeakingConfig(_vrfs.values(), c);

// Define the Null0 interface if it has been referenced. Otherwise, these show as undefined
// references.
Optional<Integer> firstRefToNull0 =
Expand Down
Expand Up @@ -18,10 +18,12 @@
import static org.batfish.representation.cisco.CiscoConfiguration.computeServiceObjectGroupAclName;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Multimap;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
Expand Down Expand Up @@ -83,9 +85,11 @@
import org.batfish.datamodel.RoutingProtocol;
import org.batfish.datamodel.SubRange;
import org.batfish.datamodel.TcpFlagsMatchConditions;
import org.batfish.datamodel.VrfLeakingConfig;
import org.batfish.datamodel.acl.AclLineMatchExpr;
import org.batfish.datamodel.acl.AndMatchExpr;
import org.batfish.datamodel.acl.MatchHeaderSpace;
import org.batfish.datamodel.bgp.community.ExtendedCommunity;
import org.batfish.datamodel.bgp.community.StandardCommunity;
import org.batfish.datamodel.eigrp.EigrpMetric;
import org.batfish.datamodel.eigrp.EigrpMetricValues;
Expand Down Expand Up @@ -1710,5 +1714,48 @@ static org.batfish.datamodel.ospf.OspfNetworkType toOspfNetworkType(
}
}

/**
* Convert VRF leaking configs, if needed. Must be called after VRF address family inheritance is
* completed, and routing policies have been converted.
*
* @param c VI {@link Configuration}
*/
public static void convertVrfLeakingConfig(Collection<Vrf> vrfs, Configuration c) {
List<Vrf> vrfsWithIpv4Af =
vrfs.stream()
.filter(v -> v.getIpv4UnicastAddressFamily() != null)
.collect(Collectors.toList());
Multimap<ExtendedCommunity, String> vrfsByExportRt = HashMultimap.create();
// pre-compute RT to VRF name mapping
for (Vrf vrf : vrfsWithIpv4Af) {
assert vrf.getIpv4UnicastAddressFamily() != null;
vrf.getIpv4UnicastAddressFamily()
.getRouteTargetExport()
.forEach(rt -> vrfsByExportRt.put(rt, vrf.getName()));
}

// Create VRF leaking configs for each importing VRF that has import RTs defined.
for (Vrf importingVrf : vrfsWithIpv4Af) {
VrfAddressFamily ipv4uaf = importingVrf.getIpv4UnicastAddressFamily();
assert ipv4uaf != null;
for (ExtendedCommunity importRt : ipv4uaf.getRouteTargetImport()) {
org.batfish.datamodel.Vrf viVrf = c.getVrfs().get(importingVrf.getName());
assert viVrf != null;
for (String exportingVrf : vrfsByExportRt.get(importRt)) {
// Take care to prevent self-loops
if (importingVrf.getName().equals(exportingVrf)) {
continue;
}
viVrf.addVrfLeakingConfig(
VrfLeakingConfig.builder()
.setLeakAsBgp(true)
.setImportFromVrf(exportingVrf)
.setImportPolicy(routeMapOrRejectAll(ipv4uaf.getImportMap(), c))
.build());
}
}
}
}

private CiscoConversions() {} // prevent instantiation of utility class
}
Expand Up @@ -28,6 +28,7 @@
import static org.batfish.datamodel.matchers.AaaAuthenticationLoginMatchers.hasListForKey;
import static org.batfish.datamodel.matchers.AaaAuthenticationMatchers.hasLogin;
import static org.batfish.datamodel.matchers.AaaMatchers.hasAuthentication;
import static org.batfish.datamodel.matchers.AbstractRouteDecoratorMatchers.hasNextHop;
import static org.batfish.datamodel.matchers.AbstractRouteDecoratorMatchers.hasPrefix;
import static org.batfish.datamodel.matchers.AbstractRouteDecoratorMatchers.hasProtocol;
import static org.batfish.datamodel.matchers.AbstractRouteDecoratorMatchers.hasTag;
Expand Down Expand Up @@ -350,6 +351,7 @@
import org.batfish.datamodel.TunnelConfiguration;
import org.batfish.datamodel.TunnelConfiguration.Builder;
import org.batfish.datamodel.Vrf;
import org.batfish.datamodel.VrfLeakingConfig;
import org.batfish.datamodel.acl.AclLineMatchExpr;
import org.batfish.datamodel.acl.AclTracer;
import org.batfish.datamodel.acl.MatchHeaderSpace;
Expand Down Expand Up @@ -389,6 +391,7 @@
import org.batfish.datamodel.ospf.StubType;
import org.batfish.datamodel.route.nh.NextHopDiscard;
import org.batfish.datamodel.route.nh.NextHopIp;
import org.batfish.datamodel.route.nh.NextHopVrf;
import org.batfish.datamodel.routing_policy.Environment.Direction;
import org.batfish.datamodel.routing_policy.RoutingPolicy;
import org.batfish.datamodel.routing_policy.expr.Conjunction;
Expand Down Expand Up @@ -7181,4 +7184,41 @@ public void testIosServicePolicyInner() throws IOException {
batfish.loadConvertConfigurationAnswerElementOrReparse(batfish.getSnapshot());
assertThat(ccae, hasNumReferrers(filename, POLICY_MAP, "PM", 2));
}

@Test
public void testIosVrfLeakingConversion() throws IOException {
String hostname = "ios-vrf-leaking";
Configuration c = parseConfig(hostname);
VrfLeakingConfig.Builder builder = VrfLeakingConfig.builder().setLeakAsBgp(true);
assertThat(
c.getVrfs().get("DST_VRF").getVrfLeakConfigs(),
contains(builder.setImportFromVrf("SRC_VRF").setImportPolicy("IMPORT_MAP").build()));
assertThat(
c.getVrfs().get("DST_IMPOSSIBLE").getVrfLeakConfigs(),
contains(
builder.setImportFromVrf("SRC_VRF").setImportPolicy("UNDEFINED~undefined").build()));
}

@Test
public void testIosVrfLeakingRoutes() throws IOException {
String hostname = "ios-vrf-leaking";

Batfish batfish = getBatfishForConfigurationNames(hostname);

NetworkSnapshot snapshot = batfish.getSnapshot();
batfish.computeDataPlane(snapshot);
DataPlane dp = batfish.loadDataPlane(snapshot);
SortedMap<String, GenericRib<AnnotatedRoute<AbstractRoute>>> ribs = dp.getRibs().get(hostname);
Set<AbstractRoute> dstVrfRoutes = ribs.get("DST_VRF").getRoutes();
assertThat(
dstVrfRoutes,
// 1.1.1.1/32 is denied by import map, only 2.2.2.0/24 is expected to be leaked.
contains(
isBgpv4RouteThat(
allOf(
hasPrefix(Prefix.parse("2.2.2.0/24")),
hasProtocol(RoutingProtocol.BGP),
hasNextHop(NextHopVrf.of("SRC_VRF"))))));
assertThat(ribs.get("DST_IMPOSSIBLE").getRoutes(), empty());
}
}
@@ -0,0 +1,49 @@
!RANCID-CONTENT-TYPE: cisco
version 15.2
!
hostname ios-vrf-leaking
!
vrf definition SRC_VRF
rd 65003:1
!
address-family ipv4
route-target export 65003:11
exit-address-family
!
ip route vrf SRC_VRF 1.1.1.1 255.255.255.255 Null0
ip route vrf SRC_VRF 2.2.2.0 255.255.255.0 Null0
!
vrf definition DST_VRF
rd 65003:2
!
address-family ipv4
import map IMPORT_MAP
route-target export 65003:22
route-target import 65003:11
exit-address-family
!
vrf definition DST_IMPOSSIBLE
rd 65003:2
!
address-family ipv4
import map UNDEFINED
route-target import 65003:11
exit-address-family
!
router bgp 65003
bgp router-id 192.168.123.3
!
address-family ipv4 vrf SRC_VRF
bgp router-id 192.168.123.31
redistribute static
exit-address-family
!
address-family ipv4 vrf DST_VRF
bgp router-id 192.168.123.32
exit-address-family
!
!
ip prefix-list import_pl seq 5 permit 2.2.2.0/24
!
route-map IMPORT_MAP permit 10
match ip address prefix-list import_pl