phut 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|