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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 38a59abc94f4a6e4dc8d9881736b06e5c461a20c
4
- data.tar.gz: 9e93f07ecb38aef9907182d681655e3ed9712db5
3
+ metadata.gz: 9b2838869618793f7529456e67f55820c6312fd4
4
+ data.tar.gz: b38be67f933c105564abad75ffe2c9e545787757
5
5
  SHA512:
6
- metadata.gz: 342641815042a8dfb0ce100cb5f3605e563a06a6d48ea30396d458b0b6bf1fdedb323dd521c8118d1b8675148eae89a671576279e5418b57f96195de263204dc
7
- data.tar.gz: c92c0c02de7f761540024a219a4a0eb6663dcfa61db066e3f8cf5ae5b6b0ac7b8da6f03f0de119942f809179b068f2562bd0dcf9170fe387f407d32a733e0327
6
+ metadata.gz: b19c285acc17e89ee19d803c1f161b741cfbd1305692af023f057aac4f06a3a7c37d0d84c31e6cfb52d0d02a2024c76609a495de38ff756cba6d2f2761369eef
7
+ data.tar.gz: 3f51908add6cd7e341ed596c2dad7d361b3838ad70337d232248d55b1fc8795f3b7b533e1147f7bba875643b5618ac9a77f590f04657d9da3dbf83d7ccd0e331
data/.hound.yml ADDED
@@ -0,0 +1,3 @@
1
+ ruby:
2
+ enabled: true
3
+ config_file: .rubocop.yml
data/.rubocop.yml CHANGED
@@ -9,3 +9,9 @@ AllCops:
9
9
  - phut.gemspec
10
10
  - spec/**/*.rb
11
11
  - tasks/*.rake
12
+
13
+ Style/StringLiterals:
14
+ EnforcedStyle: single_quotes
15
+
16
+ Style/DotPosition:
17
+ EnforcedStyle: trailing
data/CHANGELOG.md CHANGED
@@ -3,6 +3,11 @@
3
3
  ## develop (unreleased)
4
4
 
5
5
 
6
+ ## 0.2.0 (3/2/2015)
7
+ ### New features
8
+ * [#19](https://github.com/trema/phut/pull/19): Add `bin/vhost`.
9
+
10
+
6
11
  ## 0.1.0 (2/23/2015)
7
12
  ### Misc
8
13
  * The initial release version of phut.
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: [:openvswitch, :vhost]
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[:pid_dir]
66
- Phut.log_dir = options[:log_dir]
67
- Phut.socket_dir = options[:socket_dir]
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, ip = 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), "phost.#{name}.pid")
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
@@ -1,5 +1,5 @@
1
- require 'phut/cli'
2
1
  require 'phut/open_vswitch'
3
2
  require 'phut/parser'
4
3
  require 'phut/setting'
5
4
  require 'phut/version'
5
+ require 'phut/vhost_daemon'
@@ -19,7 +19,7 @@ module Phut
19
19
  end
20
20
 
21
21
  def vhosts
22
- @all.values.select { |each| each.is_a? Phost }
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] = Phost.new(attrs[:ip], attrs[:promisc], name, @logger)
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(__dir__, '..', '..')),
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
@@ -1,4 +1,4 @@
1
- require 'phut/phost'
1
+ require 'phut/vhost'
2
2
  require 'phut/virtual_link'
3
3
 
4
4
  module Phut
data/lib/phut/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  # Base module.
2
2
  module Phut
3
- VERSION = '0.1.0'
3
+ VERSION = '0.2.0'
4
4
  end
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.15.2'
29
+ gem.add_dependency 'pio', '~> 0.16.0'
30
30
  gem.add_dependency 'pry', '~> 0.10.1'
31
31
 
32
32
  # Docs
@@ -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').ip == '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').ip == '192.168.0.1' }
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.1.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-23 00:00:00.000000000 Z
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.15.2
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.15.2
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/phost.rb
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