// SPDX-License-Identifier: GPL-2.0-only // Copyright (C) 2020 Michael Crute . All rights reserved. // // Use of this source code is governed by a license that can be found in the // LICENSE file. package six import ( "fmt" "strings" ) // Create a new SIXParticipant struct from a map of data that was parsed from // the participant CSV file. This assumes the column headers from that CSV file // so it will not work with the other data formats avaiable. // // This uses the CSV file because it's both the most rich source of data and // the easiest to parse. func NewSIXParticipantFromData(d map[string]string) *SIXParticipant { r := &SIXParticipant{ Organization: d["Organization"], URL: d["URL"], ASN: mustParseInt(d["ASN"]), Speed: mustParseInt(d["Speed"]), Switch: d["Switch"], Contact: d["Contact"], Comment: d["Comment"], IsConnected: parseYesNo(d["Conn?"]), IsVoter: parseYesNo(d["Voter?"]), Update: mustParseTime(d["Update"]), Options: strings.Split(d["Options"], " "), PeeringPolicy: d["Policy"], ROACount: mustParseInt(d["rpki:roa"]), PeeringDBPrefixCountv4: mustParseInt(d["pdb:v4"]), PeeringDBPrefixCountv6: mustParseInt(d["pdb:v6"]), Addresses: Addresses{ IPv4: parseIPNetFromCIDR(d["IPv4"]), IPv6: parseIPNetFromCIDR(d["IPv6"]), }, IRRv4: IRRData{ PrefixCount: mustParseInt(d["irr:p4"]), ASNCount: mustParseInt(d["irr:a4"]), ASSetCount: mustParseInt(d["irr:ap4"]), }, IRRv6: IRRData{ PrefixCount: mustParseInt(d["irr:p6"]), ASNCount: mustParseInt(d["irr:a6"]), ASSetCount: mustParseInt(d["irr:ap6"]), }, RouteServer2: getRSData(2, d), RouteServer3: getRSData(3, d), } // Not all participants use the MTU9k VLAN ja4 := parseIPNetFromCIDR(d["Jumbo IPv4"]) ja6 := parseIPNetFromCIDR(d["Jumbo IPv6"]) if ja4 != nil && ja6 != nil { r.JumboAddresses = &Addresses{IPv4: ja4, IPv6: ja6} } return r } func getRSData(server int, d map[string]string) *RouteServer { // Extract all the data and determine if it's all empty strings, if so then // the participant isn't using the route server. If any data is not empty // then they are. Do integer conversion afterward to avoid ambiguity about // zero vs empty string. pd := []string{ d[fmt.Sprintf("rs%d:v4", server)], d[fmt.Sprintf("err%d:v4", server)], d[fmt.Sprintf("xerr%d:v4", server)], d[fmt.Sprintf("rs%d:v6", server)], d[fmt.Sprintf("err%d:v6", server)], d[fmt.Sprintf("xerr%d:v6", server)], d[fmt.Sprintf("rs%d:v4j", server)], d[fmt.Sprintf("err%d:v4j", server)], d[fmt.Sprintf("xerr%d:v4j", server)], d[fmt.Sprintf("rs%d:v6j", server)], d[fmt.Sprintf("err%d:v6j", server)], d[fmt.Sprintf("xerr%d:v6j", server)], } if allEmpty(pd) { return nil } return &RouteServer{ Number: server, asn: mustParseInt(d["ASN"]), IPv4: RouteServerStats{ Prefixes: mustParseInt(pd[0]), Errors: mustParseInt(pd[1]), TransitErrors: mustParseInt(pd[2]), }, IPv6: RouteServerStats{ Prefixes: mustParseInt(pd[3]), Errors: mustParseInt(pd[4]), TransitErrors: mustParseInt(pd[5]), }, IPv4Jumbo: RouteServerStats{ Prefixes: mustParseInt(pd[6]), Errors: mustParseInt(pd[7]), TransitErrors: mustParseInt(pd[8]), }, IPv6Jumbo: RouteServerStats{ Prefixes: mustParseInt(pd[9]), Errors: mustParseInt(pd[10]), TransitErrors: mustParseInt(pd[11]), }, } }