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

EIGRP: add metric version and plumb throughout #6532

Merged
merged 5 commits into from
Dec 30, 2020
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.hash;
import static java.util.Objects.requireNonNull;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
Expand All @@ -11,6 +10,7 @@
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.batfish.datamodel.eigrp.EigrpMetric;
import org.batfish.datamodel.eigrp.EigrpMetricVersion;

/** Represents an external EIGRP route */
public class EigrpExternalRoute extends EigrpRoute {
Expand All @@ -28,11 +28,21 @@ private EigrpExternalRoute(
long destinationAsn,
@Nullable Ip nextHopIp,
@Nonnull EigrpMetric metric,
@Nonnull EigrpMetricVersion metricVersion,
long processAsn,
long tag,
boolean nonForwarding,
boolean nonRouting) {
super(admin, network, nextHopIp, metric, processAsn, tag, nonForwarding, nonRouting);
super(
admin,
network,
nextHopIp,
metric,
metricVersion,
processAsn,
tag,
nonForwarding,
nonRouting);
_destinationAsn = destinationAsn;
}

Expand All @@ -43,15 +53,26 @@ private static EigrpExternalRoute create(
@Nullable @JsonProperty(PROP_NETWORK) Prefix network,
@Nullable @JsonProperty(PROP_NEXT_HOP_IP) Ip nextHopIp,
@Nullable @JsonProperty(PROP_EIGRP_METRIC) EigrpMetric metric,
@Nullable @JsonProperty(PROP_EIGRP_METRIC_VERSION) EigrpMetricVersion metricVersion,
@Nullable @JsonProperty(PROP_PROCESS_ASN) Long processAsn,
@Nullable @JsonProperty(PROP_TAG) Long tag) {
checkArgument(admin != null, "EIGRP route: missing %s", PROP_ADMINISTRATIVE_COST);
checkArgument(destinationAsn != null, "EIGRP route: missing %s", PROP_DESTINATION_ASN);
checkArgument(metric != null, "EIGRP route: missing %s", PROP_EIGRP_METRIC);
checkArgument(metricVersion != null, "EIGRP route: missing %s", PROP_EIGRP_METRIC_VERSION);
checkArgument(processAsn != null, "EIGRP route: missing %s", PROP_PROCESS_ASN);
checkArgument(tag != null, "EIGRP route: missing %s", PROP_TAG);
return new EigrpExternalRoute(
network, admin, destinationAsn, nextHopIp, metric, processAsn, tag, false, false);
network,
admin,
destinationAsn,
nextHopIp,
metric,
metricVersion,
processAsn,
tag,
false,
false);
}

@JsonProperty(PROP_DESTINATION_ASN)
Expand Down Expand Up @@ -79,13 +100,16 @@ public EigrpExternalRoute build() {
checkArgument(getNetwork() != null, "EIGRP route: missing %s", PROP_NETWORK);
checkArgument(_destinationAsn != null, "EIGRP route: missing %s", PROP_DESTINATION_ASN);
checkArgument(_eigrpMetric != null, "EIGRP route: missing %s", PROP_EIGRP_METRIC);
checkArgument(
_eigrpMetricVersion != null, "EIGRP route: missing %s", PROP_EIGRP_METRIC_VERSION);
checkArgument(_processAsn != null, "EIGRP route: missing %s", PROP_PROCESS_ASN);
return new EigrpExternalRoute(
getNetwork(),
getAdmin(),
_destinationAsn,
getNextHopIp(),
requireNonNull(_eigrpMetric),
_eigrpMetric,
_eigrpMetricVersion,
_processAsn,
getTag(),
getNonForwarding(),
Expand Down Expand Up @@ -115,6 +139,7 @@ public Builder toBuilder() {
// EigrpExternalRoute properties
.setDestinationAsn(getDestinationAsn())
.setEigrpMetric(getEigrpMetric())
.setEigrpMetricVersion(getEigrpMetricVersion())
.setProcessAsn(getProcessAsn());
}

Expand All @@ -130,6 +155,7 @@ public boolean equals(Object obj) {
return _admin == rhs._admin
&& Objects.equals(_destinationAsn, rhs._destinationAsn)
&& _metric.equals(rhs._metric)
&& _metricVersion == rhs._metricVersion
&& _network.equals(rhs._network)
&& _nextHopIp.equals(rhs._nextHopIp)
&& _processAsn == rhs._processAsn
Expand All @@ -149,6 +175,7 @@ public final int hashCode() {
getNonRouting(),
_destinationAsn,
_metric,
_metricVersion,
_processAsn);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.batfish.datamodel.eigrp.EigrpMetric;
import org.batfish.datamodel.eigrp.EigrpMetricVersion;

/** Represents an internal EIGRP route */
public class EigrpInternalRoute extends EigrpRoute {
Expand All @@ -19,10 +20,20 @@ private EigrpInternalRoute(
@Nullable Prefix network,
@Nullable Ip nextHopIp,
@Nonnull EigrpMetric metric,
@Nonnull EigrpMetricVersion metricVersion,
long tag,
boolean nonForwarding,
boolean nonRouting) {
super(admin, network, nextHopIp, metric, processAsn, tag, nonForwarding, nonRouting);
super(
admin,
network,
nextHopIp,
metric,
metricVersion,
processAsn,
tag,
nonForwarding,
nonRouting);
}

@JsonCreator
Expand All @@ -32,12 +43,15 @@ private static EigrpInternalRoute create(
@Nullable @JsonProperty(PROP_NETWORK) Prefix network,
@Nullable @JsonProperty(PROP_NEXT_HOP_IP) Ip nextHopIp,
@Nullable @JsonProperty(PROP_EIGRP_METRIC) EigrpMetric metric,
@Nullable @JsonProperty(PROP_EIGRP_METRIC_VERSION) EigrpMetricVersion metricVersion,
@Nullable @JsonProperty(PROP_TAG) Long tag) {
checkArgument(admin != null, "EIGRP rooute: missing %s", PROP_ADMINISTRATIVE_COST);
checkArgument(admin != null, "EIGRP route: missing %s", PROP_ADMINISTRATIVE_COST);
checkArgument(metric != null, "EIGRP route: missing %s", PROP_EIGRP_METRIC);
checkArgument(metricVersion != null, "EIGRP route: missing %s", PROP_EIGRP_METRIC_VERSION);
checkArgument(processAsn != null, "EIGRP route: missing %s", PROP_PROCESS_ASN);
checkArgument(tag != null, "EIGRP route: missing %s", PROP_TAG);
return new EigrpInternalRoute(admin, processAsn, network, nextHopIp, metric, tag, false, false);
return new EigrpInternalRoute(
admin, processAsn, network, nextHopIp, metric, metricVersion, tag, false, false);
}

public static Builder builder() {
Expand All @@ -58,6 +72,8 @@ private Builder() {}
public EigrpInternalRoute build() {
checkArgument(getNetwork() != null, "EIGRP route: missing %s", PROP_NETWORK);
checkArgument(_eigrpMetric != null, "EIGRP route: missing %s", PROP_EIGRP_METRIC);
checkArgument(
_eigrpMetricVersion != null, "EIGRP route: missing %s", PROP_EIGRP_METRIC_VERSION);
checkArgument(_processAsn != null, "EIGRP route: missing %s", PROP_PROCESS_ASN);
checkArgument(
getMetric() == 0, "EIGRP route: cannot set metric directly, use setEigrpMetric instead");
Expand All @@ -67,6 +83,7 @@ public EigrpInternalRoute build() {
getNetwork(),
getNextHopIp(),
_eigrpMetric,
_eigrpMetricVersion,
getTag(),
getNonForwarding(),
getNonRouting());
Expand Down Expand Up @@ -94,6 +111,7 @@ public Builder toBuilder() {
.setNonRouting(getNonRouting())
// EigrpInternalRoute properties
.setEigrpMetric(getEigrpMetric())
.setEigrpMetricVersion(getEigrpMetricVersion())
.setProcessAsn(getProcessAsn());
}

Expand All @@ -113,6 +131,7 @@ public boolean equals(Object obj) {
&& _tag == rhs._tag
&& _processAsn == rhs._processAsn
&& _metric.equals(rhs._metric)
&& _metricVersion == rhs._metricVersion
&& getNonForwarding() == rhs.getNonForwarding()
&& getNonRouting() == rhs.getNonRouting();
}
Expand All @@ -126,6 +145,7 @@ public final int hashCode() {
_tag,
_processAsn,
_metric,
_metricVersion,
getNonForwarding(),
getNonRouting());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
package org.batfish.datamodel;

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

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.primitives.UnsignedLong;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.batfish.datamodel.eigrp.EigrpMetric;
import org.batfish.datamodel.eigrp.EigrpMetricVersion;

/** Represents an EIGRP route, internal or external */
public abstract class EigrpRoute extends AbstractRoute {

static final String PROP_EIGRP_METRIC = "eigrp-metric";
static final String PROP_EIGRP_METRIC_VERSION = "eigrp-metric-version";
static final String PROP_PROCESS_ASN = "process-asn";

protected final int _admin;
@Nonnull protected final EigrpMetric _metric;
@Nonnull protected final EigrpMetricVersion _metricVersion;
@Nonnull protected final Ip _nextHopIp;

/** AS number of the EIGRP process that installed this route in the RIB */
Expand All @@ -27,22 +29,23 @@ public abstract class EigrpRoute extends AbstractRoute {
int admin,
Prefix network,
@Nullable Ip nextHopIp,
@Nullable EigrpMetric metric,
@Nonnull EigrpMetric metric,
@Nonnull EigrpMetricVersion metricVersion,
long processAsn,
long tag,
boolean nonForwarding,
boolean nonRouting) {
super(network, admin, tag, nonRouting, nonForwarding);
checkArgument(metric != null, "Cannot create EIGRP route: missing %s", PROP_EIGRP_METRIC);
_admin = admin;
_metric = metric;
_metricVersion = metricVersion;
_nextHopIp = firstNonNull(nextHopIp, Route.UNSET_ROUTE_NEXT_HOP_IP);
_processAsn = processAsn;
}

@JsonIgnore
public final UnsignedLong getCompositeCost() {
return _metric.cost();
return _metric.cost(_metricVersion);
}

@JsonProperty(PROP_EIGRP_METRIC)
Expand All @@ -51,9 +54,15 @@ public final EigrpMetric getEigrpMetric() {
return _metric;
}

@JsonProperty(PROP_EIGRP_METRIC_VERSION)
@Nonnull
public final EigrpMetricVersion getEigrpMetricVersion() {
return _metricVersion;
}

@Override
public final Long getMetric() {
return _metric.ribMetric();
return _metric.ribMetric(_metricVersion);
}

@Nonnull
Expand Down Expand Up @@ -82,6 +91,7 @@ public abstract static class Builder<B extends Builder<B, R>, R extends EigrpRou
extends AbstractRouteBuilder<B, R> {
@Nullable protected Long _destinationAsn;
@Nullable protected EigrpMetric _eigrpMetric;
@Nullable protected EigrpMetricVersion _eigrpMetricVersion;
@Nullable protected Long _processAsn;

public B setDestinationAsn(@Nonnull Long destinationAsn) {
Expand All @@ -94,6 +104,11 @@ public B setEigrpMetric(@Nonnull EigrpMetric metric) {
return getThis();
}

public B setEigrpMetricVersion(@Nonnull EigrpMetricVersion version) {
_eigrpMetricVersion = version;
return getThis();
}

public B setProcessAsn(@Nullable Long processAsn) {
_processAsn = processAsn;
return getThis();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,18 @@ public short getK5() {
}

@Override
public UnsignedLong cost() {
public UnsignedLong cost(EigrpMetricVersion version) {
switch (version) {
case V1:
return costV1();
case V2:
return costV2();
default:
throw new IllegalArgumentException("Unsupported version " + version);
}
}

private UnsignedLong costV1() {
checkState(_values.getBandwidth() != null, "Cannot calculate cost before bandwidth is set");
long scaledBw = BANDWIDTH_FACTOR / _values.getBandwidth();
long metric =
Expand All @@ -93,9 +104,24 @@ public UnsignedLong cost() {
return UnsignedLong.valueOf(metric);
}

private UnsignedLong costV2() {
checkState(_values.getBandwidth() != null, "Cannot calculate cost before bandwidth is set");
long scaledBw = 256L * BANDWIDTH_FACTOR / _values.getBandwidth();
long metricBw = (_k1 * scaledBw) + (_k2 * scaledBw) / (256 - _values.getEffectiveBandwidth());
long metricDelay =
// Scale delay from picoseconds to 10s of microseconds
// Do that first, to avoid overflow
256L * _k3 * (_values.getDelay() / PICO_TO_TENS_OF_MS_FACTOR);
long metric = metricBw + metricDelay;
if (_k5 != 0) {
metric = metric * ((long) _k5 / ((long) _values.getReliability() + _k4));
}
return UnsignedLong.valueOf(metric);
}

@Override
public long ribMetric() {
return cost().longValue();
public long ribMetric(EigrpMetricVersion version) {
return cost(version).longValue();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
})
public interface EigrpMetric extends Serializable {

/** Return metric as a single value, used for route preference tie breaking. */
UnsignedLong cost();
/** Return the metric as a single value, used for route preference tie breaking. */
UnsignedLong cost(EigrpMetricVersion version);

/**
* Return metric as a single value, scaled as needed to fit into a 4-byte value. Used for route
* preference tie breaking.
* Return metric as a single value, scaled as needed to fit into a 4-byte value. Used as a metric
* expected to be seen in the main RIB.
*/
long ribMetric();
long ribMetric(EigrpMetricVersion version);

/**
* Check if this metric and {@code other} are compatible, i.e., have the same type and k values
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.batfish.datamodel.eigrp;

/**
* Identifies how to summarize an {@link EigrpMetric} as a single value.
*
* <p>Is implementation-dependent. E.g., IOS-XE uses V1 and NX-OS uses V2.
*/
public enum EigrpMetricVersion {
/** IOS-XE -like. */
V1,
/** NX-OS -like. Higher precision than IOS-XE. */
V2,
}