ovsimager 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5a4813849f38c8999ec90b9f68e1607e681681e9
4
+ data.tar.gz: c08b1ec71b6b0a1b5e04c459bdc4f7238823edab
5
+ SHA512:
6
+ metadata.gz: 9a270e213b0422701c25006ee62397d623ecfd5c19a483459936c2da2f38e7c62abce02afc83634c25f618fbb76e196c3474dd3b83e24868452381e54aa0de42
7
+ data.tar.gz: adcdff1ffb9073c446e171c64592e41247eb51e21978bd7a4591bb38b3ac77fe78092891f6fbbb09ce44461a6e55f7579a486f8ea996f0d0509686555bd062a4
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ *.dot
15
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ovsimager.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Tomoki Sekiyama
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,48 @@
1
+ # OVSImager
2
+
3
+ OVSImager draws a graph that describes relationship among Open vSwitch
4
+ bridges, Linux bridges, and namespaces for routing. It can also mark
5
+ the ports where ping packets went through using tcpdump, which is a
6
+ useful feature for trouble-shooting in SDN environments.
7
+
8
+ ## Installation
9
+
10
+ $ gem install ovsimager
11
+ # sudo yum install graphviz
12
+
13
+ ## Usage
14
+
15
+ ### Draw a graph of Open vSwitch'es
16
+
17
+ $ ovsimager
18
+ ( => interfaces.png will be generated. )
19
+
20
+ ![sample](sample-interfaces.png)
21
+
22
+ ### Trace ping packets
23
+
24
+ Execute ping packet with size = 400 byte, and trace them:
25
+
26
+ $ ping -s 400 192.0.2.1
27
+ $ sudo ovsimager -d
28
+ ( => interfaces.png will be generated. )
29
+
30
+ ![sample](sample-ping-trace.png)
31
+
32
+ Or, ovsimager also can send ping:
33
+
34
+ $ sudo ovsimager -d -f 10.0.0.1 -t 192.0.2.1
35
+
36
+ Colors:
37
+
38
+ - Yellow => both 'ping' and 'pong' are went through
39
+ - Pink => only 'ping' is went through
40
+ - Red => only 'pong' is went through
41
+
42
+ ## Contributing
43
+
44
+ 1. Fork it ( https://github.com/NeoCat/ovsimager/fork )
45
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
46
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
47
+ 4. Push to the branch (`git push origin my-new-feature`)
48
+ 5. Create a new Pull Request
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
7
+
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib_dir = File.join(File.dirname(__FILE__), '..', 'lib')
4
+ $LOAD_PATH.unshift lib_dir if File.directory?(lib_dir)
5
+
6
+ require 'ovsimager'
7
+
8
+ ovsimager = OVSImager::OVSImager.new
9
+ ovsimager.parse_options
10
+ ovsimager.execute_dump
11
+ ovsimager.show_all
@@ -0,0 +1,2 @@
1
+ require "ovsimager/version"
2
+ require "ovsimager/ovsimager"
@@ -0,0 +1,86 @@
1
+ module OVSImager
2
+ class DotWriter
3
+ def initialize(fname)
4
+ @fname = fname
5
+ @dot = File.open(fname, 'w')
6
+ @dot.puts 'graph interfaces {'
7
+ @dot.puts ' compound=true'
8
+ @dot.puts ' node [shape=rect]'
9
+ @dot_peers = []
10
+ end
11
+
12
+ def escape(name)
13
+ name.to_s.gsub('-', '_')
14
+ end
15
+
16
+ def mark2color(mark)
17
+ {'<' => 'red', '>' => 'pink', '*' => 'yellow'}[mark]
18
+ end
19
+
20
+ def finish(pngname)
21
+ @dot.puts @dot_peers.join "\n"
22
+ @dot.puts '}'
23
+ @dot.close
24
+ @dot = nil
25
+ system("dot -Tpng \"#{@fname}\" -o \"#{pngname}\"")
26
+ end
27
+
28
+ # For OVSVS & LinuxBridge
29
+ def br_begin(name, br_type)
30
+ @dot.puts " subgraph cluster_br__#{escape(name)} {"
31
+ @dot.puts " label = \"#{br_type}Bridge #{name}\""
32
+ end
33
+
34
+ def br_iface(name, mark, dump, inet, tag, peer, remote=nil)
35
+ fill = mark ? "fillcolor=#{mark2color(mark)},style=filled," : ''
36
+ label = "#{name}<BR/><FONT POINT-SIZE=\"10\">#{inet.join(',')}"
37
+ if tag or remote
38
+ label += "<BR/>#{tag}#{remote && remote.gsub('>','&gt;')}"
39
+ end
40
+ if dump
41
+ label += " </FONT><FONT COLOR=\"blue\">"
42
+ if dump[0] && dump[2] && dump[0] == dump[3] && dump[1] == dump[2]
43
+ label += "<BR/>[#{dump[0]} &lt;-&gt; #{dump[1]}]"
44
+ else
45
+ label += "<BR/>[#{dump[0]} --&gt; #{dump[1]}]" if dump[0]
46
+ label += "<BR/>[#{dump[3]} &lt;-- #{dump[2]}]" if dump[2]
47
+ end
48
+ end
49
+ label += " </FONT>"
50
+ @dot.puts " #{escape(name)} [#{fill}label=<#{label}>]"
51
+ if peer && name <= peer
52
+ @dot_peers << " #{escape(name)} -- #{escape(peer)}"
53
+ end
54
+ end
55
+
56
+ def br_end
57
+ @dot.puts " }"
58
+ end
59
+
60
+ # For IPNetNS
61
+ def ns_begin(name)
62
+ @dot.puts " subgraph cluster_ns__#{escape(name)} {"
63
+ @dot.puts " label = \"Namespace\\n#{name}\""
64
+ @dot.puts " style = \"filled\""
65
+ @dot.puts " fillcolor = \"#eeeeee\""
66
+ @dot.puts " ns__#{escape(name)} " +
67
+ "[label=\"\",style=invis,width=0,height=0,margin=0]"
68
+ @nsname = name
69
+ end
70
+
71
+ def ns_br_iface(name)
72
+ @dot_peers << " #{escape(name)} -- ns__#{escape(@nsname)} " +
73
+ "[style=dashed,lhead=cluster_ns__#{escape(@nsname)}]"
74
+ end
75
+
76
+ def ns_iface(name, mark, dump, inet, tag, peer)
77
+ br_iface(name, mark, dump, inet, tag, peer)
78
+ # @dot.puts " #{escape(name)} -- #{escape(@last)} [style=invis]" if @last
79
+ # @last = name
80
+ end
81
+
82
+ def ns_end
83
+ @dot.puts ' }'
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,97 @@
1
+ require_relative 'utils'
2
+
3
+ module OVSImager
4
+ class IPNetNS
5
+ def initialize()
6
+ @ns = exec_ip('netns').split(/\n/)
7
+ @ifaces = {:root => parse_address(exec_ip('a'), :root)}
8
+ links = parse_link(exec_ip('-d link'), :root)
9
+ merge_link_type(@ifaces[:root], links)
10
+ @ns.each {|ns|
11
+ out = exec_ip("netns exec #{ns} ip a", true)
12
+ @ifaces[ns] = parse_address(out, ns)
13
+ out = exec_ip("netns exec #{ns} ip -d link", true)
14
+ links = parse_link(out, ns)
15
+ merge_link_type(@ifaces[ns], links)
16
+ }
17
+ find_veth_pair
18
+ end
19
+
20
+ def to_hash()
21
+ @ifaces
22
+ end
23
+
24
+ def ifaces_hash()
25
+ @ifaces.inject({}) {|h, (ns, v)| v.each {|i| h[i[:name]] = i}; h}
26
+ end
27
+
28
+ def ifaces_ary()
29
+ @ifaces.inject([]) {|a, (ns, v)| v.each {|i| a[i[:id].to_i] = i}; a}
30
+ end
31
+
32
+ def exec_ip(args, root=false)
33
+ Utils.execute("ip #{args}", root)
34
+ end
35
+
36
+ private
37
+ def parse(out, args)
38
+ out.split(/\n(?=[^ \s])/).map do |iface|
39
+ if iface.match(/^(\d+):\s+(\S+?):+/)
40
+ params = {:id => $1, :name => $2}
41
+ yield params, iface, args
42
+ else
43
+ STDERR.puts "IPNetNS: parse error: #{iface}"
44
+ {}
45
+ end
46
+ end
47
+ end
48
+
49
+ def parse_address(out, ns)
50
+ parse(out, ns) do |params, iface, ns|
51
+ params[:ns] = ns
52
+ params[:mac] = $1 if iface.match(/link\/\w+ (\S+)/)
53
+ [:inet, :inet6].each do |key|
54
+ params[key] = iface.scan(/#{key.to_s} (\S+)/)
55
+ end
56
+ [:mtu, :state].each do |key|
57
+ params[key] = $1 if iface.match(/#{key.to_s} (\S+)/)
58
+ end
59
+ params
60
+ end
61
+ end
62
+
63
+ def parse_link(out, ns)
64
+ parse(out, ns) do |params, iface, ns|
65
+ params[:ns] = ns
66
+ params[:mac] = $1 if iface.match(/link\/\w+ (\S+)/)
67
+ params[:type] = (iface.split(/\n/)[2] || '').strip
68
+ params
69
+ end
70
+ end
71
+
72
+ def merge_link_type(ifaces, links)
73
+ link_types = links.inject({}) {|h, link| h[link[:id]] = link[:type]; h}
74
+ ifaces.each {|iface| iface[:type] = link_types[iface[:id]]}
75
+ end
76
+
77
+ def find_veth_pair()
78
+ ifaces = ifaces_ary
79
+ ifaces.each do |iface|
80
+ next unless iface
81
+ if iface[:type] == 'veth' && !iface[:peer]
82
+ if iface[:ns] == :root
83
+ out = Utils::execute("ethtool -S #{iface[:name]}")
84
+ else
85
+ out = exec_ip("netns exec #{iface[:ns]} ethtool -S #{iface[:name]}", root=true)
86
+ end
87
+ if out.match /peer_ifindex: (\d+)/
88
+ iface[:peer] = ifaces[$1.to_i][:name]
89
+ ifaces[$1.to_i][:peer] = iface[:name]
90
+ else
91
+ STDERR.puts("Failed to lookup veth peer of '#{iface[:name]}'")
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,33 @@
1
+ require_relative 'utils'
2
+
3
+ module OVSImager
4
+ class LinuxBridge
5
+ def initialize()
6
+ brctl_out = exec_brtcl
7
+ @br = parse brctl_out
8
+ end
9
+
10
+ def to_hash()
11
+ return @br
12
+ end
13
+
14
+ def exec_brtcl()
15
+ Utils.execute('brctl show')
16
+ end
17
+
18
+ private
19
+ def parse(str)
20
+ params = {}
21
+ str.split(/\n(?=\S)/)[1..-1].map do |br|
22
+ data = br.split
23
+ params[data[0]] = {
24
+ :name => data[0],
25
+ :id => data[1],
26
+ :stp => data[2],
27
+ :interfaces => [data[0]] + data[3..-1],
28
+ }
29
+ end
30
+ params
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,145 @@
1
+ require 'optparse'
2
+ require_relative 'ovsvs'
3
+ require_relative 'linuxbridge'
4
+ require_relative 'ipnetns'
5
+ require_relative 'tcpdump'
6
+ require_relative 'dotwriter'
7
+
8
+ module OVSImager
9
+ class OVSImager
10
+ DOT_FILENAME = 'interfaces.dot'
11
+ PNG_FILENAME = 'interfaces.png'
12
+
13
+ def initialize(dump_mode=false, ping_from=nil, ping_to=nil)
14
+ @netns = IPNetNS.new
15
+ @ifaces = @netns.ifaces_hash
16
+ @linbr = LinuxBridge.new
17
+ @ovsvs = OVSVS.new
18
+
19
+ @dotwriter = DotWriter.new(DOT_FILENAME)
20
+
21
+ @dump_mode = dump_mode
22
+ @mark = {}
23
+ @dump_result = {}
24
+ @ping_from = ping_from
25
+ @ping_to = ping_to
26
+ @done = {'lo' => true}
27
+ end
28
+
29
+ def parse_options
30
+ OptionParser.new do |opts|
31
+ opts.banner = "Usage: #$0 [options]"
32
+ opts.on("-d", "--dump",
33
+ "enable dump mode (trace ping -s 400 packets)") do
34
+ @dump_mode = true
35
+ end
36
+ opts.on("-f ADDRESS", "--from ADDRESS",
37
+ "send ping from specified address") do |v|
38
+ @ping_from = v
39
+ end
40
+ opts.on("-t ADDRESS", "--to ADDRESS",
41
+ "send ping to specified address") do |v|
42
+ @ping_to = v
43
+ end
44
+ end.parse!
45
+ end
46
+
47
+ def execute_dump
48
+ return unless @dump_mode
49
+ tcpdump = TcpDump.new(@ping_from && @ping_to, @ping_from, @ping_to)
50
+ @dump_result = tcpdump.test(@ifaces)
51
+ @dump_result.each do |(iface, result)|
52
+ if result[0] && result[2]
53
+ @mark[iface] = '*'
54
+ elsif result[0]
55
+ @mark[iface] = '>'
56
+ elsif result[2]
57
+ @mark[iface] = '<'
58
+ end
59
+ end
60
+ end
61
+
62
+ def show_all
63
+ show_ovsvs
64
+ puts '-' * 80
65
+ show_linbr
66
+ puts '-' * 80
67
+ show_netns
68
+ @dotwriter.finish(PNG_FILENAME) if @dotwriter
69
+ @dotwriter = nil
70
+ end
71
+
72
+ private
73
+ def show_iface_common(name, inet, patch, tag='', ns='')
74
+ puts " [#{@mark[name]||' '}] #{name}#{tag}#{patch}\t" +
75
+ "#{inet.join(',')}\t#{ns}"
76
+ end
77
+
78
+ def show_iface(iface)
79
+ patch = iface[:peer] ? " <-> #{iface[:peer]}" : ''
80
+ show_iface_common(iface[:name], iface[:inet], patch)
81
+ end
82
+
83
+ def show_ovsvs
84
+ @ovsvs.to_hash[:bridges].each do |br|
85
+ puts "OVS Bridge #{br[:name]}:"
86
+ @dotwriter.br_begin(br[:name], 'OVS ')
87
+
88
+ br[:ports].each do |port|
89
+ name = port[:name]
90
+ iface = @ifaces[name] || {}
91
+ inet = iface[:inet] || []
92
+ tag = port[:tag] ? ' (tag=' + port[:tag] + ')' : ''
93
+ peer = port[:peer] || iface[:peer]
94
+ remote = port[:remote_ip] ?
95
+ " #{port[:local_ip] || ''} => #{port[:remote_ip]}" : ''
96
+ patch = peer ? ' <-> ' + peer : remote
97
+ ns = iface[:ns] == :root ? '' : iface[:ns]
98
+
99
+ show_iface_common(name, inet, patch, tag, ns)
100
+ @dotwriter.br_iface(name, @mark[name], @dump_result[name],
101
+ inet, tag, peer, remote)
102
+ @done[name] = true
103
+ end
104
+ @dotwriter.br_end
105
+ end
106
+ end
107
+
108
+ def show_linbr
109
+ @linbr.to_hash.each do |name, br|
110
+ puts "Bridge #{name}"
111
+ @dotwriter.br_begin(name, '')
112
+ br[:interfaces].each do |ifname|
113
+ iface = @ifaces[ifname]
114
+ @dotwriter.br_iface(ifname, @mark[ifname], @dump_result[ifname],
115
+ iface[:inet], iface[:tag], iface[:peer])
116
+ show_iface iface
117
+ @done[ifname] = true
118
+ end
119
+ @dotwriter.br_end
120
+ end
121
+ end
122
+
123
+ def show_netns
124
+ @netns.to_hash.each do |name, ifaces|
125
+ puts "Namespace #{name}"
126
+ @dotwriter.ns_begin(name)
127
+ ifaces.each do |iface|
128
+ ifname = iface[:name]
129
+ if ifname != 'lo' and !iface[:inet].empty?
130
+ if @done[ifname]
131
+ @dotwriter.ns_br_iface(ifname)
132
+ else
133
+ @dotwriter.ns_iface(ifname, @mark[ifname], @dump_result[ifname],
134
+ iface[:inet], iface[:tag], iface[:peer])
135
+ end
136
+ end
137
+ show_iface iface unless @done[iface[:name]]
138
+ @done[iface[:name]] = true
139
+ end
140
+ @dotwriter.ns_end
141
+ end
142
+ end
143
+
144
+ end
145
+ end
@@ -0,0 +1,72 @@
1
+ require_relative 'utils'
2
+
3
+ module OVSImager
4
+ class OVSVS
5
+ def initialize()
6
+ vsctl_out = exec_vstcl
7
+ @vs = parse(vsctl_out, ['bridge', 'port', 'interface'])
8
+ @vs[:bridges] ||= []
9
+
10
+ # Mark the peer port.
11
+ @vs[:bridges].each do |br|
12
+ br[:ports].each do |port|
13
+ iface = port[:interfaces][0]
14
+ if iface[:type] == 'patch' && iface[:options].match(/peer="?(\S+?)"?[,\}]/)
15
+ port[:peer] = $1
16
+ end
17
+ if iface[:type] == 'gre' || iface[:type] == 'vxlan'
18
+ if iface[:options].match(/remote_ip="?(\S+?)"?[,\}]/)
19
+ port[:remote_ip] = $1
20
+ end
21
+ if iface[:options].match(/local_ip="?(\S+?)"?[,\}]/)
22
+ port[:local_ip] = $1
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ # Move the port that has the same name with the interface to first.
29
+ @vs[:bridges].each do |vs|
30
+ vs[:ports].sort!{|a, b|
31
+ vs[:name] == a[:name] ? -1 : vs[:name] == b[:name] ? 1 :
32
+ a[:ns] == b[:ns] ? a[:name] <=> b[:name] : a[:ns] <=> b[:ns]
33
+ }
34
+ end
35
+ end
36
+
37
+ def to_hash()
38
+ return @vs
39
+ end
40
+
41
+ def exec_vstcl()
42
+ begin
43
+ Utils.execute('ovs-vsctl show', root=true)
44
+ rescue
45
+ ''
46
+ end
47
+ end
48
+
49
+ private
50
+ def parse(str, types)
51
+ name, attrs = str.split(/\n/, 2)
52
+ return {} unless name
53
+ name.gsub!(/^\"|\"$/, '')
54
+ params = {:name => name}
55
+ return params unless attrs
56
+
57
+ indent = attrs.match(/^(\s*)/)[1]
58
+ attrs.gsub!(/^#{indent}([^ ]*):\s+"?(.*?)"?\s*(?:$|\n)/) do |m|
59
+ params[$1.to_sym] = $2
60
+ ''
61
+ end
62
+ return params if types.empty?
63
+
64
+ params[(types[0]+'s').downcase.to_sym] =
65
+ attrs.split(/\s+#{types[0]} /i)[1..-1].map do |cstr|
66
+ parse(cstr, types[1..-1])
67
+ end
68
+
69
+ return params
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,64 @@
1
+ require 'time'
2
+
3
+ module OVSImager
4
+ class TcpDump
5
+ SIZE = 400
6
+ def initialize(ping=false, from=nil, to=nil)
7
+ throw 'must be root.' if Process::UID.eid != 0
8
+ @ping = ping
9
+ @from = from
10
+ @to = to
11
+ end
12
+
13
+ def test(ifaces)
14
+ result = {}
15
+ ping = nil
16
+ if @ping
17
+ puts "Sending ping from #{@from} to #{@to} ..."
18
+ ping = IO.popen("ping -s #{SIZE} -c 15 -I #{@from} #{@to} >/dev/null", "r")
19
+ end
20
+
21
+ threads = ifaces.map do |(iface, iref)|
22
+ Thread.new do
23
+ Thread.current[:iface] = iface
24
+ ns = iref[:ns]
25
+ nscmd = ns == :root ? '' : "ip netns exec #{ns} "
26
+ dump = IO.popen("exec #{nscmd}tcpdump -v -l -n -i #{iface} \\( icmp or udp port 4789 \\) and greater #{SIZE} 2>&1", "r")
27
+ puts dump.gets
28
+ time_end = Time.now + 5
29
+ req_from = req_to = rep_from = rep_to = nil
30
+ while (waitmax = time_end - Time.now) > 0 do
31
+ rs, ws, = IO.select([dump], [], [], waitmax)
32
+ break unless rs
33
+ if r = rs[0]
34
+ msg = r.gets
35
+ break unless msg
36
+ # puts msg
37
+ if msg.match(/length #{SIZE+8}/) &&
38
+ msg.match(/([\da-f\.:]+) > ([\da-f\.:]+): ICMP echo (request|reply)/)
39
+ if $3 == 'request'
40
+ req_from = $1
41
+ req_to = $2
42
+ else
43
+ rep_from = $1
44
+ rep_to = $2
45
+ end
46
+ break if req_from && req_to && rep_from && rep_to
47
+ end
48
+ end
49
+ end
50
+ puts "Killing tcpdump(#{dump.pid}) on interface #{iface}."
51
+ Process.kill('TERM', dump.pid)
52
+ dump.close
53
+ result[iface] = [req_from, req_to, rep_from, rep_to]
54
+ end
55
+ end
56
+ threads.each {|th| th.join(10)}
57
+ if @ping
58
+ Process.kill('TERM', ping.pid)
59
+ ping.close
60
+ end
61
+ return result
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,19 @@
1
+ require 'open3'
2
+
3
+ module OVSImager
4
+ class Utils
5
+ def self.get_root_helper(root=true)
6
+ return '' if not root or Process::UID.eid == 0
7
+ root ? 'sudo ' : ''
8
+ end
9
+
10
+ def self.execute(cmd, root=false)
11
+ root_helper = self.get_root_helper(root)
12
+ out = `#{root_helper}#{cmd}`
13
+ if $? != 0
14
+ raise "command execution failure: #{$?}"
15
+ end
16
+ return out
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ module OVSImager
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ovsimager/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ovsimager"
8
+ spec.version = OVSImager::VERSION
9
+ spec.authors = ["NeoCat"]
10
+ spec.email = ["neocat@neocat.jp"]
11
+ spec.summary = %q{Draw graph of Open vSwitch virtual bridges.}
12
+ spec.description = %q{OVSImager draws a graph that describes relationship among Open vSwitch bridges, Linux bridges, and namespaces for routing. It can also mark the ports where ping packets went through using tcpdump, which is a useful feature for trouble-shooting in SDN environments. }
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rspec"
24
+ end
Binary file
Binary file
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ovsimager do
4
+ it 'has a version number' do
5
+ expect(Ovsimager::VERSION).not_to be nil
6
+ end
7
+
8
+ it 'does something useful' do
9
+ expect(false).to eq(true)
10
+ end
11
+ end
@@ -0,0 +1,2 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'ovsimager'
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ovsimager
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - NeoCat
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-08-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: 'OVSImager draws a graph that describes relationship among Open vSwitch
56
+ bridges, Linux bridges, and namespaces for routing. It can also mark the ports where
57
+ ping packets went through using tcpdump, which is a useful feature for trouble-shooting
58
+ in SDN environments. '
59
+ email:
60
+ - neocat@neocat.jp
61
+ executables:
62
+ - ovsimager
63
+ extensions: []
64
+ extra_rdoc_files: []
65
+ files:
66
+ - ".gitignore"
67
+ - ".rspec"
68
+ - ".travis.yml"
69
+ - Gemfile
70
+ - LICENSE.txt
71
+ - README.md
72
+ - Rakefile
73
+ - bin/ovsimager
74
+ - lib/ovsimager.rb
75
+ - lib/ovsimager/dotwriter.rb
76
+ - lib/ovsimager/ipnetns.rb
77
+ - lib/ovsimager/linuxbridge.rb
78
+ - lib/ovsimager/ovsimager.rb
79
+ - lib/ovsimager/ovsvs.rb
80
+ - lib/ovsimager/tcpdump.rb
81
+ - lib/ovsimager/utils.rb
82
+ - lib/ovsimager/version.rb
83
+ - ovsimager.gemspec
84
+ - sample-interfaces.png
85
+ - sample-ping-trace.png
86
+ - spec/ovsimager_spec.rb
87
+ - spec/spec_helper.rb
88
+ homepage: ''
89
+ licenses:
90
+ - MIT
91
+ metadata: {}
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubyforge_project:
108
+ rubygems_version: 2.2.3
109
+ signing_key:
110
+ specification_version: 4
111
+ summary: Draw graph of Open vSwitch virtual bridges.
112
+ test_files:
113
+ - spec/ovsimager_spec.rb
114
+ - spec/spec_helper.rb