phut 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.hound.yml +3 -0
- data/.rubocop.yml +6 -0
- data/CHANGELOG.md +5 -0
- data/Rakefile +1 -1
- data/bin/phut +3 -3
- data/bin/vhost +87 -0
- data/features/dsl.feature +1 -1
- data/features/step_definitions/phut_steps.rb +1 -1
- data/lib/phut.rb +1 -1
- data/lib/phut/configuration.rb +2 -2
- data/lib/phut/raw_socket.rb +26 -0
- data/lib/phut/setting.rb +1 -1
- data/lib/phut/syntax.rb +1 -1
- data/lib/phut/version.rb +1 -1
- data/lib/phut/vhost.rb +73 -0
- data/lib/phut/vhost_daemon.rb +148 -0
- data/phut.gemspec +2 -2
- data/spec/phut/parser_spec.rb +2 -2
- metadata +10 -39
- data/lib/phut/cli.rb +0 -61
- data/lib/phut/phost.rb +0 -92
- data/tasks/vhost.rake +0 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b2838869618793f7529456e67f55820c6312fd4
|
4
|
+
data.tar.gz: b38be67f933c105564abad75ffe2c9e545787757
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b19c285acc17e89ee19d803c1f161b741cfbd1305692af023f057aac4f06a3a7c37d0d84c31e6cfb52d0d02a2024c76609a495de38ff756cba6d2f2761369eef
|
7
|
+
data.tar.gz: 3f51908add6cd7e341ed596c2dad7d361b3838ad70337d232248d55b1fc8795f3b7b533e1147f7bba875643b5618ac9a77f590f04657d9da3dbf83d7ccd0e331
|
data/.hound.yml
ADDED
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/Rakefile
CHANGED
@@ -2,7 +2,7 @@ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), 'lib')
|
|
2
2
|
|
3
3
|
require 'rake/clean'
|
4
4
|
|
5
|
-
task default:
|
5
|
+
task default: :openvswitch
|
6
6
|
task test: [:spec, :cucumber, :quality]
|
7
7
|
task quality: [:rubocop, :reek, :flog]
|
8
8
|
task travis: [:spec, 'cucumber:travis', :quality]
|
data/bin/phut
CHANGED
@@ -62,9 +62,9 @@ module Phut
|
|
62
62
|
logger.formatter = proc { |_sev, _dtm, _name, msg| msg + "\n" }
|
63
63
|
logger.level = global_options[:verbose] ? Logger::DEBUG : Logger::INFO
|
64
64
|
end
|
65
|
-
Phut.pid_dir = options
|
66
|
-
Phut.log_dir = options
|
67
|
-
Phut.socket_dir = options
|
65
|
+
Phut.pid_dir = options.fetch(:pid_dir)
|
66
|
+
Phut.log_dir = options.fetch(:log_dir)
|
67
|
+
Phut.socket_dir = options.fetch(:socket_dir)
|
68
68
|
Phut::Parser.new(stdout_logger).parse(args[0]).run
|
69
69
|
end
|
70
70
|
end
|
data/bin/vhost
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
3
|
+
|
4
|
+
require 'gli'
|
5
|
+
require 'phut'
|
6
|
+
|
7
|
+
module Phut
|
8
|
+
class VhostDaemon
|
9
|
+
# /bin/vhost command
|
10
|
+
module App
|
11
|
+
extend GLI::App
|
12
|
+
|
13
|
+
version Phut::VERSION
|
14
|
+
|
15
|
+
desc 'Runs a vhost process'
|
16
|
+
command :run do |c|
|
17
|
+
desc 'Host name'
|
18
|
+
c.flag [:n, :name]
|
19
|
+
desc 'Network interface'
|
20
|
+
c.flag [:I, :interface]
|
21
|
+
desc 'IP address'
|
22
|
+
c.flag [:i, :ip_address]
|
23
|
+
desc 'MAC address'
|
24
|
+
c.flag [:m, :mac_address]
|
25
|
+
c.desc 'ARP entries'
|
26
|
+
c.flag [:a, :arp_entries], negatable: false
|
27
|
+
c.desc 'Promisc mode'
|
28
|
+
c.switch [:p, :promisc], negatable: false
|
29
|
+
|
30
|
+
c.desc 'Location to put pid files'
|
31
|
+
c.flag [:P, :pid_dir], default_value: Phut.pid_dir
|
32
|
+
c.desc 'Location to put log files'
|
33
|
+
c.flag [:L, :log_dir], default_value: Phut.log_dir
|
34
|
+
c.desc 'Location to put socket files'
|
35
|
+
c.flag [:S, :socket_dir], default_value: Phut.socket_dir
|
36
|
+
|
37
|
+
c.action do |_global_options, options, _args|
|
38
|
+
fail '--name option is mandatory' if options[:name].nil?
|
39
|
+
fail '--interface option is mandatory' if options[:interface].nil?
|
40
|
+
fail '--ip_address option is mandatory' if options[:ip_address].nil?
|
41
|
+
fail '--mac_address option is mandatory' if options[:mac_address].nil?
|
42
|
+
options[:arp_table] =
|
43
|
+
options[:arp_entries].split(',').
|
44
|
+
each_with_object({}) do |each, table|
|
45
|
+
ip_address, mac_address = each.split('/')
|
46
|
+
table[ip_address] = mac_address
|
47
|
+
end
|
48
|
+
VhostDaemon.new(options).run
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
desc 'Terminates a vhost process'
|
53
|
+
command :stop do |c|
|
54
|
+
desc 'Host name'
|
55
|
+
c.flag [:n, :name]
|
56
|
+
|
57
|
+
c.desc 'Location to put socket files'
|
58
|
+
c.flag [:S, :socket_dir], default_value: Phut.socket_dir
|
59
|
+
|
60
|
+
c.action do |_global_options, options, _args|
|
61
|
+
fail '--name option is mandatory' if options[:name].nil?
|
62
|
+
begin
|
63
|
+
VhostDaemon.process(options[:name], options[:socket_dir]).stop
|
64
|
+
rescue DRb::DRbConnError
|
65
|
+
true # OK
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
desc 'Sends UDP packets to destination host'
|
71
|
+
command :send_packets do |c|
|
72
|
+
desc 'Source host name'
|
73
|
+
c.flag [:s, :source]
|
74
|
+
|
75
|
+
c.action do |_global_options, options, _args|
|
76
|
+
fail '--source option is mandatory' if options[:source].nil?
|
77
|
+
VhostDaemon.process(options[:source], options[:socket_dir]).
|
78
|
+
send_packets
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
default_command :help
|
83
|
+
|
84
|
+
exit run(ARGV)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/features/dsl.feature
CHANGED
@@ -22,5 +22,5 @@ Feature: DSL parser
|
|
22
22
|
Then the exit status should not be 0
|
23
23
|
And the stderr should contain:
|
24
24
|
"""
|
25
|
-
The name 192.168.0.1 conflicts with vhost (name = 192.168.0.1,
|
25
|
+
The name 192.168.0.1 conflicts with vhost (name = 192.168.0.1, IP address = 192.168.0.1).
|
26
26
|
"""
|
@@ -15,7 +15,7 @@ end
|
|
15
15
|
|
16
16
|
Then(/^a vhost named "(.*?)" launches$/) do |name|
|
17
17
|
in_current_dir do
|
18
|
-
pid_file = File.join(File.expand_path(@pid_dir), "
|
18
|
+
pid_file = File.join(File.expand_path(@pid_dir), "vhost.#{name}.pid")
|
19
19
|
step %(a file named "#{pid_file}" should exist)
|
20
20
|
end
|
21
21
|
end
|
data/lib/phut.rb
CHANGED
data/lib/phut/configuration.rb
CHANGED
@@ -19,7 +19,7 @@ module Phut
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def vhosts
|
22
|
-
@all.values.select { |each| each.is_a?
|
22
|
+
@all.values.select { |each| each.is_a? Vhost }
|
23
23
|
end
|
24
24
|
|
25
25
|
def links
|
@@ -45,7 +45,7 @@ module Phut
|
|
45
45
|
|
46
46
|
def add_vhost(name, attrs)
|
47
47
|
check_name_conflict name
|
48
|
-
@all[name] =
|
48
|
+
@all[name] = Vhost.new(attrs[:ip], attrs[:promisc], name, @logger)
|
49
49
|
end
|
50
50
|
|
51
51
|
# This method smells of :reek:LongParameterList
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
module Phut
|
4
|
+
# raw socket
|
5
|
+
class RawSocket
|
6
|
+
ETH_P_ALL = 0x0300
|
7
|
+
SIOCGIFINDEX = 0x8933
|
8
|
+
|
9
|
+
def initialize(interface)
|
10
|
+
@socket =
|
11
|
+
Socket.new(Socket::PF_PACKET, Socket::SOCK_RAW, ETH_P_ALL).tap do |sock|
|
12
|
+
ifreq = [interface].pack('a32')
|
13
|
+
sock.ioctl SIOCGIFINDEX, ifreq
|
14
|
+
sock.bind([Socket::AF_PACKET].pack('s').tap do |sll|
|
15
|
+
sll << ([ETH_P_ALL].pack 's')
|
16
|
+
sll << ifreq[16..20]
|
17
|
+
sll << ("\x00" * 12)
|
18
|
+
end)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def method_missing(method, *args)
|
23
|
+
@socket.__send__ method, *args
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/phut/setting.rb
CHANGED
@@ -5,7 +5,7 @@ module Phut
|
|
5
5
|
# Central configuration repository.
|
6
6
|
class Setting
|
7
7
|
DEFAULTS = {
|
8
|
-
root: File.expand_path(File.join(
|
8
|
+
root: File.expand_path(File.join(File.dirname(__FILE__), '..', '..')),
|
9
9
|
pid_dir: Dir.tmpdir,
|
10
10
|
log_dir: Dir.tmpdir,
|
11
11
|
socket_dir: Dir.tmpdir
|
data/lib/phut/syntax.rb
CHANGED
data/lib/phut/version.rb
CHANGED
data/lib/phut/vhost.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'phut/null_logger'
|
2
|
+
require 'phut/setting'
|
3
|
+
require 'phut/shell_runner'
|
4
|
+
require 'pio/mac'
|
5
|
+
|
6
|
+
module Phut
|
7
|
+
# An interface class to vhost emulation utility program.
|
8
|
+
class Vhost
|
9
|
+
include ShellRunner
|
10
|
+
|
11
|
+
attr_reader :ip_address
|
12
|
+
attr_reader :mac_address
|
13
|
+
attr_accessor :interface
|
14
|
+
|
15
|
+
def initialize(ip_address, promisc, name = nil, logger = NullLogger.new)
|
16
|
+
@ip_address = ip_address
|
17
|
+
@promisc = promisc
|
18
|
+
@name = name
|
19
|
+
@mac_address = Pio::Mac.new(rand(0xffffffffffff + 1))
|
20
|
+
@logger = logger
|
21
|
+
end
|
22
|
+
|
23
|
+
def name
|
24
|
+
@name || @ip_address
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
"vhost (name = #{name}, IP address = #{@ip_address})"
|
29
|
+
end
|
30
|
+
|
31
|
+
def run(all_hosts = [])
|
32
|
+
sh "rvmsudo vhost run #{run_options all_hosts}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def stop
|
36
|
+
fail "vhost (name = #{name}) is not running!" unless running?
|
37
|
+
sh "vhost stop -n #{name} -s #{Phut.socket_dir}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def maybe_stop
|
41
|
+
return unless running?
|
42
|
+
stop
|
43
|
+
end
|
44
|
+
|
45
|
+
def running?
|
46
|
+
FileTest.exists?(pid_file)
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def run_options(all_hosts)
|
52
|
+
["-n #{name}",
|
53
|
+
"-I #{interface}",
|
54
|
+
"-i #{@ip_address}",
|
55
|
+
"-m #{@mac_address}",
|
56
|
+
"-a #{arp_entries all_hosts}",
|
57
|
+
@promisc ? '--promisc' : nil,
|
58
|
+
"-P #{Phut.pid_dir}",
|
59
|
+
"-L #{Phut.log_dir}",
|
60
|
+
"-S #{Phut.socket_dir}"].compact.join(' ')
|
61
|
+
end
|
62
|
+
|
63
|
+
def arp_entries(all_hosts)
|
64
|
+
all_hosts.map do |each|
|
65
|
+
"#{each.ip_address}/#{each.mac_address}"
|
66
|
+
end.join(',')
|
67
|
+
end
|
68
|
+
|
69
|
+
def pid_file
|
70
|
+
"#{Phut.pid_dir}/vhost.#{name}.pid"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'drb'
|
2
|
+
require 'logger'
|
3
|
+
require 'phut/raw_socket'
|
4
|
+
require 'pio'
|
5
|
+
|
6
|
+
module Phut
|
7
|
+
# vhost daemon process
|
8
|
+
# rubocop:disable ClassLength
|
9
|
+
class VhostDaemon
|
10
|
+
def self.unix_domain_socket(name, socket_dir)
|
11
|
+
"drbunix:#{socket_dir}/vhost.#{name}.ctl"
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.process(name, socket_dir)
|
15
|
+
DRbObject.new_with_uri(unix_domain_socket(name, socket_dir))
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(options)
|
19
|
+
@options = options
|
20
|
+
@packets_sent = []
|
21
|
+
@packets_received = []
|
22
|
+
end
|
23
|
+
|
24
|
+
def run
|
25
|
+
start_logging
|
26
|
+
create_pid_file
|
27
|
+
start_daemon
|
28
|
+
rescue
|
29
|
+
shutdown
|
30
|
+
end
|
31
|
+
|
32
|
+
def stop
|
33
|
+
@stop = true
|
34
|
+
end
|
35
|
+
|
36
|
+
def send_packets(dest, npackets)
|
37
|
+
return unless lookup_arp_table(dest.ip_address)
|
38
|
+
udp = create_udp_packet(dest)
|
39
|
+
npackets.times do
|
40
|
+
write_to_raw_socket udp
|
41
|
+
@logger.info "Sent to #{dest.name}: #{udp}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def stats
|
46
|
+
{ tx: @packets_sent, rx: @packets_received }
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def start_logging
|
52
|
+
@logger = Logger.new(log_file)
|
53
|
+
@logger.info("#{@options.fetch(:name)} started " \
|
54
|
+
"(interface = #{@options.fetch(:interface)}," \
|
55
|
+
" IP address = #{@options.fetch(:ip_address)}," \
|
56
|
+
" MAC address = #{@options.fetch(:mac_address)}," \
|
57
|
+
" arp_entries = #{@options.fetch(:arp_entries)})")
|
58
|
+
end
|
59
|
+
|
60
|
+
def raw_socket
|
61
|
+
@raw_socket ||= RawSocket.new(@options.fetch(:interface))
|
62
|
+
end
|
63
|
+
|
64
|
+
def lookup_arp_table(ip_address)
|
65
|
+
@options.fetch(:arp_table)[ip_address]
|
66
|
+
end
|
67
|
+
|
68
|
+
def write_to_raw_socket(packet)
|
69
|
+
@packets_sent << packet.snapshot
|
70
|
+
raw_socket.write packet.to_binary_s
|
71
|
+
end
|
72
|
+
|
73
|
+
def create_udp_packet(dest)
|
74
|
+
Pio::Udp.new(source_mac: @options.fetch(:mac_address),
|
75
|
+
destination_mac: dest.mac_address,
|
76
|
+
ip_source_address: @options.fetch(:ip_address),
|
77
|
+
ip_destination_address: dest.ip_address)
|
78
|
+
end
|
79
|
+
|
80
|
+
def log_file
|
81
|
+
"#{@options.fetch(:log_dir)}/vhost.#{@options.fetch(:name)}.log"
|
82
|
+
end
|
83
|
+
|
84
|
+
def read_loop
|
85
|
+
loop do
|
86
|
+
raw_data, = raw_socket.recvfrom(8192)
|
87
|
+
udp = Pio::Udp.read(raw_data)
|
88
|
+
# TODO: Check @options[:promisc]
|
89
|
+
@logger.info "Received: #{udp}"
|
90
|
+
@packets_received << udp.snapshot
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def start_daemon
|
95
|
+
Process.daemon
|
96
|
+
trap_sigint
|
97
|
+
update_pid_file
|
98
|
+
start_threads_and_join
|
99
|
+
end
|
100
|
+
|
101
|
+
def start_threads_and_join
|
102
|
+
unix_domain_socket =
|
103
|
+
self.class.unix_domain_socket(@options.fetch(:name),
|
104
|
+
@options.fetch(:socket_dir))
|
105
|
+
DRb.start_service(unix_domain_socket, self, UNIXFileMode: 0666)
|
106
|
+
Thread.start { read_loop }.abort_on_exception = true
|
107
|
+
DRb.thread.join
|
108
|
+
end
|
109
|
+
|
110
|
+
def shutdown
|
111
|
+
@logger.error $ERROR_INFO if $ERROR_INFO
|
112
|
+
@logger.info 'Shutting down...'
|
113
|
+
FileUtils.rm pid_file if running?
|
114
|
+
fail $ERROR_INFO if $ERROR_INFO
|
115
|
+
end
|
116
|
+
|
117
|
+
def trap_sigint
|
118
|
+
Thread.start { shutdown_loop }.abort_on_exception = true
|
119
|
+
Signal.trap(:INT) { stop }
|
120
|
+
end
|
121
|
+
|
122
|
+
def shutdown_loop
|
123
|
+
loop do
|
124
|
+
break if @stop
|
125
|
+
sleep 0.1
|
126
|
+
end
|
127
|
+
shutdown
|
128
|
+
end
|
129
|
+
|
130
|
+
def create_pid_file
|
131
|
+
fail "#{@options.fetch(:name)} is already running." if running?
|
132
|
+
update_pid_file
|
133
|
+
end
|
134
|
+
|
135
|
+
def update_pid_file
|
136
|
+
File.open(pid_file, 'w') { |file| file << Process.pid }
|
137
|
+
end
|
138
|
+
|
139
|
+
def running?
|
140
|
+
FileTest.exists?(pid_file)
|
141
|
+
end
|
142
|
+
|
143
|
+
def pid_file
|
144
|
+
File.join @options.fetch(:pid_dir), "vhost.#{@options.fetch(:name)}.pid"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
# rubocop:enable ClassLength
|
148
|
+
end
|
data/phut.gemspec
CHANGED
@@ -15,7 +15,7 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.email = ['yasuhito@gmail.com']
|
16
16
|
gem.homepage = 'http://github.com/trema/phut'
|
17
17
|
|
18
|
-
gem.executables = %w(phut)
|
18
|
+
gem.executables = %w(phut vhost)
|
19
19
|
gem.files = `git ls-files`.split("\n")
|
20
20
|
|
21
21
|
gem.extensions = ['Rakefile']
|
@@ -26,7 +26,7 @@ Gem::Specification.new do |gem|
|
|
26
26
|
gem.required_ruby_version = '>= 2.0.0'
|
27
27
|
|
28
28
|
gem.add_dependency 'gli', '~> 2.12.3'
|
29
|
-
gem.add_dependency 'pio', '~> 0.
|
29
|
+
gem.add_dependency 'pio', '~> 0.16.0'
|
30
30
|
gem.add_dependency 'pry', '~> 0.10.1'
|
31
31
|
|
32
32
|
# Docs
|
data/spec/phut/parser_spec.rb
CHANGED
@@ -47,7 +47,7 @@ CONFIG
|
|
47
47
|
|
48
48
|
describe '#vhost' do
|
49
49
|
Then { config.vhosts.size == 2 }
|
50
|
-
Then { config.fetch('192.168.0.1').
|
50
|
+
Then { config.fetch('192.168.0.1').ip_address == '192.168.0.1' }
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
@@ -62,7 +62,7 @@ CONFIG
|
|
62
62
|
|
63
63
|
describe '#vhost' do
|
64
64
|
Then { config.vhosts.size == 2 }
|
65
|
-
Then { config.fetch('host1').
|
65
|
+
Then { config.fetch('host1').ip_address == '192.168.0.1' }
|
66
66
|
end
|
67
67
|
end
|
68
68
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: phut
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yasuhito Takamiya
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-02
|
11
|
+
date: 2015-03-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: gli
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ~>
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: 0.16.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ~>
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.
|
40
|
+
version: 0.16.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: pry
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -309,12 +309,14 @@ email:
|
|
309
309
|
- yasuhito@gmail.com
|
310
310
|
executables:
|
311
311
|
- phut
|
312
|
+
- vhost
|
312
313
|
extensions:
|
313
314
|
- Rakefile
|
314
315
|
extra_rdoc_files:
|
315
316
|
- README.md
|
316
317
|
files:
|
317
318
|
- .gitignore
|
319
|
+
- .hound.yml
|
318
320
|
- .rspec
|
319
321
|
- .rubocop.yml
|
320
322
|
- .ruby-version
|
@@ -327,6 +329,7 @@ files:
|
|
327
329
|
- README.md
|
328
330
|
- Rakefile
|
329
331
|
- bin/phut
|
332
|
+
- bin/vhost
|
330
333
|
- features/dsl.feature
|
331
334
|
- features/dsl_link.feature
|
332
335
|
- features/dsl_vhost.feature
|
@@ -337,16 +340,17 @@ files:
|
|
337
340
|
- features/support/env.rb
|
338
341
|
- features/support/hooks.rb
|
339
342
|
- lib/phut.rb
|
340
|
-
- lib/phut/cli.rb
|
341
343
|
- lib/phut/configuration.rb
|
342
344
|
- lib/phut/null_logger.rb
|
343
345
|
- lib/phut/open_vswitch.rb
|
344
346
|
- lib/phut/parser.rb
|
345
|
-
- lib/phut/
|
347
|
+
- lib/phut/raw_socket.rb
|
346
348
|
- lib/phut/setting.rb
|
347
349
|
- lib/phut/shell_runner.rb
|
348
350
|
- lib/phut/syntax.rb
|
349
351
|
- lib/phut/version.rb
|
352
|
+
- lib/phut/vhost.rb
|
353
|
+
- lib/phut/vhost_daemon.rb
|
350
354
|
- lib/phut/virtual_link.rb
|
351
355
|
- phut.gemspec
|
352
356
|
- spec/phut/open_vswitch_spec.rb
|
@@ -361,43 +365,10 @@ files:
|
|
361
365
|
- tasks/relish.rake
|
362
366
|
- tasks/rspec.rake
|
363
367
|
- tasks/rubocop.rake
|
364
|
-
- tasks/vhost.rake
|
365
368
|
- vendor/.gitignore
|
366
369
|
- vendor/README.md
|
367
370
|
- vendor/openvswitch-1.2.2.trema1.tar.gz
|
368
371
|
- vendor/openvswitch-1.2.2_librt-check.diff
|
369
|
-
- vendor/phost/src/.gitignore
|
370
|
-
- vendor/phost/src/Makefile
|
371
|
-
- vendor/phost/src/arp.c
|
372
|
-
- vendor/phost/src/arp.h
|
373
|
-
- vendor/phost/src/cli.c
|
374
|
-
- vendor/phost/src/cli.h
|
375
|
-
- vendor/phost/src/cmdif.c
|
376
|
-
- vendor/phost/src/cmdif.h
|
377
|
-
- vendor/phost/src/common.c
|
378
|
-
- vendor/phost/src/common.h
|
379
|
-
- vendor/phost/src/eth.c
|
380
|
-
- vendor/phost/src/eth.h
|
381
|
-
- vendor/phost/src/ethdev.c
|
382
|
-
- vendor/phost/src/ethdev.h
|
383
|
-
- vendor/phost/src/icmp.c
|
384
|
-
- vendor/phost/src/icmp.h
|
385
|
-
- vendor/phost/src/ipv4.c
|
386
|
-
- vendor/phost/src/ipv4.h
|
387
|
-
- vendor/phost/src/log.c
|
388
|
-
- vendor/phost/src/log.h
|
389
|
-
- vendor/phost/src/phost.c
|
390
|
-
- vendor/phost/src/phost.h
|
391
|
-
- vendor/phost/src/stats.c
|
392
|
-
- vendor/phost/src/stats.h
|
393
|
-
- vendor/phost/src/tap.c
|
394
|
-
- vendor/phost/src/tap.h
|
395
|
-
- vendor/phost/src/trx.c
|
396
|
-
- vendor/phost/src/trx.h
|
397
|
-
- vendor/phost/src/udp.c
|
398
|
-
- vendor/phost/src/udp.h
|
399
|
-
- vendor/phost/src/utils.c
|
400
|
-
- vendor/phost/src/utils.h
|
401
372
|
homepage: http://github.com/trema/phut
|
402
373
|
licenses:
|
403
374
|
- GPL3
|
data/lib/phut/cli.rb
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
require 'phut/null_logger'
|
2
|
-
require 'phut/setting'
|
3
|
-
require 'phut/shell_runner'
|
4
|
-
|
5
|
-
module Phut
|
6
|
-
# cli command wrapper.
|
7
|
-
class Cli
|
8
|
-
include ShellRunner
|
9
|
-
|
10
|
-
def initialize(host, logger = NullLogger.new)
|
11
|
-
@host = host
|
12
|
-
@logger = logger
|
13
|
-
end
|
14
|
-
|
15
|
-
def send_packets(dest, options = {})
|
16
|
-
n_pkts = options[:n_pkts]
|
17
|
-
sh [executable,
|
18
|
-
"-i #{@host.interface} send_packets",
|
19
|
-
"--ip_dst #{dest.ip}",
|
20
|
-
"--ip_src #{@host.ip}",
|
21
|
-
'--tp_src 1',
|
22
|
-
'--tp_dst 1',
|
23
|
-
'--pps 1',
|
24
|
-
'--length 22',
|
25
|
-
n_pkts ? "--n_pkts=#{n_pkts}" : '--duration 1'].join(' ')
|
26
|
-
end
|
27
|
-
|
28
|
-
def show_tx_stats
|
29
|
-
puts stats(:tx)
|
30
|
-
end
|
31
|
-
|
32
|
-
def show_rx_stats
|
33
|
-
puts stats(:rx)
|
34
|
-
end
|
35
|
-
|
36
|
-
def add_arp_entry(other)
|
37
|
-
sh "sudo #{executable} -i #{@host.interface} add_arp_entry " \
|
38
|
-
"--ip_addr #{other.ip} --mac_addr #{other.mac}"
|
39
|
-
end
|
40
|
-
|
41
|
-
def set_ip_and_mac_address
|
42
|
-
sh "sudo #{executable} -i #{@host.interface} set_host_addr " \
|
43
|
-
"--ip_addr #{@host.ip} --ip_mask #{@host.netmask} " \
|
44
|
-
"--mac_addr #{@host.mac}"
|
45
|
-
end
|
46
|
-
|
47
|
-
def enable_promisc
|
48
|
-
sh "sudo #{executable} -i #{@host.interface} enable_promisc"
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
|
-
def executable
|
54
|
-
"#{Phut.root}/vendor/phost/src/cli"
|
55
|
-
end
|
56
|
-
|
57
|
-
def stats(type)
|
58
|
-
`sudo #{executable} -i #{@host.interface} show_stats --#{type}`
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
data/lib/phut/phost.rb
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
require 'phut/cli'
|
2
|
-
require 'phut/null_logger'
|
3
|
-
require 'phut/setting'
|
4
|
-
require 'phut/shell_runner'
|
5
|
-
require 'pio/mac'
|
6
|
-
|
7
|
-
module Phut
|
8
|
-
# An interface class to phost emulation utility program.
|
9
|
-
class Phost
|
10
|
-
include ShellRunner
|
11
|
-
|
12
|
-
attr_reader :ip
|
13
|
-
attr_reader :mac
|
14
|
-
attr_accessor :interface
|
15
|
-
|
16
|
-
def initialize(ip_address, promisc, name = nil, logger = NullLogger.new)
|
17
|
-
@ip = ip_address
|
18
|
-
@promisc = promisc
|
19
|
-
@name = name
|
20
|
-
@mac = Pio::Mac.new(rand(0xffffffffffff + 1))
|
21
|
-
@logger = logger
|
22
|
-
end
|
23
|
-
|
24
|
-
def name
|
25
|
-
@name || @ip
|
26
|
-
end
|
27
|
-
|
28
|
-
def to_s
|
29
|
-
"vhost (name = #{name}, ip = #{@ip})"
|
30
|
-
end
|
31
|
-
|
32
|
-
def run(hosts = [])
|
33
|
-
sh "sudo #{executable} #{options.join ' '}"
|
34
|
-
sleep 1
|
35
|
-
set_ip_and_mac_address
|
36
|
-
maybe_enable_promisc
|
37
|
-
add_arp_entries hosts
|
38
|
-
end
|
39
|
-
|
40
|
-
def stop
|
41
|
-
fail "phost (name = #{name}) is not running!" unless running?
|
42
|
-
pid = IO.read(pid_file)
|
43
|
-
sh "sudo kill #{pid}"
|
44
|
-
end
|
45
|
-
|
46
|
-
def maybe_stop
|
47
|
-
return unless running?
|
48
|
-
stop
|
49
|
-
end
|
50
|
-
|
51
|
-
def netmask
|
52
|
-
'255.255.255.255'
|
53
|
-
end
|
54
|
-
|
55
|
-
def running?
|
56
|
-
FileTest.exists?(pid_file)
|
57
|
-
end
|
58
|
-
|
59
|
-
private
|
60
|
-
|
61
|
-
def set_ip_and_mac_address
|
62
|
-
Phut::Cli.new(self, @logger).set_ip_and_mac_address
|
63
|
-
end
|
64
|
-
|
65
|
-
def maybe_enable_promisc
|
66
|
-
return unless @promisc
|
67
|
-
Phut::Cli.new(self).enable_promisc
|
68
|
-
end
|
69
|
-
|
70
|
-
def add_arp_entries(hosts)
|
71
|
-
hosts.each do |each|
|
72
|
-
Phut::Cli.new(self).add_arp_entry each
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def pid_file
|
77
|
-
"#{Phut.pid_dir}/phost.#{name}.pid"
|
78
|
-
end
|
79
|
-
|
80
|
-
def executable
|
81
|
-
"#{Phut.root}/vendor/phost/src/phost"
|
82
|
-
end
|
83
|
-
|
84
|
-
def options
|
85
|
-
%W(-p #{Phut.pid_dir}
|
86
|
-
-l #{Phut.log_dir}
|
87
|
-
-n #{name}
|
88
|
-
-i #{interface}
|
89
|
-
-D)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
data/tasks/vhost.rake
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
require 'phut'
|
2
|
-
|
3
|
-
def phost_src
|
4
|
-
File.join Phut.root, 'vendor', 'phost', 'src'
|
5
|
-
end
|
6
|
-
|
7
|
-
def phost_objects
|
8
|
-
FileList[File.join(phost_src, '*.o')]
|
9
|
-
end
|
10
|
-
|
11
|
-
def phost_vendor_binary
|
12
|
-
File.join phost_src, 'phost'
|
13
|
-
end
|
14
|
-
|
15
|
-
def phost_cli_vendor_binary
|
16
|
-
File.join phost_src, 'cli'
|
17
|
-
end
|
18
|
-
|
19
|
-
desc 'Build vhost executables'
|
20
|
-
task vhost: [phost_vendor_binary, phost_cli_vendor_binary]
|
21
|
-
|
22
|
-
file phost_vendor_binary do
|
23
|
-
cd phost_src do
|
24
|
-
sh 'make'
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
file phost_cli_vendor_binary do
|
29
|
-
cd phost_src do
|
30
|
-
sh 'make'
|
31
|
-
end
|
32
|
-
end
|