From c66f99324cb2842d330d690cfb84865a843413df Mon Sep 17 00:00:00 2001 From: robl Date: Fri, 21 Feb 2025 04:32:37 +0000 Subject: [PATCH 1/2] [IM] Add option GRAPHER_BACKEND_MRTG_RESELLER_AGGREGATE to set reseller aggregate graph behaviour --- .env.dev | 1 + .env.docker | 1 + .env.example | 26 ++++++++++ app/Services/Grapher/Backend/Mrtg.php | 48 ++++++++++++++++++- config/grapher.php | 3 ++ .../grapher/mrtg/member-ports.foil.php | 24 +++++----- 6 files changed, 90 insertions(+), 13 deletions(-) diff --git a/.env.dev b/.env.dev index 7b1aa4912..429a5ff87 100644 --- a/.env.dev +++ b/.env.dev @@ -181,6 +181,7 @@ GRAPHER_BACKEND_MRTG_DBTYPE="rrd" # more sensible such as: # GRAPHER_BACKEND_MRTG_WORKDIR="/srv/mrtg" # GRAPHER_BACKEND_MRTG_LOGDIR="/srv/mrtg" +# GRAPHER_BACKEND_MRTG_RESELLER_AGGREGATE="include" ################################################################################# ## Grapher - sflow - see: https://docs.ixpmanager.org/latest/grapher/sflow/ diff --git a/.env.docker b/.env.docker index bb29adf1c..fd67da9aa 100644 --- a/.env.docker +++ b/.env.docker @@ -94,6 +94,7 @@ GRAPHER_BACKENDS="dummy" GRAPHER_BACKEND_MRTG_WORKDIR="/mrtg_data" GRAPHER_BACKEND_MRTG_LOGDIR="/srv/mrtg" +# GRAPHER_BACKEND_MRTG_RESELLER_AGGREGATE="include" #GRAPHER_BACKEND_SFLOW_ENABLED=true #GRAPHER_BACKEND_SFLOW_ROOT="http://sflow.example.com/sflow" GRAPHER_CACHE_ENABLED=false diff --git a/.env.example b/.env.example index 4c91ff6dd..10935ff66 100644 --- a/.env.example +++ b/.env.example @@ -177,6 +177,32 @@ GRAPHER_BACKEND_MRTG_DBTYPE="rrd" # GRAPHER_BACKEND_MRTG_WORKDIR="/srv/mrtg" # GRAPHER_BACKEND_MRTG_LOGDIR="/srv/mrtg" +# Behaviour for reseller member aggregate graphs. +# This only affects the *individual* aggregate graphs for resellers. +# Reseller/Fanout ports are always excluded from overall aggregate graphs. + +# include = Always include reseller uplink ports in member aggregate graphs (default) +# - Set this if resellers always have separate physical peering/uplink ports. +# GRAPHER_BACKEND_MRTG_RESELLER_AGGREGATE="include" + +# exclude = Always exclude reseller uplink ports from member aggregate graphs. +# GRAPHER_BACKEND_MRTG_RESELLER_AGGREGATE="exclude" + +# ppp = Only include peering/reseller uplink ports having a crossconnect. +# All other other port types are included except 'fanout'. +# +# - Set this if you have patch panel records, and resellers: +# - Can have only reseller uplink ports (no peering ports), or; +# - Have their own peering VLAN via the same physical interface as the +# reseller uplink port, or; +# - Have their own peering VLAN via a subinterface of reseller uplink port. +# - Other 'software' interfaces or VLAN translation is used for +# reseller peering ports., and you want to avoid double-counting. +# +# In this case, for resellers, reseller|peering ports which do not have an +# associated patch panel port are not added to the member aggregate graphs: +# GRAPHER_BACKEND_MRTG_RESELLER_AGGREGATE="ppp" + ################################################################################# ## Grapher - sflow - see: https://docs.ixpmanager.org/latest/grapher/sflow/ ## diff --git a/app/Services/Grapher/Backend/Mrtg.php b/app/Services/Grapher/Backend/Mrtg.php index c973f357f..63d538080 100644 --- a/app/Services/Grapher/Backend/Mrtg.php +++ b/app/Services/Grapher/Backend/Mrtg.php @@ -136,6 +136,7 @@ public function generateConfiguration( int $type = self::GENERATED_CONFIG_TYPE_M * * array `['locs']` of Location objects indexed by their ID * * array `['infras']` of Infrastructure objects indexed by their ID * * array `['custports']` containing an array of PhysicalInterfaceEntity IDs indexed by customer ID + * * array `['custaggr']` containing an array of PhysicalInterfaceEntity IDs indexed by customer ID for aggregate graph * * array `['custlags']` containing an array of PhysicalInterfaceEntity IDs contained in an array indexed * by VirtualInterfaceEntity IDs in turn in an array of customer IDs: * `['custlags'][$custid][$viid][]` @@ -155,6 +156,7 @@ public function getPeeringPorts(): array $data['infraports_maxbytes'] = []; $data['custs'] = []; $data['custports'] = []; + $data['custaggr'] = []; $data['custlags'] = []; $data['locs'] = []; $data['locports'] = []; @@ -226,8 +228,50 @@ public function getPeeringPorts(): array $switcher = $pi->switchPort->switcher; $location = $pi->switchPort->switcher->cabinet->location; - // don't count reseller ports or fanout ports in agregates - if( !$pi->switchPort->typeReseller() && !$pi->switchPort->typeFanout() ) { + $do_aggregate = 1; + + // For resellers, include reseller uplink / peering ports having a physical + // Patch panel port associated with them in the member aggregate graph. + // + // (For resellers having only uplink ports, or where they peer on + // a subinterface of their uplink port, don't double-count the uplink + // port with the reseller's own peering port in the aggregate graph. + + if ( $c->isReseller && $reseller_agg == 'ppp' ) { + + $do_aggregate = 0; + $ppp = $pi->switchPort->patchPanelPort; + + // Include only ports which have a crossconnect: + if( isset ( $ppp->id ) ) { + $do_aggregate = 1; + } + + // For other port types, assume include: + if( !$pi->switchPort->typeReseller() && !$pi->switchPort->typePeering() ) { + $do_aggregate = 1; + } + } + + + if ( $c->isReseller && $reseller_agg == 'exclude' ) { + + if( $pi->switchPort->typeReseller() ) { + $do_aggregate = 0; + } + + } + + // Always exclude fanout ports: + if ( $pi->switchPort->typeFanout() ) { $do_aggregate = 0; } + + // Add to member aggregate graph: + if( $do_aggregate == 1 ) { + $data[ 'custaggr' ][ $c->id ][] = $pi->id; + } + + // Add to overall aggregate graphs if not reseller / fanout (don't double-count) + if( !$pi->switchPort->typeReseller() && !$pi->switchPort->typeFanout() ) { $data[ 'swports' ][ $pi->switchPort->switcher->id ][] = $pi->id; $data[ 'locports' ][ $pi->switchPort->switcher->cabinet->location->id ][] = $pi->id; $data[ 'infraports' ][ $pi->switchPort->switcher->infrastructureModel->id ][] = $pi->id; diff --git a/config/grapher.php b/config/grapher.php index 0537285b5..f0dd8dcce 100644 --- a/config/grapher.php +++ b/config/grapher.php @@ -71,6 +71,9 @@ // local directory or a URL to remote web server 'logdir' => env( 'GRAPHER_BACKEND_MRTG_LOGDIR', '/tmp' ), + // aggregate graph behaviour for resellers. + 'reseller_agg' => env( 'GRAPHER_BACKEND_MRTG_RESELLER_AGGREGATE', 'include' ), // options: include, exclude, ppp + 'trunks' => call_user_func( function() { if( file_exists( config_path() . '/grapher_trunks.php' ) ) { return include( config_path() . '/grapher_trunks.php' ); diff --git a/resources/views/services/grapher/mrtg/member-ports.foil.php b/resources/views/services/grapher/mrtg/member-ports.foil.php index 69e8ed529..d0aaf02b4 100644 --- a/resources/views/services/grapher/mrtg/member-ports.foil.php +++ b/resources/views/services/grapher/mrtg/member-ports.foil.php @@ -92,17 +92,19 @@ endif; // overall aggregate - echo $this->insert( - "services/grapher/mrtg/target", [ - 'trafficTypes' => \IXP\Utils\Grapher\Mrtg::TRAFFIC_TYPES, - 'mrtgPrefix' => sprintf( "aggregate-%05d", $c->id ), - 'portIds' => $t->data['custports'][ $c->id ], - 'data' => $t->data, - 'graphTitle' => sprintf( "%s -- IXP Total Aggregate -- %%s / second", $c->abbreviatedName ), - 'directory' => sprintf("members/%x/%05d", $c->id % 16, $c->id), - 'maxbytes' => $custmaxbytes, - ] - ) . "\n\n\n"; + if( isset( $t->data['custaggr'][$c->id] ) ): + echo $this->insert( + "services/grapher/mrtg/target", [ + 'trafficTypes' => \IXP\Utils\Grapher\Mrtg::TRAFFIC_TYPES, + 'mrtgPrefix' => sprintf( "aggregate-%05d", $c->id ), + 'portIds' => $t->data['custaggr'][ $c->id ], + 'data' => $t->data, + 'graphTitle' => sprintf( "%s -- IXP Total Aggregate -- %%s / second", $c->abbreviatedName ), + 'directory' => sprintf("members/%x/%05d", $c->id % 16, $c->id), + 'maxbytes' => $custmaxbytes, + ] + ) . "\n\n\n"; + endif; endforeach; ?> From 6174962ca91b635293a56a72e4dc3005c0397d99 Mon Sep 17 00:00:00 2001 From: robl Date: Fri, 21 Feb 2025 04:52:59 +0000 Subject: [PATCH 2/2] [IM] Add option GRAPHER_BACKEND_MRTG_RESELLER_AGGREGATE to set reseller aggregate graph behaviour --- app/Services/Grapher/Backend/Mrtg.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/Services/Grapher/Backend/Mrtg.php b/app/Services/Grapher/Backend/Mrtg.php index 63d538080..96ae54166 100644 --- a/app/Services/Grapher/Backend/Mrtg.php +++ b/app/Services/Grapher/Backend/Mrtg.php @@ -172,6 +172,8 @@ public function getPeeringPorts(): array // we need to wrap switch ports in physical interfaces for switch aggregates and, as such, we need to use unused physical interface IDs $maxPiID = 0; + $reseller_agg = config('grapher.backends.mrtg.reseller_agg'); + foreach( Customer::all() as $c ) { foreach( $c->virtualInterfaces as $vi ) { // we do not include core bundle interfaces here