master
go 274 lines 24 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package snmp
4
5 import (
6 "context"
7 "sort"
8 "strconv"
9 "time"
10
11 "github.com/netdata/netdata/go/plugins/pkg/funcapi"
12 )
13
14 const (
15 bgpPeersMethodID = "bgp-peers"
16 bgpPeersParamView = "view"
17 bgpPeersViewPeers = "peers"
18 bgpPeersViewFamilies = "peer_families"
19 bgpPeersViewAll = "all"
20 bgpPeersDefaultView = bgpPeersViewPeers
21 )
22
23 type bgpPeerColumn struct {
24 funcapi.ColumnMeta
25 Value func(*bgpPeerEntry) any
26 }
27
28 type funcBGPPeers struct {
29 cache *bgpPeerCache
30 }
31
32 func newFuncBGPPeers(cache *bgpPeerCache) *funcBGPPeers {
33 return &funcBGPPeers{cache: cache}
34 }
35
36 func bgpPeerColumnSet(cols []bgpPeerColumn) funcapi.ColumnSet[bgpPeerColumn] {
37 return funcapi.Columns(cols, func(c bgpPeerColumn) funcapi.ColumnMeta { return c.ColumnMeta })
38 }
39
40 var _ funcapi.MethodHandler = (*funcBGPPeers)(nil)
41
42 func bgpPeersMethodConfig() funcapi.MethodConfig {
43 return funcapi.MethodConfig{
44 ID: bgpPeersMethodID,
45 Name: "BGP Peers",
46 UpdateEvery: 10,
47 Help: "Detailed current BGP peer and peer-family state from cached SNMP data",
48 RequiredParams: []funcapi.ParamConfig{{
49 ID: bgpPeersParamView,
50 Name: "View",
51 Help: "Choose whether to show peer rows, peer-family rows, or both",
52 Selection: funcapi.ParamSelect,
53 Options: []funcapi.ParamOption{
54 {ID: bgpPeersViewPeers, Name: "Peers", Default: true},
55 {ID: bgpPeersViewFamilies, Name: "Peer Families"},
56 {ID: bgpPeersViewAll, Name: "All"},
57 },
58 }},
59 }
60 }
61
62 func (f *funcBGPPeers) MethodParams(_ context.Context, method string) ([]funcapi.ParamConfig, error) {
63 if method != bgpPeersMethodID {
64 return nil, nil
65 }
66 return bgpPeersMethodConfig().RequiredParams, nil
67 }
68
69 func (f *funcBGPPeers) Cleanup(_ context.Context) {}
70
71 func (f *funcBGPPeers) Handle(_ context.Context, method string, params funcapi.ResolvedParams) *funcapi.FunctionResponse {
72 if method != bgpPeersMethodID {
73 return funcapi.NotFoundResponse(method)
74 }
75 if f.cache == nil {
76 return funcapi.UnavailableResponse("BGP peer data is not available for this device")
77 }
78
79 view := params.GetOne(bgpPeersParamView)
80 if view == "" {
81 view = bgpPeersDefaultView
82 }
83
84 snapshot := f.cache.snapshot(time.Now())
85 if snapshot.expired || len(snapshot.entries) == 0 {
86 if snapshot.message == "" {
87 snapshot.message = "no BGP peer data is available for this device"
88 }
89 return funcapi.UnavailableResponse(snapshot.message)
90 }
91
92 rows := make([][]any, 0, len(snapshot.entries))
93 for _, entry := range snapshot.entries {
94 if !matchesBGPPeerView(entry.scope, view) {
95 continue
96 }
97 rows = append(rows, buildBGPPeerRow(entry))
98 }
99
100 sortBGPPeerRows(rows)
101
102 cs := bgpPeerColumnSet(bgpPeerColumns)
103 help := "Detailed current BGP peer and peer-family state from cached SNMP data"
104 if snapshot.stale && snapshot.message != "" {
105 help += ". " + snapshot.message
106 }
107 return &funcapi.FunctionResponse{
108 Status: 200,
109 Help: help,
110 Columns: cs.BuildColumns(),
111 Data: rows,
112 DefaultSortColumn: "Neighbor",
113 }
114 }
115
116 func matchesBGPPeerView(scope, view string) bool {
117 switch view {
118 case bgpPeersViewAll:
119 return true
120 case bgpPeersViewFamilies:
121 return scope == bgpPeersViewFamilies
122 default:
123 return scope == bgpPeersViewPeers
124 }
125 }
126
127 func buildBGPPeerRow(entry *bgpPeerEntry) []any {
128 row := make([]any, len(bgpPeerColumns))
129 for i, col := range bgpPeerColumns {
130 row[i] = col.Value(entry)
131 }
132 return row
133 }
134
135 func sortBGPPeerRows(rows [][]any) {
136 if len(rows) == 0 {
137 return
138 }
139
140 colIdx := map[string]int{}
141 for i, col := range bgpPeerColumns {
142 colIdx[col.Name] = i
143 }
144
145 sort.Slice(rows, func(i, j int) bool {
146 a := rows[i]
147 b := rows[j]
148
149 for _, name := range []string{"Scope", "Routing Instance", "Neighbor", "Family"} {
150 av, _ := a[colIdx[name]].(string)
151 bv, _ := b[colIdx[name]].(string)
152 if av == bv {
153 continue
154 }
155 return av < bv
156 }
157 return false
158 })
159 }
160
161 func bgpScopeLabel(scope string) string {
162 switch scope {
163 case bgpPeersViewFamilies:
164 return "peer family"
165 default:
166 return "peer"
167 }
168 }
169
170 func bgpFamilyLabel(tags map[string]string) string {
171 if name := tags["address_family_name"]; name != "" && name != "all all" {
172 return name
173 }
174 af := tags["address_family"]
175 safi := tags["subsequent_address_family"]
176 switch {
177 case af == "" && safi == "":
178 return ""
179 case af == "all" && safi == "all":
180 return "all"
181 case safi == "":
182 return af
183 default:
184 return af + " " + safi
185 }
186 }
187
188 func bgpLastErrorDisplay(entry *bgpPeerEntry) string {
189 if entry.lastErrorText != "" {
190 return entry.lastErrorText
191 }
192 if entry.lastErrorCode == nil {
193 return ""
194 }
195 if entry.lastErrorSubcode == nil {
196 return "code " + int64ToString(entry.lastErrorCode)
197 }
198 return "code " + int64ToString(entry.lastErrorCode) + " / subcode " + int64ToString(entry.lastErrorSubcode)
199 }
200
201 func int64ToString(v *int64) string {
202 if v == nil {
203 return ""
204 }
205 return strconv.FormatInt(*v, 10)
206 }
207
208 func int64Value(v *int64) any {
209 if v == nil {
210 return nil
211 }
212 return *v
213 }
214
215 var bgpPeerColumns = []bgpPeerColumn{
216 {ColumnMeta: funcapi.ColumnMeta{Name: "rowId", Tooltip: "Row ID", Type: funcapi.FieldTypeString, Visible: false, Sortable: true, Filter: funcapi.FieldFilterMultiselect, UniqueKey: true, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return e.key }},
217 {ColumnMeta: funcapi.ColumnMeta{Name: "Stale", Tooltip: "Whether this row is from a previous successful collection after a newer BGP collection failure", Type: funcapi.FieldTypeBoolean, Visible: false, Sortable: true, Filter: funcapi.FieldFilterMultiselect, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return e.stale }},
218 {ColumnMeta: funcapi.ColumnMeta{Name: "Scope", Tooltip: "Scope", Type: funcapi.FieldTypeString, Visible: true, Sortable: true, Filter: funcapi.FieldFilterMultiselect, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return bgpScopeLabel(e.scope) }},
219 {ColumnMeta: funcapi.ColumnMeta{Name: "Routing Instance", Tooltip: "Routing Instance", Type: funcapi.FieldTypeString, Visible: true, Sortable: true, Filter: funcapi.FieldFilterMultiselect, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return e.tags["routing_instance"] }},
220 {ColumnMeta: funcapi.ColumnMeta{Name: "Neighbor", Tooltip: "Neighbor", Type: funcapi.FieldTypeString, Visible: true, Sortable: true, Filter: funcapi.FieldFilterMultiselect, Sticky: true, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return e.tags["neighbor"] }},
221 {ColumnMeta: funcapi.ColumnMeta{Name: "Local Address", Tooltip: "Local Address", Type: funcapi.FieldTypeString, Visible: true, Sortable: true, Filter: funcapi.FieldFilterMultiselect, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return e.tags["local_address"] }},
222 {ColumnMeta: funcapi.ColumnMeta{Name: "Remote AS", Tooltip: "Remote AS", Type: funcapi.FieldTypeString, Visible: true, Sortable: true, Filter: funcapi.FieldFilterMultiselect, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return e.tags["remote_as"] }},
223 {ColumnMeta: funcapi.ColumnMeta{Name: "Peer Description", Tooltip: "Peer Description", Type: funcapi.FieldTypeString, Visible: true, Sortable: true, Filter: funcapi.FieldFilterMultiselect, FullWidth: true, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return e.tags["peer_description"] }},
224 {ColumnMeta: funcapi.ColumnMeta{Name: "Family", Tooltip: "Family", Type: funcapi.FieldTypeString, Visible: true, Sortable: true, Filter: funcapi.FieldFilterMultiselect, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return bgpFamilyLabel(e.tags) }},
225 {ColumnMeta: funcapi.ColumnMeta{Name: "Admin Status", Tooltip: "Admin Status", Type: funcapi.FieldTypeString, Visible: true, Sortable: true, Filter: funcapi.FieldFilterMultiselect, Visualization: funcapi.FieldVisualPill, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return e.adminStatus }},
226 {ColumnMeta: funcapi.ColumnMeta{Name: "Connection State", Tooltip: "Connection State", Type: funcapi.FieldTypeString, Visible: true, Sortable: true, Filter: funcapi.FieldFilterMultiselect, Visualization: funcapi.FieldVisualPill, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return humanizeBGPLabel(e.state) }},
227 {ColumnMeta: funcapi.ColumnMeta{Name: "Previous State", Tooltip: "Previous State", Type: funcapi.FieldTypeString, Visible: true, Sortable: true, Filter: funcapi.FieldFilterMultiselect, Visualization: funcapi.FieldVisualPill, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return humanizeBGPLabel(e.previousState) }},
228 {ColumnMeta: funcapi.ColumnMeta{Name: "Established Uptime", Tooltip: "Established Uptime", Type: funcapi.FieldTypeInteger, Units: "seconds", Visible: true, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummaryMax}, Value: func(e *bgpPeerEntry) any { return int64Value(e.establishedUptime) }},
229 {ColumnMeta: funcapi.ColumnMeta{Name: "Last Update Age", Tooltip: "Last Update Age", Type: funcapi.FieldTypeInteger, Units: "seconds", Visible: true, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummaryMax}, Value: func(e *bgpPeerEntry) any { return int64Value(e.lastReceivedUpdate) }},
230 {ColumnMeta: funcapi.ColumnMeta{Name: "Updates Received", Tooltip: "Updates Received", Type: funcapi.FieldTypeInteger, Visible: true, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummarySum}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.updateCounts, "received")) }},
231 {ColumnMeta: funcapi.ColumnMeta{Name: "Updates Sent", Tooltip: "Updates Sent", Type: funcapi.FieldTypeInteger, Visible: true, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummarySum}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.updateCounts, "sent")) }},
232 {ColumnMeta: funcapi.ColumnMeta{Name: "Prefixes Accepted", Tooltip: "Prefixes Accepted", Type: funcapi.FieldTypeInteger, Visible: true, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummaryMax}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.routeCounts, "accepted")) }},
233 {ColumnMeta: funcapi.ColumnMeta{Name: "Prefixes Advertised", Tooltip: "Prefixes Advertised", Type: funcapi.FieldTypeInteger, Visible: true, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummaryMax}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.routeCounts, "advertised")) }},
234 {ColumnMeta: funcapi.ColumnMeta{Name: "Last Error", Tooltip: "Last Error", Type: funcapi.FieldTypeString, Visible: true, Sortable: true, Filter: funcapi.FieldFilterMultiselect, FullWidth: true, Wrap: true, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return bgpLastErrorDisplay(e) }},
235 {ColumnMeta: funcapi.ColumnMeta{Name: "Down Reason", Tooltip: "Down Reason", Type: funcapi.FieldTypeString, Visible: true, Sortable: true, Filter: funcapi.FieldFilterMultiselect, FullWidth: true, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return e.lastDownReason }},
236 {ColumnMeta: funcapi.ColumnMeta{Name: "GR State", Tooltip: "GR State", Type: funcapi.FieldTypeString, Visible: true, Sortable: true, Filter: funcapi.FieldFilterMultiselect, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return e.gracefulRestart }},
237 {ColumnMeta: funcapi.ColumnMeta{Name: "Unavailability Reason", Tooltip: "Unavailability Reason", Type: funcapi.FieldTypeString, Visible: true, Sortable: true, Filter: funcapi.FieldFilterMultiselect, FullWidth: true, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return e.unavailabilityReason }},
238 {ColumnMeta: funcapi.ColumnMeta{Name: "Neighbor Address Type", Tooltip: "Neighbor Address Type", Type: funcapi.FieldTypeString, Visible: false, Sortable: true, Filter: funcapi.FieldFilterMultiselect, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return e.tags["neighbor_address_type"] }},
239 {ColumnMeta: funcapi.ColumnMeta{Name: "Local AS", Tooltip: "Local AS", Type: funcapi.FieldTypeString, Visible: false, Sortable: true, Filter: funcapi.FieldFilterMultiselect, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return e.tags["local_as"] }},
240 {ColumnMeta: funcapi.ColumnMeta{Name: "Local Identifier", Tooltip: "Local Identifier", Type: funcapi.FieldTypeString, Visible: false, Sortable: true, Filter: funcapi.FieldFilterMultiselect, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return e.tags["local_identifier"] }},
241 {ColumnMeta: funcapi.ColumnMeta{Name: "Peer Identifier", Tooltip: "Peer Identifier", Type: funcapi.FieldTypeString, Visible: false, Sortable: true, Filter: funcapi.FieldFilterMultiselect, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return e.tags["peer_identifier"] }},
242 {ColumnMeta: funcapi.ColumnMeta{Name: "Peer Type", Tooltip: "Peer Type", Type: funcapi.FieldTypeString, Visible: false, Sortable: true, Filter: funcapi.FieldFilterMultiselect, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return e.tags["peer_type"] }},
243 {ColumnMeta: funcapi.ColumnMeta{Name: "BGP Version", Tooltip: "BGP Version", Type: funcapi.FieldTypeString, Visible: false, Sortable: true, Filter: funcapi.FieldFilterMultiselect, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return e.tags["bgp_version"] }},
244 {ColumnMeta: funcapi.ColumnMeta{Name: "Messages Received", Tooltip: "Messages Received", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummarySum}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.messageCounts, "received")) }},
245 {ColumnMeta: funcapi.ColumnMeta{Name: "Messages Sent", Tooltip: "Messages Sent", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummarySum}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.messageCounts, "sent")) }},
246 {ColumnMeta: funcapi.ColumnMeta{Name: "Notifications Received", Tooltip: "Notifications Received", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummarySum}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.notificationCounts, "received")) }},
247 {ColumnMeta: funcapi.ColumnMeta{Name: "Notifications Sent", Tooltip: "Notifications Sent", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummarySum}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.notificationCounts, "sent")) }},
248 {ColumnMeta: funcapi.ColumnMeta{Name: "Last Received Notification Reason", Tooltip: "Last Received Notification Reason", Type: funcapi.FieldTypeString, Visible: false, Sortable: true, Filter: funcapi.FieldFilterMultiselect, FullWidth: true, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return e.lastRecvNotify }},
249 {ColumnMeta: funcapi.ColumnMeta{Name: "Last Sent Notification Reason", Tooltip: "Last Sent Notification Reason", Type: funcapi.FieldTypeString, Visible: false, Sortable: true, Filter: funcapi.FieldFilterMultiselect, FullWidth: true, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return e.lastSentNotify }},
250 {ColumnMeta: funcapi.ColumnMeta{Name: "Open Received", Tooltip: "Open Received", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummarySum}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.openCounts, "received")) }},
251 {ColumnMeta: funcapi.ColumnMeta{Name: "Open Sent", Tooltip: "Open Sent", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummarySum}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.openCounts, "sent")) }},
252 {ColumnMeta: funcapi.ColumnMeta{Name: "Keepalive Received", Tooltip: "Keepalive Received", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummarySum}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.keepaliveCounts, "received")) }},
253 {ColumnMeta: funcapi.ColumnMeta{Name: "Keepalive Sent", Tooltip: "Keepalive Sent", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummarySum}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.keepaliveCounts, "sent")) }},
254 {ColumnMeta: funcapi.ColumnMeta{Name: "Route Refresh Received", Tooltip: "Route Refresh Received", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummarySum}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.routeRefreshCounts, "received")) }},
255 {ColumnMeta: funcapi.ColumnMeta{Name: "Route Refresh Sent", Tooltip: "Route Refresh Sent", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummarySum}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.routeRefreshCounts, "sent")) }},
256 {ColumnMeta: funcapi.ColumnMeta{Name: "Established Transitions", Tooltip: "Established Transitions", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummarySum}, Value: func(e *bgpPeerEntry) any { return int64Value(e.establishedCount) }},
257 {ColumnMeta: funcapi.ColumnMeta{Name: "Down Transitions", Tooltip: "Down Transitions", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummarySum}, Value: func(e *bgpPeerEntry) any { return int64Value(e.downTransitions) }},
258 {ColumnMeta: funcapi.ColumnMeta{Name: "Up Transitions", Tooltip: "Up Transitions", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummarySum}, Value: func(e *bgpPeerEntry) any { return int64Value(e.upTransitions) }},
259 {ColumnMeta: funcapi.ColumnMeta{Name: "Flaps", Tooltip: "Flaps", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummarySum}, Value: func(e *bgpPeerEntry) any { return int64Value(e.flaps) }},
260 {ColumnMeta: funcapi.ColumnMeta{Name: "Prefixes Received", Tooltip: "Prefixes Received", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummaryMax}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.routeCounts, "received")) }},
261 {ColumnMeta: funcapi.ColumnMeta{Name: "Prefixes Active", Tooltip: "Prefixes Active", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummaryMax}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.routeCounts, "active")) }},
262 {ColumnMeta: funcapi.ColumnMeta{Name: "Prefixes Rejected", Tooltip: "Prefixes Rejected", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummaryMax}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.routeCounts, "rejected")) }},
263 {ColumnMeta: funcapi.ColumnMeta{Name: "Prefixes Suppressed", Tooltip: "Prefixes Suppressed", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummaryMax}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.routeCounts, "suppressed")) }},
264 {ColumnMeta: funcapi.ColumnMeta{Name: "Prefixes Withdrawn", Tooltip: "Prefixes Withdrawn", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummaryMax}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.routeCounts, "withdrawn")) }},
265 {ColumnMeta: funcapi.ColumnMeta{Name: "Routes Received Total", Tooltip: "Routes Received Total", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummaryMax}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.routeTotals, "received")) }},
266 {ColumnMeta: funcapi.ColumnMeta{Name: "Routes Advertised Total", Tooltip: "Routes Advertised Total", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummaryMax}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.routeTotals, "advertised")) }},
267 {ColumnMeta: funcapi.ColumnMeta{Name: "Routes Rejected Total", Tooltip: "Routes Rejected Total", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummaryMax}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.routeTotals, "rejected")) }},
268 {ColumnMeta: funcapi.ColumnMeta{Name: "Routes Active Total", Tooltip: "Routes Active Total", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummaryMax}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.routeTotals, "active")) }},
269 {ColumnMeta: funcapi.ColumnMeta{Name: "Prefix Limit", Tooltip: "Prefix Limit", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummaryMax}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.routeLimits, "admin_limit")) }},
270 {ColumnMeta: funcapi.ColumnMeta{Name: "Prefix Threshold", Tooltip: "Prefix Threshold", Type: funcapi.FieldTypeInteger, Units: "%", Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummaryMax}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.routeLimitThresholds, "threshold")) }},
271 {ColumnMeta: funcapi.ColumnMeta{Name: "Prefix Clear Threshold", Tooltip: "Prefix Clear Threshold", Type: funcapi.FieldTypeInteger, Units: "%", Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummaryMax}, Value: func(e *bgpPeerEntry) any { return int64Value(mapValuePtr(e.routeLimitThresholds, "clear_threshold")) }},
272 {ColumnMeta: funcapi.ColumnMeta{Name: "Last Error Code", Tooltip: "Last Error Code", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return int64Value(e.lastErrorCode) }},
273 {ColumnMeta: funcapi.ColumnMeta{Name: "Last Error Subcode", Tooltip: "Last Error Subcode", Type: funcapi.FieldTypeInteger, Visible: false, Sortable: true, Filter: funcapi.FieldFilterRange, Transform: funcapi.FieldTransformNumber, Summary: funcapi.FieldSummaryCount}, Value: func(e *bgpPeerEntry) any { return int64Value(e.lastErrorSubcode) }},
274 }