複数のNICを持つ場合のデフォルトゲートウェイ
先日、仮想Linuxマシン(CentOS7)に複数のネットワークインターフェイス(以下、NICa、NICbとする)を持たせて、NICbが接続している側のゲートウェイをマシン全体のデフォルトゲートウェイ(以下、デフォゲ)にしようとしたのに、起動時にどうしてもルーティングテーブルのデフォゲがNICa側のゲートウェイになって困った。
状況としては、以下の通り:
調べたところ、以下のことが分かった。
- 各NICには優先順位がある。("in numerically ascending order"らしい)
- 各NICは、最初に/etc/sysconfig/networkのGATEWAY設定、次に個々のifcfgファイル (/etc/sysconfig/network-scripts内)にあるGATEWAY設定を読み込み、最後のGATEWAY設定がそのNICのゲートウェイとして設定される(参考)。
- そして、全体ルーティングテーブルのデフォルト設定は先勝ちで、優先順位の高いNICのゲートウェイがデフォゲになる。
今回のケースでは、NICaのゲートウェイ設定が優先的にデフォゲとして設定されてしまい、/etc/sysconfig/networkのGATEWAYは無視されていた。
ではどうすべきか。原理主義的に行くなら、デフォゲは使わず必要なルーティングはすべて静的に設定というのもある。それは大変という場合は、以下がおすすめ。
- sysconfigのGATEWAY設定は削除。
- ゲートウェイが必要なNICには適切にnmcliで設定 (ipv4.gateway のこと)。
- 同じくnmcliで、デフォゲにしたいゲートウェイに向いているNICの never-default を no に、それ以外のNICのそれは yes に設定。
メリットは以後の操作をすべてnmcliで出来るようになるのと、グローバル設定をなくせること。デメリットは、sysconfig/network のGATEWAY設定しか知らない人を混乱させるかもということ。まあ、それはコミュニケーションを取ればよい。
そんな感じにすると以下のようになる(192.168.0.0側がNICa、192.168.20.0側がNICbで外につながっている)。
# grep GATEWAY /etc/sysconfig/network # nmcli con mod enp0s3 ipv4.addresses "192.168.0.98/24" # nmcli con mod enp0s8 ipv4.addresses "192.168.20.98/24 192.168.20.1" # nmcli con mod enp0s3 ipv4.never-default yes # nmcli con mod enp0s8 ipv4.never-default no # systemctl restart network # nmcli con show enp0s3 | egrep 'ipv4.(addresses|never)' ipv4.addresses: { ip = 192.168.0.98/24, gw = 0.0.0.0 } ipv4.never-default: yes # nmcli con show enp0s8 | egrep 'ipv4.(addresses|never)' ipv4.addresses: { ip = 192.168.20.98/24, gw = 192.168.20.1 } ipv4.never-default: no # ip route default via 192.168.20.1 dev enp0s8 proto static metric 1024 192.168.0.0/24 dev enp0s3 proto kernel scope link src 192.168.0.98 192.168.20.0/24 dev enp0s8 proto kernel scope link src 192.168.20.98 # ping -c 2 8.8.8.8 PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data. 64 bytes from 8.8.8.8: icmp_seq=1 ttl=48 time=50.6 ms 64 bytes from 8.8.8.8: icmp_seq=2 ttl=48 time=42.2 ms --- 8.8.8.8 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1003ms rtt min/avg/max/mdev = 42.265/46.482/50.699/4.217 ms
ボンディングの場合も似たようなポリシーでできると思うが、サブアドレスで一つのNICにまったくセグメントの異なるアドレスを設定している場合は、どうすべきかは知らない。
ちなみに、NICごとにゲートウェイが設定できてしまうのは、デフォゲ先にあるルータが通信できなくなった場合のバックアップゲートウェイを設定する場合に必要な機能とのこと(参考:マルチホーム コンピュータのデフォルトゲートウェイ設定)らしいのだけど、では障害発生時にどうやって切り替えるかは知らない。RHEL HAアドオンみたいなHAミドルでがガリガリ書くしかないような気がする。
bashのwhileループ内の変数をループ外で使う
化石みたいな問題。
よく知られていることだが、下記のような各行を足し算するシェルスクリプトを書くと、最後の結果が0になってびっくりする。
$ cat get_nothing.sh __calculate_total() { local total=0 fpath=$1 cat $fpath | while read line; do total=$(( $total + ${line:-0} )) done echo "Total reaches $total" } __calculate_total $@
$ cat numbers.txt 101 -40 4566 32 $ bash ./get_nothing.sh numbers.txt Total reaches 0
これはwhile等の制御文だったかパイプの先だったか忘れたが、bashが別プロセス起こしちゃうんで、戻ってくるときにせっかく変更した変数の内容が破棄されるかららしい。
解決方法としては、UNIX FAQとかにexecでファイルディスクリプタを一時的に変更して云々な話が書かれていたりするが、現在の超高度に発達したSIerの開発現場において、そんなマイナーなテク使われても誰も読めなくて迷惑するのでやめてほしい。あと、一時ファイルにwhileループごとに値を書き出すのもやめて。コードレビューする人の 疲労感を無駄に積み増すんじゃない。
一番よい解決方法は、bashやめてPerlなりPythonなりまともな言語で書く。
でも、現在の超高度に発達したSIerの開発現場では、言語一つ変更するのに、周囲とのネゴとか試験仕様書の更新とか、誰も幸せにならないエネルギーが必要なので、シェルスクリプトの範囲内で何とかしてみる方法を考えてみた。
たぶんこう書くと16倍(当社比)くらいすっきり感が出ると思う。
$ cat goes_well.sh __sum_up() { local line total=0 while read line; do total=$(( $total + ${line:-0} )) done echo $total return 0 } main() { local total=0 fpath=$1 total=`cat $fpath | __sum_up` echo "Total reaches $total" return 0 }
つまり、while部分を別関数に切り出す。切り出しただけなので、行数はそれほど変わらない。
ファイル読み込み中にエラーが出た場合の処理を書きたい場合も容易に拡張できる。
$ cat goes_well2.sh __sum_up() { local line total=0 while read line; do if [[ "$line" =~ ^-?[0-9]+$ ]]; then total=$(( $total + ${line} )) else return 1 fi done echo $total return 0 } main() { local rc total=0 fpath=$1 # Todo: check the fpath is valid. total=`cat $fpath 2>/dev/null | __sum_up` rc=$? if [ $rc -ne 0 ]; then return $rc fi echo "Total reaches $total" return 0 } main $@
$ bash ./goes_well2.sh numbers.txt ;echo "rc=$?" Total reaches 4659 rc=0 $ cat numbers2.txt 101 -40 NOT NUMBER 4566 32 $ bash ./calc_total.sh numbers2.txt ;echo "rc=$?" rc=1
欠点は、"total="のパイプより前のコマンドでエラーが出ても$?が0になってしまう点で、そこのところはあまりいい書き方思いつかないので、まじめに直前にファイル存在チェック書いたほうが読みやすくてよいと思う。
まあでも、やはりbashを使わないのが正解。
ちなみにfor 文で
for nb in `cat numbers.txt`; do ..(足し算).. done echo $total
などとしても動くが、numbers.txt のファイルの中身が文字列としてメモリに全展開されるので、ファイルサイズが小さいことが保証されていない限りお勧めしない。
ANTLR v4 の文法ファイルのサンプル
最近までいろいろ ANTLR v4 をいじっていて、ようやく文法ファイルの書き方がわかってきた。
でも初心者向けの解説記事を書けるほど頭の中がこなれていないので、サンプルだけ示すことにする。
こんなファイルを考える。
"This" "is a " "\"quoted\" text." ""
このファイルから、「This」「is<改行> a 」「"quoted" text.」「(空文字)」という四つの文字列を認識するパーサを書きたいとする。
ファイル解析のプログラムはスクラッチからがりがり書いてもよいけど、文法が複雑になってくるとプログラムが汚くなりがちである。そこで、構文解析プログラムジェネレータである ANTLR が便利ということになる。
ANTLR 自体の細かい説明は面倒なのでしないけど、要は文法ファイルを与えるとその文法に従ったファイルを解釈するための Java プログラムを生成してくれる。
といった流れは簡単なのだが、文法ファイルの書き方はそれほど初心者には優しくない。
文法ファイルは、字句解析部分と構文解析部分の二つの部分から成り立つが、最近はこれを個別のファイルとして書くのが流行り(?)である。
まず字句解析の文法ファイル StringLexer.g4。
lexer grammar StringLexer; QUOTE: '"' -> pushMode(STRING_MODE) ; WS: ( ' ' | '\t' ) -> skip; NL : ( '\r' '\n'? | '\n') -> skip ; OUTER_CHAR: . -> skip ; mode STRING_MODE; RQUOTE: '"' -> popMode ; ESC: '\\' -> skip, pushMode(ESCCHAR_MODE) ; NOT_ESCCHAR: . ; mode ESCCHAR_MODE; ESCCHAR: ( '\\' | '"' ) -> popMode ;
「lexer」の行はおまじない。
最初の「mode」より上のグローバル部分と、二つの「mode」で、グローバル部分を一つのモードと考えると、合計三つのモードから構成される。
それで、グローバルの上のほうにある「QUOTE」の行では、引用符(") を読んだら、STRING_MODE というモードに移行する、という意味であり、STRING_MODE の最初の「RQUOTE」は、引用符を読み込んだら元のモードに戻るという意味である。
STRING_MODE は引用符の中を処理する部分であり、ESCCHAR_MODE はさらにその中のエスケープ文字を処理する部分である。まあ、あとは説明しなくても分かるでしょ。
エスケープ可能な文字はここでは2種類 (\と")に限定しているが、字句解析の段階でエラーにすると現場プログラム的にはエラー処理が面倒になるので、任意文字にしてもよいかもしれない。
この mode はとても便利である。字句解析ルールは何もしないとグローバルに効いてしまうので、その場合、字句解析プログラムは文字列の中だろうがコメントだろうが、お構いなしに字句解析ルールを当てはめてしまう。
実は最近まで mode を知らなかったので、このグローバル対策のためのバッドノウハウの塊みたいな文法ファイルを書いていたが、mode を使うときれいに字句解析文法ファイルを書ける。素晴らしい。
ただし mode は字句解析文法部分にしか使えないので、必然的に字句解析と構文解析とで文法ファイルを分ける必要が出てくる。
次に構文解析の文法ファイル。
StringParser.g4
parser grammar StringParser; options { tokenVocab=StringLexer; } strings : string* ; string returns [ String text ] : QUOTE v=string_text RQUOTE { $text = $v.text; } ; string_text : ( ESCCHAR | NOT_ESCCHAR )* ;
options のところが、さっきの字句解析ファイルのトークンを使っているよという宣言。
string ルールのところの RQUOTE の後の部分が、アクションというやつである。何もしないと 「"This"」と左右の引用符がくっついたままの文字列しかプログラムから取得できず面倒になるので、string_text のところだけを取り出して $text という変数に返すようにしている。
二つの文法ファイルができたらあとは、ANTLRに食わせて Java コードを生成させて、動かすだけである。
java -classath antlr-4.2.2-complete.jar org.antlr.v4.Tool -o <出力先> -package<パッケージ> StringLexer.g4 StringParser.g4
Java からの呼び出し方は以下の通り:
public void test(String filepath) throws IOException { ANTLRFileStream fromFileStream = new ANTLRFileStream(filepath); StringLexer lexer = new StringLexer(fromFileStream); CommonTokenStream tokens = new CommonTokenStream(lexer); StringParser parser = new StringParser(tokens); StringsContext stringsContext = parser.strings(); for (StringParser.StringContext stringContext : stringsContext.string()) { System.out.println("[[" + stringContext.text + "]]"); } }
出力結果。
[[This]] [[is a ]] [["quoted" text.]] [[]]
ジョギング音楽
ジョギングのときに聞いている曲の紹介。2年前に書いた記事から、だいぶ変わったので再編集。
曲名 | アーティスト名 | BPM | リンク |
---|---|---|---|
Holy Ground | Taylor Swift | 156 | iTunes / Youtube |
I'll Fight | Daughtry | 156 | iTunes / Youtube |
Blurry | Puddle of Mudd | 157 | iTunes / Youtube |
Everything Has Changed | Taylor Swift | 160 | iTunes / Youtube |
Never Say Never | The Fray | 160 | iTunes / Youtube |
What About Now | Daughtry | 162 | iTunes / Youtube |
Keep It Together | Puddle of Mudd | 162 | iTunes |
We Don't Have To Look Back Now | Puddle of Mudd | 163 | Youtube |
Back to the Beginning Again | Switchfoot | 167 | iTunes / iTunes |
We Are Never Ever Getting Back Together | Taylor Swift | 171 | iTunes / Youtube |
Wild Heart | Daughtry | 177 | iTunes / Youtube |
Puddle of Mudd は、ボーカルがよく捕まるためか最近はあまり新曲を出していないが、BPMがちょうどよいので2年前から生き残っている。
Permutation: Javaでの順列組合せの列挙
順列を全部生成するコードを書く必要があって世の中のコードを探したのだけど、あまりきれいなコードがなかったので自分で書いた、単なる備忘録的記事。
まあ、このコードがきれいかというと、うーん、でも使いやすさとシンプルさでは、いろいろ検索した中ではきれいだと思うんだけど。
public class Permutation<T extends <Serializable> { private int baseIndex; private int index; private T[] objs; private Permutation<T> subPermutation; public Permutation(T[] objs) { this(0, 0, objs.clone()); } private Permutation(int baseIndex, int index, T[] objs) { if (objs == null || objs.length == 0) { throw new IllegalArgumentException(); } this.baseIndex = baseIndex; this.index = index; this.objs = objs; if (this.index < this.objs.length - 1) { this.subPermutation = new Permutation<T>(this.baseIndex + 1, this.index + 1, this.objs); } } public T[] getTarget() { return this.objs; } public boolean next() { if (this.subPermutation == null) { return false; } boolean result = this.subPermutation.next(); if (result == true) { return true; } this.swap(this.baseIndex, this.index); ++this.index; if (this.objs.length <= this.index) { this.index = this.baseIndex; return false; } this.swap(this.index, this.baseIndex); return true; } @Override public String toString() { // snip. } private void swap(int index1, int index2) { T tmp = this.objs[index1]; this.objs[index1] = this.objs[index2]; this.objs[index2] = tmp; } }
呼び出し方は、
Permutation<String> p = new Permutation<>(new String[] { "a", "b", "c" }); do { System.out.println(p.toString()); } while (p.next());
で、次のようになる。
[a,b,c] [a,c,b] [b,a,c] [b,c,a] [c,b,a] [c,a,b]
メモリも大して食わないし、そこそこ高速だと思う。
Apache antのjavaタスクのarg要素に空白を含むパスを複数指定するには
antもANTLRも今更感はあるけど、久しぶりにいじると楽しい。
でも、結構はまる。文法ファイル(*.g4) が複数あって、かつパスに空白が含まれる場合(Google Driveとか)に、java タスクの arg 要素で pathref 属性を使おうとすると、ant が空白でパスを切ってしまって java タスクに思い通りに渡らない。そこで、 pathconvert を以下のように使って、文字列化してしまうとうまくいく。
<path id="src.antlr"> <fileset dir="${basedir}/src/antlr"> <include name="**/*.g4" /> </fileset> </path> <target name="antlr_compile"> <echo message="[DEBUG] ${toString:src.antlr}" /> <pathconvert property="antlr.args" refid="src.antlr" pathsep=" "> <regexpmapper from="^(.*)$" to='"\1"' /> </pathconvert> <echo message="[DEBUG] ${antlr.args}" /> <java classname="org.antlr.v4.Tool"> <classpath> <pathelement path="${basedir}/lib/antlr-4.1-complete.jar" /> </classpath> <arg line='-o "${basedir}/src/java/iwsttty/example_antlr"' /> <arg line="-package iwsttty.example_antlr" /> <arg line="${antlr.args}" /> </java> </target>
antlr タスクでは複数の文法ファイル指定はうまくいかなかったです。
VirtualBox ネットワーク設定
(12/10) 再度見てみたら、NAT Networkのところも問題なく接続できていた。確認方法がいまいちなだけだった。というわけで、この記事はあたかも最初からうまく設定できてたように書き直す。
# 嘘はついていない。あくまで確認が不足していただけ…。
(3/8) バージョン4.3.8から、ping proxyが実装されているので、NAT Network でもpingが通るようになっていた。なんかこの記事、追記が多すぎるので書き直したい。
とにかくVirtualBoxのネットワーク設定である。構築に使用したOS やVirtualBoxのバージョンは以下の通り。
- ホストOS
- Windows 8.1
- ゲストOS
- CentOS 6.5
- VirtualBox
- 4.3.4 r91027 *1
一つのホストOS上に以下のような仮想ネットワークを構成する。
想定としては、管理用セグメントをHost-Onlyネットワークで、サービス用セグメントを「NAT Network」ネットワークで、サーバ間セグメントをInternalネットワークで実現し、おのおの複数のNICを持つサーバというか仮想PCを接続しようとしている。NATは本当は作るつもりなかったけど、最初はNAT Networkがうまく疎通できないと思っていた関係で手っ取り早くインターネットへの口がほしかったのと、全部使った感がほしかったので入れてみた。
疎通可否を表にするとこんな感じ (日曜日なのに仕事っぽいな)。
NAT(w/o port forwarding) | NAT Network(w/o port forwarding) | Host Only ネットワーク | Internal ネットワーク | |
---|---|---|---|---|
ゲストOS間 | - | ○ | ○ | ○ |
ゲストOS → ホストOS/GW | ○ | ○ | ○ | - |
ゲストOS → インターネット | ○ | ○ | - | - |
ホストOS → ゲストOS | - | - | ○ | - |
DHCP | disabled | disabled | disabled | N/A |
○は疎通OK、ハイフン(-)は仕様上通らないもの。DHCPは全部OFF(実際のサーバ構築では、そんなもの使わない)。ポートフォワーディングは後回し。
順番に概要だけ説明。
NAT
今のところゲストOSからインターネットに出ていくための唯一のインターフェイス。
設定上の注意点は、VirtualBox が 10.0.N.0 のネットワークアドレスを勝手に割り当てること。自由なアドレスは使えない(仕様) (12/12追記 じゃなくてデフォルト値だった)。したがってゲストOS 側はこれに合わせて設定を入れる必要がある。今回、図で言うところの仮想PC O00の三番目のネットワークインターフェイス(Linuxから見るとeth2)をNATにしたので、10.0.2.0から数えて三番目の 10.0.4.0 が自動的に割り当てられた。ゲートウェイは 10.0.4.2 になるので、これをデフォゲにする。このNATネットワークはちゃんと設定すれば、ゲストOS側から簡単にインターネットに疎通してくれる。
[root@vso00 ~]# ping -c 3 8.8.8.8 PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data. 64 bytes from 8.8.8.8: icmp_seq=1 ttl=43 time=43.6 ms 64 bytes from 8.8.8.8: icmp_seq=2 ttl=43 time=43.2 ms 64 bytes from 8.8.8.8: icmp_seq=3 ttl=43 time=43.1 ms --- 8.8.8.8 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2047ms rtt min/avg/max/mdev = 43.116/43.355/43.670/0.334 ms
Host-only ネットワーク
最初、ゲストからホストへは疎通せず悩んでいたが、ホストOSのWindowsにて「ゲストまたはパブリックネットワーク」側のWindowsファイアウォールを落としたら通ることが分かった。ファイアウォールを無効にするのは嫌なので、受信規則を追加した。すなわち、「スコープ」の「ローカルIPアドレス」「リモートIP アドレス」ともに「192.168.0.0/24」とし、詳細のプロファイルは「パブリック」をチェック、「操作」は「接続を許可する」。これで想定どおり動くようになった。
(3/1追記: 一つ書き忘れた。下の VBoxManage.exe list hostonlyifs の出力にあるけど、VirtualBox が生成するHost-onlyネットワーク用仮想NICのIPアドレスは、Host-onlyネットワークのネットワークアドレスに合わせてデフォルトのものから変更している(GUIのファイル→環境設定→ネットワーク→Host-Onlyネットワーク→ドライバーアイコン)。これをやらないと、ホストからゲストにルーティングしてくれない。)
Internal ネットワーク
特に問題なし。寝ながら設定してもつながる。
NAT Network ネットワーク / NAT サービスネットワーク / NatNetwork
GUIでは「NAT ネットワーク」と書かれているが、マニュアルはNATサービス、どっちが正式名称なんだろう。とりあえず、GUIに合わせるが、この名称はググりにくい…。
それはともかく、NatNetwork は、Host-Onlyネットワークの機能を持ちながらも、インターネットに出ていけるネットワークである。
最初、うまく接続できないと思っていたが実はできていた。マニュアルには以下のように書いてある。
but letting systems inside communicate with each other and with systems outside using TCP and UDP over IPv4 and IPv6.
Chapter 6. Virtual networking
ICMPでつながるとはどこにも書いてなかった。不覚。(追記: 上述のとおり、4.3.8 以降は ping proxyが実装されている)
[root@vsw01 ~]# ping -c 3 www.yahoo.co.jp PING www.g.yahoo.co.jp (203.216.231.189) 56(84) bytes of data. --- www.g.yahoo.co.jp ping statistics --- 3 packets transmitted, 0 received, 100% packet loss, time 12001ms [root@vsw01 ~]# curl http://www.yahoo.co.jp | head -10 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <meta http-equiv="content-style-type" content="text/css"> <meta http-equiv="content-script-type" content="text/javascript"> <meta name="description" content="日本最大級のポータルサイト。検索、オークション、ニュース、天気、スポーツ、メール、ショッピングなど多数のサービスを展開。あなたの生活をより豊かにする「課題解決エンジン」を目指していきます。"> <meta property="og:title" content="Yahoo! JAPAN"> <meta property="og:type" content="article"> <meta property="og:url" content="http://www.yahoo.co.jp/"> 101 4774 0 4774 0 0 78196 0 --:--:-- --:--:-- --:--:-- 172k curl: (23) Failed writing body (3418 != 7300)
以上。とりあえず、VirtualBox の設定をさらしておく。
PS ...\virtualbox> & 'C:\Program Files\VirtualBox\VBoxManage.exe' list hostonlyifs Name: VirtualBox Host-Only Ethernet Adapter GUID: d2098a99-d909-4084-a50d-c0c828cc8a49 DHCP: Disabled IPAddress: 192.168.0.1 NetworkMask: 255.255.255.0 IPV6Address: XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX IPV6NetworkMaskPrefixLength: 64 HardwareAddress: 08:00:27:XX:XX:XX MediumType: Ethernet Status: Up VBoxNetworkName: HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter PS ...\virtualbox> & 'C:\Program Files\VirtualBox\VBoxManage.exe' list intnets Name: InternalNetwork Name: intnet (使っているのは上のほう) PS ...\virtualbox> & 'C:\Program Files\VirtualBox\VBoxManage.exe' list natnets NetworkName: ServiceNetwork IP: 192.168.2.1 Network: 192.168.2.0/24 IPv6 Enabled: No IPv6 Prefix: DHCP Enabled: No Enabled: Yes loopback mappings (ipv4) 127.0.0.1=2
Linuxのルーティング設定や/etc/sysconfig/network-scripts/ifcfg-* は、基本通り書いているだけなので詳細は省略。
手順だけ書いておく。まずVirtualboxのGUIで各仮想PCのネットワークインターフェイスをNATにするとか、Host-Onlyにするとか種類を設定する。このとき、MACアドレスを確認しておく。仮想Linuxを起動、「ip link」コマンドで、設定したインターフェイスが仮想OSに認識されていることを確認。/etc/udev/rules.d/70-persistent-net.rules を見て、MACアドレスとNIC名の対応付ルールに想定外のものが自動生成されている場合は適宜変更する(ATTR{address}とNAMEの対応のこと)。特にVirtualBox側でMACアドレスを再生成した場合にeth4 とかができてしまうので、例えば古いeth1行を削除し新しいeth4のNAMEをeth1 にしたりする作業が必要。変更した場合、仮想OS再起動。んで、/etc/sysconfig/network-scripts/ifcfg-ethN を修正する。見るのはBOOTPROTO(dhcpになっていないこと)、HWADDR、IPADDRとNETMASK。HWADDRがVirtualBox の GUI で設定した値と違うと、NICが起動しない。大事。外に出ていけるインターフェイスだけはGATEWAYも設定。あとはまあ「ifdown ethN; ifup ethN」して「ip addr」してpingで確認という感じ。(今回、このping確認が仇となったわけだが)
ちなみに最初の、ホストOS側のGUIで設定する部分のうち必要分は全部 VBoxManage コマンドで実施できることは確認済み。
*1:2/28追記: NAT Network について言うと、4.3.6はダメ。4.3.8はOK。