2 ###############################################################################
4 # collecty - A system statistics collection daemon for IPFire #
5 # Copyright (C) 2015 IPFire development team #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
26 from ..colours
import *
29 CONNTRACK_FILE
= "/proc/net/nf_conntrack"
31 class ConntrackTable(object):
49 _stateful_layer4_protocols
= {
86 def __init__(self
, filename
):
87 with
open(filename
) as f
:
88 self
.layer3_protocols
= {}
89 for proto
in self
._layer
3_protocols
:
90 self
.layer3_protocols
[proto
] = 0
92 self
.layer4_protocols
= {}
93 for proto
in self
._layer
4_protocols
:
94 self
.layer4_protocols
[proto
] = 0
96 self
.protocol_states
= {}
97 for proto
, states
in self
._stateful
_layer
4_protocols
.items():
98 self
.protocol_states
[proto
] = dict((state
, 0) for state
in states
)
100 for line
in f
.readlines():
104 layer3_protocol
= line
[0]
107 self
.layer3_protocols
[layer3_protocol
] += 1
109 self
.layer3_protocols
["other"] += 1
112 layer4_protocol
= line
[2]
115 self
.layer4_protocols
[layer4_protocol
] += 1
117 self
.layer4_protocols
["other"] += 1
118 layer4_protocol
= "other"
120 # Count connection states
121 if layer4_protocol
in self
.protocol_states
:
125 self
.protocol_states
[layer4_protocol
][state
] += 1
130 class ConntrackLayer3ProtocolsGraphTemplate(base
.GraphTemplate
):
131 name
= "conntrack-layer3-protocols"
133 _protocols
= ConntrackTable
._layer
3_protocols
136 "ipv6" : COLOUR_IPV6
,
137 "ipv4" : COLOUR_IPV4
,
138 "other" : COLOUR_IPVX
,
141 def get_objects(self
, *args
):
143 self
.plugin
.get_object("layer3-protocols"),
148 # Order the protocols by standard deviation which will give us cleaner graphs
149 # http://stackoverflow.com/questions/13958409/how-to-graph-rrd-stackable-data-by-standard-deviation-to-maximize-readability
150 stddev
= self
.object.get_stddev()
153 for p
in self
._protocols
:
154 protos
[p
] = stddev
.get(p
)
156 return sorted(protos
, key
=protos
.get
)
159 def protocol_descriptions(self
):
160 _
= self
.locale
.translate
165 "other" : _("Other"),
169 def graph_title(self
):
170 _
= self
.locale
.translate
171 return _("Connections by Layer 3 Protocols")
174 def graph_vertical_label(self
):
175 _
= self
.locale
.translate
176 return _("Number of open connections")
184 _
= self
.locale
.translate
187 for proto
in self
.protocols
:
188 colour
= self
.protocol_colours
.get(proto
, COLOUR_OTHER
)
189 description
= self
.protocol_descriptions
.get(proto
, proto
)
192 "AREA:%s%s:%-15s:STACK" % (proto
, colour
, description
),
193 "GPRINT:%s_cur:%-6s %%8.0lf" % (proto
, _("Now")),
194 "GPRINT:%s_avg:%-6s %%8.0lf" % (proto
, _("Avg")),
195 "GPRINT:%s_min:%-6s %%8.0lf" % (proto
, _("Min")),
196 "GPRINT:%s_max:%-6s %%8.0lf\\l" % (proto
, _("Max")),
202 def rrd_graph_args(self
):
204 "--legend-direction=bottomup",
208 class ConntrackLayer4ProtocolsGraphTemplate(ConntrackLayer3ProtocolsGraphTemplate
):
209 name
= "conntrack-layer4-protocols"
214 "icmp" : COLOUR_ICMP
,
215 "igmp" : COLOUR_IGMP
,
216 "udplite" : COLOUR_UDPLITE
,
217 "sctp" : COLOUR_SCTP
,
218 "dccp" : COLOUR_DCCP
,
222 def protocol_descriptions(self
):
223 _
= self
.locale
.translate
230 "udplite" : _("UDP Lite"),
233 "other" : _("Other"),
236 protocol_sortorder
= {
246 def get_objects(self
, *args
):
248 self
.plugin
.get_object("layer4-protocols"),
252 def graph_title(self
):
253 _
= self
.locale
.translate
254 return _("Connections by IP Protocols")
257 def _protocols(self
):
258 return sorted(ConntrackTable
._layer
4_protocols
,
259 key
=lambda x
: self
.protocol_sortorder
.get(x
, 99))
262 class ConntrackProtocolWithStatesGraphTemplate(base
.GraphTemplate
):
263 name
= "conntrack-protocol-states"
267 states_descriptions
= {
292 "SHUTDOWN_ACK_SENT" : 0,
311 def graph_title(self
):
312 _
= self
.locale
.translate
313 return _("Protocol States of all %s connections") % self
.protocol
.upper()
316 def graph_vertical_label(self
):
317 _
= self
.locale
.translate
318 return _("Number of open connections")
322 return self
.object.protocol
326 return sorted(ConntrackTable
._stateful
_layer
4_protocols
[self
.protocol
],
327 key
=lambda x
: self
.states_sortorder
[self
.protocol
].get(x
, 99))
331 _
= self
.locale
.translate
334 for state
in reversed(self
.states
):
336 "colour" : COLOURS_PROTOCOL_STATES
.get(state
, BLACK
),
337 "description" : self
.states_descriptions
[self
.protocol
].get(state
, state
),
338 "proto" : self
.protocol
,
341 "legend_min" : "%10s\: %%8.0lf" % _("Minimum"),
342 "legend_max" : "%10s\: %%8.0lf" % _("Maximum"),
343 "legend_avg" : "%10s\: %%8.0lf" % _("Average"),
344 "legend_cur" : "%10s\: %%8.0lf" % _("Current"),
347 args
+= self
.object.make_rrd_defs(state
) + [
348 "AREA:%(state)s%(colour)s:%(description)-15s:STACK" % i
,
349 "GPRINT:%(state)s_cur:%(legend_cur)s" % i
,
350 "GPRINT:%(state)s_avg:%(legend_avg)s" % i
,
351 "GPRINT:%(state)s_min:%(legend_min)s" % i
,
352 "GPRINT:%(state)s_max:%(legend_max)s\\n" % i
,
358 def rrd_graph_args(self
):
360 "--legend-direction=bottomup",
364 class ConntrackObject(base
.Object
):
367 def init(self
, conntrack_table
):
368 self
.conntrack_table
= conntrack_table
375 class ConntrackLayer3ProtocolsObject(ConntrackObject
):
376 protocols
= ConntrackTable
._layer
3_protocols
379 "DS:%s:GAUGE:0:U" % p
for p
in protocols
384 return "layer3-protocols"
389 for proto
in self
.protocols
:
390 r
= self
.conntrack_table
.layer3_protocols
.get(proto
, 0)
391 results
.append("%s" % r
)
396 class ConntrackLayer4ProtocolsObject(ConntrackObject
):
397 protocols
= ConntrackTable
._layer
4_protocols
400 "DS:%s:GAUGE:0:U" % p
for p
in protocols
405 return "layer4-protocols"
410 for proto
in self
.protocols
:
411 r
= self
.conntrack_table
.layer4_protocols
.get(proto
, 0)
412 results
.append("%s" % r
)
417 class ConntrackProtocolWithStatesObject(ConntrackObject
):
418 def init(self
, conntrack_table
, protocol
):
419 ConntrackObject
.init(self
, conntrack_table
)
420 self
.protocol
= protocol
423 return "<%s %s>" % (self
.__class
__.__name
__, self
.protocol
)
427 return ConntrackTable
._stateful
_layer
4_protocols
.get(self
.protocol
)
430 def rrd_schema(self
):
431 return ["DS:%s:GAUGE:0:U" % state
for state
in self
.states
]
433 def get_states(self
):
436 for state
in self
.states
:
437 r
= self
.conntrack_table
.protocol_states
[self
.protocol
].get(state
, 0)
438 results
.append("%s" % r
)
443 return self
.get_states()
446 class ConntrackPlugin(base
.Plugin
):
448 description
= "Conntrack Plugin"
451 ConntrackLayer3ProtocolsGraphTemplate
,
452 ConntrackLayer4ProtocolsGraphTemplate
,
453 ConntrackProtocolWithStatesGraphTemplate
,
458 ct
= self
.get_conntrack_table()
461 yield ConntrackLayer3ProtocolsObject(self
, ct
)
462 yield ConntrackLayer4ProtocolsObject(self
, ct
)
464 for protocol
in ConntrackTable
._stateful
_layer
4_protocols
:
465 yield ConntrackProtocolWithStatesObject(self
, ct
, protocol
)
467 def get_conntrack_table(self
):
468 if not os
.path
.exists(CONNTRACK_FILE
):
471 return ConntrackTable(CONNTRACK_FILE
)