eqixiacEquinix Infrastructure as Code

Peering Intelligence and latency

Presence of networks at Equinix exchanges and facilities from PeeringDB, peering lost with a metro, and fibre latency floors.

Purpose#

Peering Intelligence cross-references PeeringDB with the Equinix exchanges and facilities for a list of ASNs. It reports the Equinix metros in which each network is present, the exchanges at which you and a target network can peer, and the peering that is lost if a metro fails.

Data and credentials#

SourceDataAccess
PeeringDBNetworks, exchange memberships (netixlan), facility presence (netfac), organizationsAnonymous at about 20 requests per minute, or with an API key
FabricMetro codes, service profilesThe Fabric client

The PeeringDB key is separate from the Equinix credentials and is resolved in this order: the argument of peeringIntelligence("key"), then EquinixConfig.peeringDbApiKey, then the PEERINGDB_API_KEY environment variable, then anonymous access.

Two defects, both fixed in 4.0, caused 3.0.0 to return no presence for any network. PeeringDB ignores an asn filter on netfac and returns unrelated rows, so the client now resolves each ASN to its network id and filters on that. The live Fabric metros response has no IBX list, so Equinix facility names are now matched to metros through the live metro codes. Unit tests built from live response shapes cover the fixes. The end-to-end run was not repeated live on 2026-11-11, because PeeringDB throttled anonymous calls.

Presence#

Java
import com.eqixiac.equinix.core.enums.MetroCode;
import com.eqixiac.equinix.core.model.MetroId;
import com.eqixiac.equinix.design.peering.model.MetroPresenceReport;
import com.eqixiac.equinix.design.peering.model.NetworkPresence;
import com.eqixiac.equinix.design.peering.model.PeeringIntelligenceResult;

PeeringIntelligenceResult presence = fabric.peeringIntelligence()
    .addAsn(16509, "AWS")
    .addAsn(8075, "Microsoft")
    .addAsn(15169, "Google")
    .addAsn(13335, "Cloudflare")
    .analyze();

System.out.println(presence.getPresenceMatrix().toTableString());           // rows: networks, columns: metros
System.out.println(presence.getPresenceMatrix().toDetailedTableString());   // with port capacity and route-server use

List<MetroId> allThree = presence.getPresenceMatrix().metrosWithAllAsns(List.of(16509L, 8075L, 15169L));

MetroPresenceReport ashburn = presence.metroReport(MetroId.of(MetroCode.DC));
System.out.println(ashburn.withIxPeering().size() + " target networks peer at the exchange in DC, "
    + ashburn.totalIxCapacityMbps() / 1000 + " Gbps of port capacity");

NetworkPresence aws = presence.networkPresence(16509);
System.out.println(aws.getPeeringPolicy() + ", " + aws.ixMetroCount() + " metros, route servers: "
    + aws.isRouteServerParticipant());

The port capacity in the report is the figure that each network declares in PeeringDB, which says nothing about the traffic on the port.

Peering opportunities#

When the request includes your own ASN, the result lists the Equinix exchanges at which both you and a target network are present.

Java
import com.eqixiac.equinix.design.peering.model.PeeringOpportunity;

PeeringIntelligenceResult mutual = fabric.peeringIntelligence()
    .addAsn(16509, "AWS")
    .addAsn(13335, "Cloudflare")
    .customerAsn(65100L)
    .analyze();

for (PeeringOpportunity opportunity : mutual.getPeeringOpportunities()) {
    System.out.println(opportunity.getTargetLabel() + " at " + opportunity.getMetro()
        + " (" + opportunity.getIxName() + "): " + opportunity.getComplexity()
        + ", feasibility " + (int) (opportunity.getFeasibility() * 100) + "%");
}

Complexity and feasibility are derived from the target's stated peering policy and route-server participation. A target with an open policy that uses the route servers can be reached without a bilateral session. A target with a selective or restrictive policy has to agree to a peering request. The feasibility figure ranks the opportunities and is not an estimate of the probability that a request succeeds.

Resiliency#

Java
import com.eqixiac.equinix.design.peering.model.BlastRadiusReport;
import com.eqixiac.equinix.design.peering.model.FailoverPath;

PeeringIntelligenceResult resilience = fabric.peeringIntelligence()
    .addAsn(16509, "AWS")
    .addAsn(8075, "Microsoft")
    .addAsn(13335, "Cloudflare")
    .customerMetros(MetroCode.DC, MetroCode.DA, MetroCode.SG)
    .includeResiliency(true)
    .analyze();

BlastRadiusReport dc = resilience.getResiliency().blastRadiusFor(MetroId.of(MetroCode.DC));
System.out.println("Losing DC removes " + (int) (dc.getImpactRatio() * 100) + "% of the peering reach: "
    + dc.getLostIxPeeringLabels() + ", severity " + dc.getSeverity());

for (FailoverPath path : resilience.getResiliency().failoverPathsForAsn(16509)) {
    System.out.println(path.getFailoverMetro() + " " + path.getIxCapacityMbps() / 1000 + " Gbps, diversity "
        + path.getDiversity().getRating() + ": " + path.getRecommendation());
}

resilience.getResiliency().criticalCorrelations().forEach(c ->
    System.out.println(c.getSeverity() + " " + c.getFailureDomain() + ": " + c.getRecommendation()));

Files.writeString(Path.of("peering-report.md"), resilience.toMarkdown());

The blast radius is the share of the target networks' reach that depends on one metro, given the metros you are in. A correlated failure is a set of paths that use different metros and share a failure domain. The analysis uses presence data and has no data on physical routes, so two metros that it reports as diverse can share a fibre path that PeeringDB does not describe.

Latency estimates#

SpeedOfLightLatency computes the delay of light in fibre over the great-circle distance between two locations: about 4.9 microseconds per km one way, with a refractive index of 1.467.

EndpointsCoordinate sourcePrecision
IBX to IBXInternet Access ibxs(), or the enriched metro registryPer data center; a same-metro pair gets a real, non-zero figure
Metro to metroFabric metros()Metro centroid
IBX to metroBothMixed
Raw coordinates or kilometresNoneOffline
Java
import com.eqixiac.equinix.design.geo.SpeedOfLightLatency;
import com.eqixiac.equinix.fabric.model.Metro;
import com.eqixiac.equinix.internetaccess.model.Ibx;

Ibx la4 = internet.ibxs().getByCode("LA4");
Ibx sv5 = internet.ibxs().getByCode("SV5");
Metro dcMetro = fabric.metros().getByMetroCode(MetroCode.DC);
Metro svMetro = fabric.metros().getByMetroCode(MetroCode.SV);

SpeedOfLightLatency roundTrip = SpeedOfLightLatency.roundTrip();
double ibxToIbx = roundTrip.millisBetween(la4, sv5);
double metroToMetro = roundTrip.millisBetween(dcMetro, svMetro);
double km = SpeedOfLightLatency.distanceKm(la4, sv5);

SpeedOfLightLatency routed = SpeedOfLightLatency.builder()
    .mode(SpeedOfLightLatency.Mode.ONE_WAY)
    .routeFactor(1.4)                 // 1.0 is the physical floor; real terrestrial routes are longer
    .refractiveIndex(1.467)
    .build();
double oneWay = routed.millisBetween(la4, sv5);

The result is a lower bound that excludes switching, queuing and the extra length of real fibre routes. The measured counterpart is the round-trip avgLatency in metro.getConnectedMetros(). On 2026-11-11 Fabric reported 65.8 ms round trip between SV and DC against a physical floor of 37.6 ms, a ratio of 1.75. The Metro Optimizer fits this ratio from all measured pairs to estimate the unmeasured ones.

For a location without coordinates the calculator throws IllegalArgumentException with the name of the location.