Skip to content

(Part 3) Command-line parsing and YAML config files in Rust#1278

Merged
stevenengler merged 10 commits intoshadow:devfrom
stevenengler:rust-parsing
May 5, 2021
Merged

(Part 3) Command-line parsing and YAML config files in Rust#1278
stevenengler merged 10 commits intoshadow:devfrom
stevenengler:rust-parsing

Conversation

@stevenengler
Copy link
Copy Markdown
Contributor

@stevenengler stevenengler commented Apr 8, 2021

Replaces Shadow's existing command-line and configuration file parsing code with Rust versions using Serde and Clap (version 3.0.0-beta.2). Shadow's XML configuration file format has been replaced by YAML in the process.

This PR will be easier to review as individual commits.

Closes #773.

Changed CLI options:

Old options                                                 New options
-----------                                                 -----------

-?, --help                                                  -h, --help
--help-all
--help-sys
--help-experimental
--interface-buffer=N                    [1024000]           --interface-buffer                  ["1024000 B"]
--interface-qdisc=QDISC                 ['fifo']            --interface-qdisc                   ["fifo"]
--socket-recv-buffer=N                  [174760]            --socket-recv-buffer                ["174760 B"]
                                                            --socket-recv-autotune              [true]
--socket-send-buffer=N                  [131072]            --socket-send-buffer                ["131072 B"]
                                                            --socket-send-autotune              [true]
--max-concurrency=N                     [-1]                --max-concurrency
--set-sched-fifo                                            --use-sched-fifo                    [false]
--disable-object-counters                                   --use-object-counters               [true]
--disable-shim-syscall-handler                              --use-shim-syscall-handler          [true]
--disable-o-n-waitpid-workarounds                           --use-o-n-waitpid-workarounds       [true]
--send-explicit-block-message=[0|1]     [1]                 --use-explicit-block-message        [true]
--enable-syscall-counters                                   --use-syscall-counters              [false]
--disable-memory-manager                                    --use-memory-manager                [true]
--preload-spin-max=N                    [8096]              --preload-spin-max                  [8096]
                                                            --bootstrap-end-time                ["0 sec"]
                                                            --heartbeat-interval                ["1 sec"]
                                                            --stop-time
                                                            --bandwidth-down
                                                            --bandwidth-up
                                                            --city-code-hint
                                                            --country-code-hint
                                                            --ip-hint
                                                            --pcap-directory
                                                            --type-hint
-c, --exit-after-shm-cleanup                                --shm-cleanup
-d, --data-directory=PATH               ['shadow.data']     -d, --data-directory                ["shadow.data"]
-e, --data-template=PATH                [None]              -e, --template-directory
-g, --gdb                                                   -g, --gdb
-h, --heartbeat-frequency=N             [1]                 --heartbeat-interval                ["1 sec"]
-i, --heartbeat-log-info=LIST           ['node']            --host-heartbeat-log-info           [["node"]]
-j, --heartbeat-log-level=LEVEL         ['message']         --host-heartbeat-log-level          ["message"]
                                                            --host-log-level
-l, --log-level=LEVEL                   ['message']         -l, --log-level                     ["message"]
-r, --runahead=TIME                     [0]                 --runahead
-s, --seed=N                            [1]                 --seed                              [1]
-t, --scheduler-policy=SPOL             ['steal']           --scheduler-policy                  ["steal"]
-n, --interpose-method=METHOD           ['ptrace']          --interpose-method                  ["ptrace"]
-z, --pin-cpus                                              --use-cpu-pinning                   [false]
-w, --workers=N                         [0]                 -w, --workers                       [0]
-v, --version                                               -V, --version
                                                            --show-build-info
                                                            --show-config

Changed configuration options:

bootstraptime         bootstrap_end_time
starttime             start_time
stoptime              stop_time
arguments             args
iphint                ip_hint
citycodehint          city_code_hint
countrycodehint       country_code_hint
typehint              type_hint
loglevel              log_level
heartbeatloglevel     heartbeat_log_level
heartbeatloginfo      heartbeat_log_info
pcapdir               pcap_directory
bandwidthdown         bandwidth_down (unit changed from KiB/s to bits)
bandwidthup           bandwidth_up (unit changed from KiB/s to bits)
heartbeatfrequency    heartbeat_interval
socketrecvbuffer      socket_recv_buffer
socketsendbuffer      socket_send_buffer
interfacebuffer       interface_buffer

Changed topology options:

bandwidthup      bandwidth_up (type changed to "string", and unit changed to bits)
bandwidthdown    bandwidth_down (type changed to "string", and unit changed to bits)
packetloss       packet_loss
countrycode      country_code
citycode         city_code

Miscellaneous changes:

  • added a quantity field for processes
  • renamed the configuration file top-level options field to general, and added new experimental options under the top-level experimental field, and new host default options under the top-level host_defaults field.
  • hosts in the configuration file are now specified using a map/dictionary, and not a list of hosts
  • moved some existing options into the experimental group (Organize and remove legacy options #1220)
  • topology in the configuration file is no longer a list
  • most of the host options have moved into an options field
  • added a plain topology option (in addition to the existing graphml and path options), which uses a simple built-in topology (Add default single-node topology in case user does not provide one #1221)
  • process arguments in the configuration file can now be passed as a list of arguments
  • the existing XML/YAML conversion script has been modified to convert to the new YAML format, and no longer converts from YAML to XML
  • added a new script for converting the topology graphml file to the new format
  • removed the configuration file plugin list, and now each process specifies the path to the executable to run (Remove the plugins list from the root of the configuration file #1147)
  • disabled the XML/YAML conversion tests
  • the logpcap and pcapdir options have been combined into a single option pcap_directory
  • removed some of the short option flags (-h, -i, -j, etc)
  • removes legacy configuration options suck as kill and time (Remove old Shadow configuration options #1146)
  • values can be provided with a unit value (for example "1 Mbit", "1 megabit", etc) and if a unit isn't given, will default to the base unit (Allow variable suffixes for bandwidth config values #1161)
  • environment field is now per-process rather than global
  • arguments are no longer split by spaces

To do after this PR:

@stevenengler stevenengler added Type: Enhancement New functionality or improved design Component: Main Composing the core Shadow executable labels Apr 8, 2021
@stevenengler stevenengler self-assigned this Apr 8, 2021
@stevenengler stevenengler marked this pull request as draft April 8, 2021 18:34
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 13, 2021

Codecov Report

Merging #1278 (c1df77a) into dev (fd1138d) will increase coverage by 0.44%.
The diff coverage is 70.47%.

Impacted file tree graph

@@            Coverage Diff             @@
##              dev    #1278      +/-   ##
==========================================
+ Coverage   55.74%   56.19%   +0.44%     
==========================================
  Files         142      140       -2     
  Lines       20960    20161     -799     
  Branches     5295     5018     -277     
==========================================
- Hits        11685    11329     -356     
+ Misses       6160     5941     -219     
+ Partials     3115     2891     -224     
Flag Coverage Δ
tests 56.19% <70.47%> (+0.44%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
src/main/host/network_interface.c 72.38% <0.00%> (ø)
src/main/host/tracker.c 38.85% <ø> (ø)
src/main/core/main.c 50.42% <40.90%> (-4.52%) ⬇️
src/main/core/manager.c 66.97% <59.37%> (+0.74%) ⬆️
src/main/routing/topology.c 44.20% <61.29%> (+2.28%) ⬆️
src/main/core/scheduler/scheduler.c 74.14% <66.66%> (-0.24%) ⬇️
src/main/core/support/config_handlers.c 83.33% <83.33%> (ø)
src/main/core/controller.c 79.00% <90.27%> (+18.67%) ⬆️
src/main/core/worker.c 77.23% <100.00%> (-0.97%) ⬇️
src/main/host/descriptor/tcp.c 78.06% <100.00%> (-0.34%) ⬇️
... and 19 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fd1138d...c1df77a. Read the comment docs.

@stevenengler stevenengler force-pushed the rust-parsing branch 4 times, most recently from e58c2e1 to bfe22de Compare April 15, 2021 17:23
@stevenengler stevenengler changed the base branch from dev to main April 15, 2021 17:58
@stevenengler stevenengler changed the base branch from main to dev April 15, 2021 17:58
@stevenengler stevenengler force-pushed the rust-parsing branch 5 times, most recently from aa54082 to 9e576ab Compare April 27, 2021 18:43
@stevenengler stevenengler changed the title Command-line parsing and YAML config files in Rust (Part 2) Command-line parsing and YAML config files in Rust Apr 27, 2021
@stevenengler stevenengler changed the title (Part 2) Command-line parsing and YAML config files in Rust (Part 3) Command-line parsing and YAML config files in Rust May 3, 2021
@stevenengler stevenengler force-pushed the rust-parsing branch 3 times, most recently from 1364109 to bff5b2f Compare May 3, 2021 22:21
@stevenengler stevenengler requested a review from robgjansen May 3, 2021 22:28
Copy link
Copy Markdown
Member

@robgjansen robgjansen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great! It simplifies a lot of things and will make it much simpler to configure experiments. I'm looking forward to using this new format in my experiments :)

I don't have any complex changes, but I'd like to look at any changes you make anyway :)

return EXIT_SUCCESS;
}

char* configName = clioptions_getConfig(options);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth commenting that this will never return a NULL configName.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this so that it can return NULL (before it would panic!()), but also added a NULL check in C.

Comment on lines +181 to +189
configFile = configfile_parse(configName);
} else {
configFile = configfile_parse("/dev/stdin");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth commenting why configfile_parse might return NULL.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment.

configfile_free(configFile);

if (clioptions_getShowConfig(options)) {
config_showConfig(config);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to exit after showing the config?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added.

ConfigHandlerFn fn = g_array_index(experimentalOptions, ConfigHandlerFn, i);
fn(config);
}
g_array_free(experimentalOptions, true);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to set experimentalOptions to NULL to make sure we don't operate on it anymore (now that the array data has been freed)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, added.

Comment on lines +10 to +11
#define OPTIONS_TOKENPASTE(x, y) x##y
#define OPTIONS_TOKENPASTE2(x, y) OPTIONS_TOKENPASTE(x, y)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want these to be used outside of this file? Or should we undef them at the end of this file?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we can undef them since they're used by the ADD_CONFIG_HANDLER macro. (The build fails when I undef them.)

rm -rf ${SHADOW_TEST_NAME}.data \
&& ${yaml2xml} ${SHADOW_TEST_SHADOW_CONFIG} --output - \
| ${CMAKE_BINARY_DIR}/src/main/shadow \
&& ${CMAKE_BINARY_DIR}/src/main/shadow \
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woo! :)

- plugin: test_clone
starttime: 1
arguments: ''
host:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super-nit: can we change the name of the host to something that is more apparently a hostname instead of host?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to testnode like the other tests.

Comment on lines +34 to +35
bandwidth_down: 819200 Kibit
bandwidth_up: 819200 Kibit
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some more Kibit -> Kibibit conversions here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind, Kibit is fine.

Comment on lines +42 to +43
bandwidth_down: 819200 Kibit
bandwidth_up: 819200 Kibit
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we just set this bandwidth as the default for everyone in the host_defaults part of the config? Then we wouldn't need to duplicate it for each host.

Or even better, the topology only contains a single node, and that node already has the correct bandwidth, so I think all the hosts will already get assigned that bandwidth even if we don't specify it as a host option or host_default option.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some hosts have bandwidths of 819200 kibibit (102400 KiB/s), some have 81920 kibibit (10240 KiB/s), clients have no defined bandwidths, and the topology node has a bandwidth of 81920 kibibit. Is there a reason why the original configuration had these hosts with different bandwidths? And why some hosts had bandwiths 10x greater than the topology node? Since this is just a test, it should be fine giving them all the same bandwidth, right?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I don't think the bandwidths matter much in this small test. I think they can all be the same. Not sure why they were different before - probably because I decided that many many years ago and never changed it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the topology bandwidth to 1 Gbit (rounded up from the ~800 Mbit that most hosts were using) and unset all of the other bandwidths.

@stevenengler stevenengler requested a review from robgjansen May 5, 2021 16:49
@stevenengler stevenengler marked this pull request as ready for review May 5, 2021 16:50
Copy link
Copy Markdown
Member

@robgjansen robgjansen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Thanks for the changes :)

@stevenengler stevenengler merged commit f6f25cd into shadow:dev May 5, 2021
@stevenengler stevenengler deleted the rust-parsing branch May 5, 2021 19:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Component: Main Composing the core Shadow executable Type: Enhancement New functionality or improved design

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants