em-sflow 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+
19
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in em-sflow.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Norman Elton
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,56 @@
1
+ = sFlow Library for EventMachine
2
+
3
+ == Summary
4
+
5
+ This gem collects, parses, and optionally proxies sampled flow records from network switches and routers. For information about sFlow, refer to www.sflow.org[http://www.sflow.org].
6
+
7
+ == Features
8
+
9
+ Version 1.0.0
10
+
11
+ * Ability to parse the following sFlow messages: Raw Packet Header, Generic Interface Counter, Ethernet Interface Counter
12
+ * All other sFlow messages are stubbed out. Their implementation should take no more than a few minutes for someone with access to an sFlow-capable device exporting these message types.
13
+ * Ability to proxy a copy of the sFlow packet to a secondary collector.
14
+
15
+
16
+ == Examples
17
+
18
+ Collector:
19
+
20
+ EM.run {
21
+ c = EventMachine::SFlow::Collector.new(:host => "127.0.0.1")
22
+
23
+ c.on_sflow do |pkt|
24
+ puts "Got #{pkt.samples.count} samples"
25
+
26
+ pkt.samples.each do |sample|
27
+ sample.records.each do |record|
28
+ if record.is_a? EM::SFlow::RawPacketHeader
29
+ puts "Received a sampled packet from #{pkt.agent} of length #{record.header.size}"
30
+ elsif record.is_a? EM::SFlow::GenericInterfaceCounters
31
+ puts "Interface #{record.if_index} on #{pkt.agent} has seen #{record.if_in_octets} inbound bytes, #{record.if_out_octets} outbound bytes"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ }
37
+
38
+ Proxy:
39
+
40
+ EM.run {
41
+ c = EventMachine::SFlow::Collector.new(:host => "127.0.0.1")
42
+
43
+ c.proxy_to "192.168.1.1"
44
+ }
45
+
46
+ Multiple callbacks and proxy targets can be defined simultaneously
47
+
48
+ == Change Log
49
+
50
+ Version 1.0.0:
51
+
52
+ * Initial release
53
+
54
+ == Credits
55
+
56
+ Author: Norman Elton normelton@gmail.com
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/em-sflow/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Norman Elton"]
6
+ gem.email = ["normelton@gmail.com"]
7
+ gem.description = "EventMachine-powered sFlow Collector"
8
+ gem.summary = "EventMachine-powered sFlow Collector"
9
+ gem.homepage = "http://github.com/normelton/em-sflow"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "em-sflow"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = EventMachine::SFlow::VERSION
17
+
18
+ gem.extra_rdoc_files = ["README.rdoc"]
19
+ gem.rdoc_options = ["--line-numbers", "--inline-source", "--title", "EM-SFLOW", "--main", "README.rdoc"]
20
+
21
+ gem.add_runtime_dependency "eventmachine", ">= 0.12.10"
22
+ end
@@ -0,0 +1,20 @@
1
+ require "em-sflow/version"
2
+
3
+ require "eventmachine"
4
+ require "ipaddr"
5
+
6
+ require "em-sflow/collector"
7
+ require "em-sflow/datagram_handler"
8
+ require "em-sflow/binary_string"
9
+ require "em-sflow/packet/datagram"
10
+ require "em-sflow/packet/flow_sample"
11
+ require "em-sflow/packet/counter_sample"
12
+ require "em-sflow/packet/raw_packet_header"
13
+ require "em-sflow/packet/generic_interface_counters"
14
+ require "em-sflow/packet/ethernet_interface_counters"
15
+
16
+ module EventMachine
17
+ module SFlow
18
+ # Your code goes here...
19
+ end
20
+ end
@@ -0,0 +1,9 @@
1
+ module EventMachine
2
+ module SFlow
3
+ module BinaryString
4
+ def advance i
5
+ slice!(0..(i - 1))
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,24 @@
1
+
2
+ module EventMachine
3
+ module SFlow
4
+ class Collector
5
+ def initialize args = {}
6
+ args[:host] ||= "127.0.0.1"
7
+ args[:port] ||= 6343
8
+
9
+ @callbacks = []
10
+ @proxy_targets = []
11
+
12
+ EventMachine.open_datagram_socket(args[:host], args[:port], DatagramHandler, {:host => args[:host], :callbacks => @callbacks, :proxy_targets => @proxy_targets})
13
+ end
14
+
15
+ def proxy_to target
16
+ @proxy_targets << target
17
+ end
18
+
19
+ def on_sflow &proc
20
+ @callbacks << proc
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,30 @@
1
+ module EventMachine
2
+ module SFlow
3
+ module DatagramHandler
4
+ def initialize args
5
+ @host = args[:host]
6
+ @callbacks = args[:callbacks]
7
+ @proxy_targets = args[:proxy_targets]
8
+ end
9
+
10
+ def receive_data data
11
+ unless @proxy_targets.empty?
12
+ @proxy_socket ||= EventMachine.open_datagram_socket(@host, 0)
13
+
14
+ @proxy_targets.each do |target|
15
+ target_host = target.split(":")[0]
16
+ target_port = target.split(":")[1] || "6343"
17
+
18
+ @proxy_socket.send_datagram(data, target_host, target_port)
19
+ end
20
+ end
21
+
22
+ datagram = Datagram.new(data)
23
+
24
+ @callbacks.each do |callback|
25
+ callback.call datagram
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,40 @@
1
+ class EventMachine::SFlow::CounterSample
2
+ attr_accessor :sequence_number, :source_class, :source_value, :records
3
+ def initialize data
4
+ @records = []
5
+
6
+ data.extend EM::SFlow::BinaryString
7
+
8
+ @sequence_number, source_id_class_value, record_count = data.unpack("NNN")
9
+
10
+ @source_class = source_id_class_value >> 24
11
+ @source_value = source_id_class_value & (2 ** 24 - 1)
12
+
13
+ data.advance(12)
14
+
15
+ record_count.times do
16
+ enterprise_format, length = data.unpack("NN")
17
+
18
+ enterprise = enterprise_format >> 12
19
+ format = enterprise_format & (2 ** 12 - 1)
20
+
21
+ data.advance(8)
22
+
23
+ record_data = data.advance(length)
24
+
25
+ if enterprise == 0 && format == 1
26
+ @records << EM::SFlow::GenericInterfaceCounters.new(record_data)
27
+ elsif enterprise == 0 && format == 2
28
+ @records << EM::SFlow::EthernetInterfaceCounters.new(record_data)
29
+ elsif enterprise == 0 && format == 3
30
+ # @records << EM::SFlow::TokenRingCounters.new(record_data)
31
+ elsif enterprise == 0 && format == 4
32
+ # @records << EM::SFlow::HundredBaseVgCounters.new(record_data)
33
+ elsif enterprise == 0 && format == 5
34
+ # @records << EM::SFlow::VlanCounters.new(record_data)
35
+ elsif enterprise == 0 && format == 1001
36
+ # @records << EM::SFlow::ProcessorInformation.new(record_data)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,46 @@
1
+ class EventMachine::SFlow::Datagram
2
+ attr_reader :version, :agent, :sub_agent_id, :datagram_sequence, :uptime, :samples
3
+
4
+ def initialize data
5
+ data.extend EM::SFlow::BinaryString
6
+
7
+ @samples = []
8
+
9
+ @version, ip_version = data.unpack("NN")
10
+
11
+ data.advance(8)
12
+
13
+ if ip_version == 1
14
+ @agent = IPAddr.new(data.unpack("N").first, Socket::AF_INET)
15
+ data.advance(4)
16
+ else
17
+ ip_elements = data.unpack("NNNN")
18
+ @agent = IPAddr.new((ip_elements[0] << 96) + (ip_elements[1] << 64) + (ip_elements[2] << 32) + ip_elements[3], Socket::AF_INET6)
19
+ data.advance(16)
20
+ end
21
+
22
+ @sub_agent_id, @datagram_sequence, @uptime, sample_count = data.unpack("NNNN")
23
+
24
+ data.advance(16)
25
+
26
+ sample_count.times do
27
+ enterprise_format, length = data.unpack("NN")
28
+ enterprise = enterprise_format >> 12
29
+ format = enterprise_format & (2 ** 12 - 1)
30
+
31
+ data.advance(8)
32
+
33
+ sample_data = data.advance(length)
34
+
35
+ if enterprise == 0 && format == 1
36
+ @samples << EM::SFlow::FlowSample.new(sample_data)
37
+ elsif enterprise == 0 && format == 2
38
+ @samples << EM::SFlow::CounterSample.new(sample_data)
39
+ elsif enterprise == 0 && format == 3
40
+ # @samples << EM::SFlow::ExpandedFlowSample.new(sample_data)
41
+ elsif enterprise == 0 && format == 4
42
+ # @samples << EM::SFlow::ExpandedCounterSample.new(sample_data)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,9 @@
1
+ class EventMachine::SFlow::EthernetInterfaceCounters
2
+ attr_accessor :alignment_errors, :fcs_errors, :single_collision_frames, :multiple_collision_frames, :sqe_test_errors, :deferred_transmissions, :late_collisions, :excessive_collisions, :internal_mac_transmit_errors, :carrier_sense_errors, :frames_too_long, :internal_mac_receive_errors, :symbol_errors
3
+
4
+ def initialize data
5
+ data.extend EventMachine::SFlow::BinaryString
6
+
7
+ @alignment_errors, @fcs_errors, @single_collision_frames, @multiple_collision_frames, @sqe_test_errors, @deferred_transmissions, @late_collisions, @excessive_collisions, @internal_mac_transmit_errors, @carrier_sense_errors, @frames_too_long, @internal_mac_receive_errors, @symbol_errors = data.unpack("NNNNNNNNNNNNN")
8
+ end
9
+ end
@@ -0,0 +1,61 @@
1
+ class EventMachine::SFlow::FlowSample
2
+ attr_accessor :sequence_number, :source_class, :source_value, :sampling_rate, :sample_pool, :drop_count, :input_count, :output_count, :records
3
+
4
+ def initialize data
5
+ data.extend EM::SFlow::BinaryString
6
+
7
+ @records = []
8
+
9
+ @sequence_number, source_id_class_value, @sampling_rate, @sample_pool, @drop_count, @input_count, @output_count, record_count = data.unpack("NNNNNNNN")
10
+
11
+ @source_class = source_id_class_value >> 24
12
+ @source_value = source_id_class_value & (2 ** 24 - 1)
13
+
14
+ data.advance(32)
15
+
16
+ record_count.times do
17
+ enterprise_format, length = data.unpack("NN")
18
+
19
+ enterprise = enterprise_format >> 12
20
+ format = enterprise_format & (2 ** 12 - 1)
21
+
22
+ data.advance(8)
23
+
24
+ record_data = data.advance(length)
25
+
26
+ if enterprise == 0 && format == 1
27
+ @records << EM::SFlow::RawPacketHeader.new(record_data)
28
+ elsif enterprise == 0 && format == 2
29
+ # @records << EM::SFlow::EthernetFrameData.new(record_data)
30
+ elsif enterprise == 0 && format == 3
31
+ # @records << EM::SFlow::IPv4Data.new(record_data)
32
+ elsif enterprise == 0 && format == 4
33
+ # @records << EM::SFlow::IPv6Data.new(record_data)
34
+ elsif enterprise == 0 && format == 1001
35
+ # @records << EM::SFlow::ExtendedSwitchData.new(record_data)
36
+ elsif enterprise == 0 && format == 1002
37
+ # @records << EM::SFlow::ExtendedRouterData.new(record_data)
38
+ elsif enterprise == 0 && format == 1003
39
+ # @records << EM::SFlow::ExtendedGatewayData.new(record_data)
40
+ elsif enterprise == 0 && format == 1004
41
+ # @records << EM::SFlow::ExtendedUserData.new(record_data)
42
+ elsif enterprise == 0 && format == 1005
43
+ # @records << EM::SFlow::ExtendedUrlData.new(record_data)
44
+ elsif enterprise == 0 && format == 1006
45
+ # @records << EM::SFlow::ExtendedMplsData.new(record_data)
46
+ elsif enterprise == 0 && format == 1007
47
+ # @records << EM::SFlow::ExtendedNatData.new(record_data)
48
+ elsif enterprise == 0 && format == 1008
49
+ # @records << EM::SFlow::ExtendedMplsTunnel.new(record_data)
50
+ elsif enterprise == 0 && format == 1009
51
+ # @records << EM::SFlow::ExtendedMplsVc.new(record_data)
52
+ elsif enterprise == 0 && format == 1010
53
+ # @records << EM::SFlow::ExtendedMplsFec.new(record_data)
54
+ elsif enterprise == 0 && format == 1011
55
+ # @records << EM::SFlow::ExtendedMplsLvpFec.new(record_data)
56
+ elsif enterprise == 0 && format == 1012
57
+ # @records << EM::SFlow::ExtendedVlanTunnel.new(record_data)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,26 @@
1
+ class EventMachine::SFlow::GenericInterfaceCounters
2
+ attr_accessor :if_index, :if_type, :if_speed, :if_direction, :if_admin_status, :if_oper_status, :if_in_octets, :if_in_ucast_pkts, :if_in_mcast_pkts, :if_in_bcast_pkts, :if_in_discards, :if_in_errors, :if_in_unknown_protocols, :if_out_octets, :if_out_ucast_pkts, :if_out_mcast_pkts, :if_out_bcast_pkts, :if_out_discards, :if_out_errors, :if_promiscuous
3
+
4
+ def initialize data
5
+ data.extend EventMachine::SFlow::BinaryString
6
+
7
+ @if_index, @if_type, if_speed_a, if_speed_b, @if_direction, if_status = data.unpack("NNNNNN")
8
+ @if_speed = (if_speed_a << 32) + if_speed_b
9
+ @if_admin_status = (if_status >> 31) && 1
10
+ @if_oper_status = (if_status >> 30) && 1
11
+
12
+ data.advance(24)
13
+
14
+ if_in_octets_a, if_in_octets_b, @if_in_ucast_pkts, @if_in_mcast_pkts, @if_in_bcast_pkts, @if_in_discards, @if_in_errors, @if_in_unknown_protocols = data.unpack("NNNNNNNN")
15
+ @if_in_octets = (if_in_octets_a << 32) + if_in_octets_b
16
+
17
+ data.advance(32)
18
+
19
+ if_out_octets_a, if_out_octets_b, @if_out_ucast_pkts, @if_out_mcast_pkts, @if_out_bcast_pkts, @if_out_discards, @if_out_errors = data.unpack("NNNNNNN")
20
+ @if_out_octets = (if_out_octets_a << 32) + if_out_octets_b
21
+
22
+ data.advance(28)
23
+
24
+ @if_promiscuous = data.unpack("N").first
25
+ end
26
+ end
@@ -0,0 +1,12 @@
1
+ class EventMachine::SFlow::RawPacketHeader
2
+ attr_accessor :protocol, :frame_length, :strip_count, :header
3
+
4
+ def initialize data
5
+ data.extend EventMachine::SFlow::BinaryString
6
+
7
+ @protocol, @frame_length, @strip_count, length = data.unpack("NNNN")
8
+ data.advance(16)
9
+
10
+ @header = data
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ module EventMachine
2
+ module SFlow
3
+ VERSION = "1.0.1"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: em-sflow
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Norman Elton
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: eventmachine
16
+ requirement: &70342806966360 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.12.10
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70342806966360
25
+ description: EventMachine-powered sFlow Collector
26
+ email:
27
+ - normelton@gmail.com
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files:
31
+ - README.rdoc
32
+ files:
33
+ - .gitignore
34
+ - Gemfile
35
+ - LICENSE
36
+ - README.rdoc
37
+ - Rakefile
38
+ - em-sflow.gemspec
39
+ - lib/em-sflow.rb
40
+ - lib/em-sflow/binary_string.rb
41
+ - lib/em-sflow/collector.rb
42
+ - lib/em-sflow/datagram_handler.rb
43
+ - lib/em-sflow/packet/counter_sample.rb
44
+ - lib/em-sflow/packet/datagram.rb
45
+ - lib/em-sflow/packet/ethernet_interface_counters.rb
46
+ - lib/em-sflow/packet/flow_sample.rb
47
+ - lib/em-sflow/packet/generic_interface_counters.rb
48
+ - lib/em-sflow/packet/raw_packet_header.rb
49
+ - lib/em-sflow/version.rb
50
+ homepage: http://github.com/normelton/em-sflow
51
+ licenses: []
52
+ post_install_message:
53
+ rdoc_options:
54
+ - --line-numbers
55
+ - --inline-source
56
+ - --title
57
+ - EM-SFLOW
58
+ - --main
59
+ - README.rdoc
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 1.8.5
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: EventMachine-powered sFlow Collector
80
+ test_files: []