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: convert ospf area range #6665

Merged
merged 2 commits into from Mar 1, 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 @@ -845,10 +845,7 @@ public void exitSiip_address(Siip_addressContext ctx) {

@Override
public void enterS_router_ospf(S_router_ospfContext ctx) {
if (_frr.getOspfProcess() == null) {
_frr.setOspfProcess(new OspfProcess());
}
_currentOspfVrf = _frr.getOspfProcess().getDefaultVrf();
_currentOspfVrf = _frr.getOrCreateOspfProcess().getDefaultVrf();
}

@Override
Expand Down
Expand Up @@ -5,7 +5,6 @@
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.mapping;
import static org.batfish.common.util.CollectionUtil.toImmutableSortedMap;
import static org.batfish.datamodel.Configuration.DEFAULT_VRF_NAME;
import static org.batfish.datamodel.MultipathEquivalentAsPathMatchMode.EXACT_PATH;
import static org.batfish.datamodel.MultipathEquivalentAsPathMatchMode.PATH_LENGTH;
Expand All @@ -24,6 +23,7 @@
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.ImmutableSortedSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
Expand Down Expand Up @@ -82,6 +82,7 @@
import org.batfish.datamodel.bgp.community.Community;
import org.batfish.datamodel.bgp.community.ExtendedCommunity;
import org.batfish.datamodel.ospf.OspfArea;
import org.batfish.datamodel.ospf.OspfAreaSummary;
import org.batfish.datamodel.ospf.OspfInterfaceSettings;
import org.batfish.datamodel.ospf.OspfMetricType;
import org.batfish.datamodel.routing_policy.Common;
Expand Down Expand Up @@ -202,6 +203,10 @@ public static String computeOspfExportPolicyName(String vrfName) {
return String.format("~OSPF_EXPORT_POLICY:%s~", vrfName);
}

public static String computeOspfAreaRangeFilterName(String vrfName, long area) {
return String.format("~OSPF_AREA_RANGE:%s:%s~", vrfName, area);
}

/**
* Infers the peer Ip for the interface. This is doable only if the interface has exactly one
* (primary) address that is a /30 or /31. For a /30, the address must NOT be the first or last
Expand Down Expand Up @@ -1282,7 +1287,7 @@ static org.batfish.datamodel.ospf.OspfProcess toOspfProcess(
}

addOspfInterfaces(vsConfig, vrfInterfaces, proc.getProcessId(), w);
proc.setAreas(computeOspfAreas(vsConfig, vrfInterfaces.keySet()));
proc.setAreas(computeOspfAreas(c, vsConfig, ospfVrf, vrfInterfaces.keySet()));

// Handle Max Metric Router LSA
if (firstNonNull(vsConfig.getOspfProcess().getMaxMetricRouterLsa(), Boolean.FALSE)) {
Expand Down Expand Up @@ -1425,7 +1430,10 @@ static void addOspfInterfaces(

@VisibleForTesting
static SortedMap<Long, OspfArea> computeOspfAreas(
CumulusConcatenatedConfiguration vsConfig, Collection<String> vrfIfaceNames) {
Configuration c,
CumulusConcatenatedConfiguration vsConfig,
OspfVrf ospfVrf,
Collection<String> vrfIfaceNames) {
Map<Long, List<String>> areaInterfaces =
vrfIfaceNames.stream()
.filter(
Expand All @@ -1438,10 +1446,60 @@ static SortedMap<Long, OspfArea> computeOspfAreas(
iface -> vsConfig.getOspfInterface(iface).get().getOspfArea(),
mapping(Function.identity(), Collectors.toList())));

return toImmutableSortedMap(
areaInterfaces,
Entry::getKey,
e -> OspfArea.builder().setNumber(e.getKey()).addInterfaces(e.getValue()).build());
// Ensure that the VRF-level OSPF config has each area used.
areaInterfaces.keySet().forEach(ospfVrf::getOrCreateArea);

// Now convert each area
ImmutableSortedMap.Builder<Long, OspfArea> areas = ImmutableSortedMap.naturalOrder();
ospfVrf
.getAreas()
.values()
.forEach(
vrfArea -> {
long num = vrfArea.getArea();
List<String> interfaces = areaInterfaces.get(num);
if (interfaces.isEmpty()) {
// No interfaces, skip area.
return;
}
OspfArea area = convertArea(c, ospfVrf.getVrfName(), vrfArea, interfaces);
areas.put(area.getAreaNumber(), area);
});
return areas.build();
}

private static @Nonnull OspfArea convertArea(
Configuration c,
String vrfName,
org.batfish.representation.cumulus.OspfArea vsArea,
Collection<String> interfaces) {
OspfArea.Builder ret = OspfArea.builder().setNumber(vsArea.getArea()).addInterfaces(interfaces);

// Handle OSPF Area Range conversion into VI OspfAreaSummary. It has two steps:
// 1. convert OspfAreaRange to OspfAreaSummary
// 2. add a RouteFilterList to force summarization and block more specific routes.
if (!vsArea.getRanges().isEmpty()) {
ImmutableList.Builder<RouteFilterLine> lines =
ImmutableList.builderWithExpectedSize(vsArea.getRanges().size() + 1);
for (OspfAreaRange range : vsArea.getRanges().values()) {
// OSPF costs are only 16-bit, but the VI metric is a long, for other protocols that support
// that. Upconvert if not null.
Prefix prefix = range.getRange();
Long cost = range.getCost() == null ? null : range.getCost().longValue();
OspfAreaSummary summary = new OspfAreaSummary(true, cost);
ret.addSummary(prefix, summary);
lines.add(new RouteFilterLine(LineAction.DENY, PrefixRange.moreSpecificThan(prefix)));
}
// Anything not summarized is permitted.
lines.add(new RouteFilterLine(LineAction.PERMIT, PrefixRange.ALL));
RouteFilterList summaryFilter =
new RouteFilterList(
computeOspfAreaRangeFilterName(vrfName, vsArea.getArea()), lines.build());
c.getRouteFilterLists().put(summaryFilter.getName(), summaryFilter);
ret.setSummaryFilter(summaryFilter.getName());
}

return ret.build();
}

@Nullable
Expand Down
Expand Up @@ -64,6 +64,13 @@ public void setBgpProcess(@Nullable BgpProcess bgpProcess) {
_bgpProcess = bgpProcess;
}

public @Nonnull OspfProcess getOrCreateOspfProcess() {
if (_ospfProcess == null) {
_ospfProcess = new OspfProcess();
}
return _ospfProcess;
}

@Nullable
public OspfProcess getOspfProcess() {
return _ospfProcess;
Expand Down
@@ -1,6 +1,7 @@
package org.batfish.representation.cumulus;

import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nonnull;
Expand All @@ -27,6 +28,10 @@ public OspfVrf(String name) {
return _areas.get(area);
}

public @Nonnull Map<Long, OspfArea> getAreas() {
return Collections.unmodifiableMap(_areas);
}

@Nullable
public Ip getRouterId() {
return _routerId;
Expand Down
Expand Up @@ -8,6 +8,7 @@
import static org.batfish.datamodel.matchers.MapMatchers.hasKeys;
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.CumulusConversions.computeOspfAreaRangeFilterName;
import static org.batfish.representation.cumulus.CumulusRoutingProtocol.CONNECTED;
import static org.batfish.representation.cumulus.CumulusRoutingProtocol.OSPF;
import static org.batfish.representation.cumulus.CumulusRoutingProtocol.STATIC;
Expand All @@ -21,6 +22,7 @@
import static org.batfish.representation.cumulus.CumulusStructureUsage.ROUTE_MAP_MATCH_COMMUNITY_LIST;
import static org.hamcrest.Matchers.aMapWithSize;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.anEmptyMap;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
Expand Down Expand Up @@ -76,11 +78,14 @@
import org.batfish.datamodel.OriginType;
import org.batfish.datamodel.OspfExternalType2Route;
import org.batfish.datamodel.Prefix;
import org.batfish.datamodel.RouteFilterList;
import org.batfish.datamodel.RoutingProtocol;
import org.batfish.datamodel.StaticRoute.Builder;
import org.batfish.datamodel.SubRange;
import org.batfish.datamodel.answers.ConvertConfigurationAnswerElement;
import org.batfish.datamodel.bgp.community.StandardCommunity;
import org.batfish.datamodel.ospf.OspfAreaSummary;
import org.batfish.datamodel.ospf.OspfProcess;
import org.batfish.datamodel.routing_policy.RoutingPolicy;
import org.batfish.datamodel.routing_policy.expr.LiteralLong;
import org.batfish.grammar.BatfishParseTreeWalker;
Expand Down Expand Up @@ -1883,6 +1888,48 @@ public void testRouterOspfAreaRange() {
assertThat(area5.getRange(prefix).getCost(), nullValue());
}

@Test
public void testRouterOspfAreaRangeConversion() {
parse(
"interface swp1\n"
+ " ip address 1.2.3.4/5\n"
+ " ip ospf area 1.1.1.0\n"
+ "\n"
+ "interface swp2\n"
+ " ip address 2.3.4.5/6\n"
+ " ip ospf area 5\n"
+ "\n"
+ "router ospf\n"
+ " area 1.1.1.0 range 1.255.0.0/17 cost 10\n");
long area1110 = Ip.parse("1.1.1.0").asLong();
Configuration c = _config.toVendorIndependentConfigurations().get(0);
assertThat(c.getDefaultVrf().getOspfProcesses(), aMapWithSize(1));
OspfProcess proc = Iterables.getOnlyElement(c.getDefaultVrf().getOspfProcesses().values());
assertThat(proc.getAreas(), hasKeys(5L, area1110));
{
org.batfish.datamodel.ospf.OspfArea area = proc.getAreas().get(5L);
assertThat(area.getSummaries(), anEmptyMap());
assertThat(area.getSummaryFilter(), nullValue());
}
{
org.batfish.datamodel.ospf.OspfArea area = proc.getAreas().get(area1110);
assertThat(area.getSummaries(), hasKeys(Prefix.parse("1.255.0.0/17")));
OspfAreaSummary summary = Iterables.getOnlyElement(area.getSummaries().values());
assertThat(summary.getAdvertised(), equalTo(true));
assertThat(summary.getMetric(), equalTo(10L));
String name = computeOspfAreaRangeFilterName(c.getDefaultVrf().getName(), area1110);
assertThat(area.getSummaryFilter(), equalTo(name));
assertThat(c.getRouteFilterLists(), hasKey(name));
RouteFilterList filter = c.getRouteFilterLists().get(name);
assertTrue(filter.permits(Prefix.parse("1.255.0.0/17"))); // prefix itself should be permitted
assertFalse(
filter.permits(
Prefix.parse("1.255.64.0/18"))); // more specific, even with diff prefix, denied
assertTrue(filter.permits(Prefix.parse("10.0.0.0/18"))); // more specific, not overlapping
assertTrue(filter.permits(Prefix.parse("1.255.0.0/16"))); // less specific
}
}

@Test
public void testRouterOspfNetwork() {
parse(
Expand Down
Expand Up @@ -1766,9 +1766,12 @@ public void testComputeOspfProcess_HasArea() {
.getOrCreateInterface("iface")
.getOrCreateOspf()
.setOspfArea(1L);
OspfVrf vsVrf =
concatenatedConfiguration.getFrrConfiguration().getOrCreateOspfProcess().getDefaultVrf();
Configuration c = new Configuration("c", ConfigurationFormat.CUMULUS_CONCATENATED);

SortedMap<Long, OspfArea> areas =
computeOspfAreas(concatenatedConfiguration, ImmutableList.of("iface"));
computeOspfAreas(c, concatenatedConfiguration, vsVrf, ImmutableList.of("iface"));
assertThat(
areas,
equalTo(
Expand All @@ -1781,19 +1784,25 @@ public void testComputeOspfProcess_NoArea() {
CumulusConcatenatedConfiguration concatenatedConfiguration =
new CumulusConcatenatedConfiguration();
concatenatedConfiguration.getFrrConfiguration().getOrCreateInterface("iface").getOrCreateOspf();
OspfVrf vsVrf =
concatenatedConfiguration.getFrrConfiguration().getOrCreateOspfProcess().getDefaultVrf();
Configuration c = new Configuration("c", ConfigurationFormat.CUMULUS_CONCATENATED);

SortedMap<Long, OspfArea> areas =
computeOspfAreas(concatenatedConfiguration, ImmutableList.of("iface"));
computeOspfAreas(c, concatenatedConfiguration, vsVrf, ImmutableList.of("iface"));
assertThat(areas, equalTo(ImmutableSortedMap.of()));
}

@Test
public void testComputeOspfProcess_NoInterface() {
CumulusConcatenatedConfiguration concatenatedConfiguration =
new CumulusConcatenatedConfiguration();
OspfVrf vsVrf =
concatenatedConfiguration.getFrrConfiguration().getOrCreateOspfProcess().getDefaultVrf();
Configuration c = new Configuration("c", ConfigurationFormat.CUMULUS_CONCATENATED);

SortedMap<Long, OspfArea> areas =
computeOspfAreas(concatenatedConfiguration, ImmutableList.of("iface"));
computeOspfAreas(c, concatenatedConfiguration, vsVrf, ImmutableList.of("iface"));
assertThat(areas, equalTo(ImmutableSortedMap.of()));
}

Expand Down