Skip to content

Commit 5e3e93a

Browse files
authored
Merge pull request #65 from ictsc/add-ictsc2025pr2
Add files for ICTSC2025 preround 2
2 parents 74fc37b + cdb3024 commit 5e3e93a

17 files changed

Lines changed: 1977 additions & 1 deletion

File tree

40.5 KB
Loading
20.6 KB
Loading
140 KB
Loading
33.5 KB
Loading
21.6 KB
Loading
24.4 KB
Loading
82.7 KB
Loading
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
title: "ICTSC2025 二次予選 問題解説まとめ"
3+
description: "ICTSC2025 二次予選 問題解説まとめ"
4+
tags: ["ICTSC2025", "問題解説まとめ"]
5+
pubDate: 2025-12-27T08:48:13.846Z
6+
slug: "2025/12/27/ictsc2025pr2"
7+
draft: false
8+
renderer: "md"
9+
sticky: true
10+
---
11+
12+
ICTSC2025 二次予選で出題した問題の問題文、及び問題解説を公開します。
13+
ぜひ今後の研鑽にご利用いただければと思います。
14+
15+
* [ICTSC2025 二次予選 問題解説: 眠れない夜](./lil)
16+
* [ICTSC2025 二次予選 問題解説: 半分しか伝わらない](./mid)
17+
* [ICTSC2025 二次予選 問題解説: The Handover of the Handover](./mpt)
18+
* [ICTSC2025 二次予選 問題解説: All I Want for Christmas are ...](./mtm)
19+
* [ICTSC2025 二次予選 問題解説: 新オフィスを救え!!](./rvt)
20+
* [ICTSC2025 二次予選 問題解説: ログが保存されない](./slg)
21+
* [ICTSC2025 二次予選 問題解説: 情シスことはじめ](./tmt)
22+
23+
また、それぞれの配点は以下の通りです。
24+
25+
| 問題 | 配点 |
26+
| ------------ | ---: |
27+
| 眠れない夜 | 150 |
28+
| 半分しか伝わらない | 100 |
29+
| The Handover of the Handover | 200 |
30+
| All I Want for Christmas are ... | 100 |
31+
| 新オフィスを救え!! | 150 |
32+
| ログが保存されない | 50 |
33+
| 情シスことはじめ | 150 |
34+
| **(合計)** | 900 |

src/content/blog/2025-pre-round-2nd/lil.md

Lines changed: 386 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
---
2+
title: "ICTSC2025 二次予選 問題解説: 半分しか伝わらない"
3+
description: "ICTSC2025 二次予選 問題解説: 半分しか伝わらない"
4+
tags: ["ICTSC2025", "問題解説"]
5+
pubDate: 2025-12-27T08:41:14.623Z
6+
slug: "2025/12/27/ictsc2025pr2/mid"
7+
draft: false
8+
renderer: "md"
9+
sticky: false
10+
---
11+
12+
## 概要
13+
14+
あなたは、2台のGWサーバーから、ルーターを経由して社内のサービスに冗長経路でアクセスできるNW構成の作成をお願いされました。
15+
この仕事には前任の担当者がおり、Network Namespaceを用いて模擬した検証環境を作成していた途中だったみたいなのですが、担当者は既に会社におらず詳細が分かりません。
16+
とりあえず動作確認を行ったところ、それぞれのGWからRouter側の宛先アドレス`10.10.10.10`にPingを飛ばすと、約50-100%のパケットロスが発生し、非常に不安定な状態であることが分かりました。
17+
18+
平常時にPingが100%通ることと、片系断でも残りの経路で疎通が継続すること(フェールオーバー)を目標に、作りかけの検証環境を完成させてください。
19+
20+
## 構成概要
21+
22+
- `setup-network.service` が作成する network namespace は `GW1``GW2``Router1``Router2` の4つ
23+
- `GW1``GW2``Router1``Router2` にそれぞれ接続されており、192.168.70.0/24 で収容
24+
- 目的アドレス `10.10.10.10/32``Router1``Router2``lo` に設定されており、どちらに届いても問題ない
25+
- ネットワークは netplan で自動構成されており、`sudo systemctl restart setup-network.service` で初期状態に戻せる
26+
- 大まかな構成・配線は下図の通り
27+
28+
![](/images/2025-pre-round-2nd/mid.png)
29+
30+
## 制約条件
31+
32+
- 上記の図から配線や機器(namespace)を追加・変更することは不可
33+
- 問題を解く上で一時的に構成を変更することは可能とする
34+
- namespace名やlink名の変更は不可
35+
36+
## 初期状態
37+
38+
- service `setup-network`が起動し、netplanを用いた検証構成が起動している
39+
- GW1及びGW2から"10.10.10.10"にPingを実行すると、約50-100%のパケットロスが発生する
40+
41+
## 終了状態
42+
43+
- 以下を満たす`ans.sh`をホームディレクトリ上に作成すること。
44+
- `sudo systemctl restart setup-network.service` を実行した後にans.shを実行することで、下記の条件を満たすこと
45+
1. GW1及びGW2から`10.10.10.10`にPingを実行すると、100%成功すること(平常系で安定していること)
46+
2. **GW-Router間の**いずれか1本のリンクを停止させても、GW1, GW2双方でPingが100%成功すること(フェールオーバーが動作すること)
47+
- 例: `GW1` - `Router1` の 接続インターフェースを down しても通信が継続して行える。
48+
49+
- **回答時には、ans.shとして作成したスクリプトの中身(全文)をcatコマンドなどで表示し、記述欄に含めてください**
50+
51+
## 接続情報
52+
53+
| ホスト名 | IPアドレス | ユーザ | パスワード|
54+
| --------- | ----------- | ------ | ------------------ |
55+
| mid-srv-01 | 192.168.255.71 | user | ictsc2025 |
56+
57+
## 確認例
58+
59+
### 平常時
60+
61+
```shell
62+
sudo ip netns exec GW1 ping -c 10 10.10.10.10
63+
sudo ip netns exec GW2 ping -c 10 10.10.10.10
64+
```
65+
66+
### フェールオーバー動作の確認
67+
68+
Router1 側を一時的に切った場合の例:
69+
70+
```shell
71+
sudo ip netns exec Router1 ip link set veth-rt1-gw1 down # 片系停止
72+
sudo ip netns exec GW1 ping -c 10 10.10.10.10 # 通信ができることを確認
73+
sudo ip netns exec GW2 ping -c 10 10.10.10.10
74+
sudo ip netns exec Router1 ip link set veth-rt1-gw1 up # 復旧
75+
```
76+
77+
### Tips
78+
79+
netnsによる検証環境の作成・削除はそれぞれ以下のコマンドで実行されます。
80+
81+
```shell
82+
sudo systemctl start setup-network.service
83+
sudo systemctl stop setup-network.service
84+
```
85+
86+
各namespaceのIF名・アドレス・ルーティングなどは、`sudo ip netns exec <ns> {{任意のコマンド}}` のようにすれば確認可能です。
87+
88+
```shell
89+
sudo ip netns exec <ns> ip addr
90+
sudo ip netns exec <ns> ip route
91+
```
92+
93+
----
94+
95+
## 解説
96+
97+
### 想定している解答手順
98+
99+
問題文に載っている配線図だけだと、手がかりが少なく、状況の把握が難しいはずです。
100+
そこでまずは、netnsでどのようなコンフィグが投入されているのかを特定し、詳細な構成図を作成してみます。
101+
102+
問題文を見ると、netnsによる検証環境の作成・削除をsystemdでやっていることが分かります。
103+
そこで、setup-network.serviceの設定ファイルを追っていくことで、問題環境の展開を行っているスクリプトファイルにたどり着きます。
104+
105+
```
106+
user@baseimage-ubuntu2404:~$ cat /etc/systemd/system/setup-network.service
107+
[Unit]
108+
Description=ICTSC Lab Network Setup
109+
After=network.target
110+
111+
[Service]
112+
Type=oneshot
113+
RemainAfterExit=yes
114+
ExecStart=/opt/bin/setup-network.sh
115+
ExecStop=/opt/bin/cleanup-network.sh
116+
117+
[Install]
118+
WantedBy=multi-user.target
119+
```
120+
121+
.serviceから見つけた `/opt/bin/setup-network.sh` を開いてコンフィグを確認し、詳細な構成図を作成すると、次のようになることが分かります。
122+
123+
![](/images/2025-pre-round-2nd/mid-solution.png)
124+
125+
この構成からわかることは以下の通りです
126+
127+
1. GWのインターフェースはbondingされている。
128+
1. Router間のサイドリンクは存在するもののupされていない
129+
1. Router側のIPアドレスは単独のInterfaceに紐づいている
130+
131+
bondingの設定に注目すると、`ip netns exec GWx ip link add bond0 type bond` となっており、bondingのmodeが指定されていません。
132+
これは、mode 0、つまり`balance-rr`で動作することを示します。
133+
これはラウンドロビン方式、つまり、パケットをbond0のスレーブになっているそれぞれのインターフェースに順番に送信します。
134+
初期状態の場合、GWのbond0から、Router1, 2に向けて交互にパケットが送信されてしまうため、ARP解決が上手く行えません。これがPingが50%の確率で失敗する原因になっています。
135+
このことは、Router1, 2にtcpdumpを仕掛けて、パケットの動きを観察することで確認できると思います。
136+
137+
解法は主に2通りあり、
138+
139+
- bondを維持しながら、Router1 - 2間のサイドリンクを活用してARP解決させる方法
140+
- bondを廃してマルチパスルーティングを設定する方法
141+
142+
を想定しています。
143+
144+
#### 解法1 サイドリンクの活用
145+
146+
Router間の接続(サイドリンク)を有効にしたうえで、Router1とRouter2それぞれに **ブリッジ(br0)** を作成し、GW接続用のvethインターフェイスと **Router間のvethインターフェイス(veth-rt1-rt2, veth-rt2-rt1)** をブリッジメンバーに追加します。これにより、Router1とRouter2がL2で接続され、どちらのRouterにパケットが到達しても宛先の`10.10.10.10`に到達可能になります。
147+
148+
この解法においては、GW側の設定変更は不要です。
149+
150+
↓ ans.shの例
151+
152+
```shell
153+
#!/bin/bash
154+
155+
echo "Applying bonding solution..."
156+
157+
# Router1: Enable side link and create bridge
158+
ip netns exec Router1 ip link set veth-rt1-rt2 up
159+
ip netns exec Router1 ip link add br0 type bridge
160+
ip netns exec Router1 ip link set veth-rt1-gw1 master br0
161+
ip netns exec Router1 ip link set veth-rt1-gw2 master br0
162+
ip netns exec Router1 ip link set veth-rt1-rt2 master br0
163+
ip netns exec Router1 ip addr del 192.168.70.11/24 dev veth-rt1-gw1 2>/dev/null || true
164+
ip netns exec Router1 ip addr add 192.168.70.11/24 dev br0
165+
ip netns exec Router1 ip link set br0 up
166+
167+
# Router2: Enable side link and create bridge
168+
ip netns exec Router2 ip link set veth-rt2-rt1 up
169+
ip netns exec Router2 ip link add br0 type bridge
170+
ip netns exec Router2 ip link set veth-rt2-gw1 master br0
171+
ip netns exec Router2 ip link set veth-rt2-gw2 master br0
172+
ip netns exec Router2 ip link set veth-rt2-rt1 master br0
173+
ip netns exec Router2 ip addr del 192.168.70.12/24 dev veth-rt2-gw1 2>/dev/null || true
174+
ip netns exec Router2 ip addr add 192.168.70.12/24 dev br0
175+
ip netns exec Router2 ip link set br0 up
176+
177+
echo "Configuration completed!"
178+
```
179+
180+
#### 解法2 ECMPの設定
181+
182+
Router側の設定は解法1と同じくブリッジを構成してRouter間をL2接続します。
183+
184+
GW側では**bondingを削除**し、各vethインターフェイス(veth-gw1-rt1, veth-gw1-rt2等)に直接同じIPアドレスを割り当て、**ECMP(Equal-Cost Multi-Path)**ルーティングで2つのnexthopを設定します(`ip route add 10.10.10.10/32 nexthop via ... dev ... nexthop via ... dev ...`)。これにより、Linuxカーネルのマルチパスルーティング機能を使って負荷分散と冗長性を実現します。
185+
186+
ただし、複数のインターフェイスに同じIPアドレスを設定するため、正しくフェールオーバーさせるためには、リンクダウン時にルートを切り替えられる設定を追加する必要があります。
187+
ignore_routes_with_linkdown などの設定を使って、ダウンしている経路を無視できるようにしてあげるとよいでしょう。
188+
189+
↓ ans.shの例
190+
191+
```shell
192+
#!/bin/bash
193+
194+
echo "Applying Pure ECMP solution..."
195+
196+
# Router1: Enable side link and create bridge
197+
ip netns exec Router1 ip link set veth-rt1-rt2 up
198+
ip netns exec Router1 ip link add br0 type bridge
199+
ip netns exec Router1 ip link set veth-rt1-gw1 master br0
200+
ip netns exec Router1 ip link set veth-rt1-gw2 master br0
201+
ip netns exec Router1 ip link set veth-rt1-rt2 master br0
202+
ip netns exec Router1 ip addr del 192.168.70.11/24 dev veth-rt1-gw1 2>/dev/null || true
203+
ip netns exec Router1 ip addr add 192.168.70.11/24 dev br0
204+
ip netns exec Router1 ip link set br0 up
205+
206+
# Router2: Enable side link and create bridge
207+
ip netns exec Router2 ip link set veth-rt2-rt1 up
208+
ip netns exec Router2 ip link add br0 type bridge
209+
ip netns exec Router2 ip link set veth-rt2-gw1 master br0
210+
ip netns exec Router2 ip link set veth-rt2-gw2 master br0
211+
ip netns exec Router2 ip link set veth-rt2-rt1 master br0
212+
ip netns exec Router2 ip addr del 192.168.70.12/24 dev veth-rt2-gw1 2>/dev/null || true
213+
ip netns exec Router2 ip addr add 192.168.70.12/24 dev br0
214+
ip netns exec Router2 ip link set br0 up
215+
216+
# GW1: Remove bonding and configure ECMP
217+
ip netns exec GW1 ip route del 10.10.10.10/32 via 192.168.70.11 2>/dev/null || true
218+
ip netns exec GW1 ip route del 10.10.10.10/32 via 192.168.70.12 2>/dev/null || true
219+
ip netns exec GW1 ip link set bond0 down 2>/dev/null
220+
ip netns exec GW1 ip link set veth-gw1-rt1 nomaster 2>/dev/null
221+
ip netns exec GW1 ip link set veth-gw1-rt2 nomaster 2>/dev/null
222+
ip netns exec GW1 ip addr del 192.168.70.1/24 dev bond0 2>/dev/null || true
223+
ip netns exec GW1 ip link del bond0 2>/dev/null
224+
ip netns exec GW1 ip addr add 192.168.70.1/24 dev veth-gw1-rt1
225+
ip netns exec GW1 ip addr add 192.168.70.1/24 dev veth-gw1-rt2
226+
ip netns exec GW1 ip link set veth-gw1-rt1 up
227+
ip netns exec GW1 ip link set veth-gw1-rt2 up
228+
ip netns exec GW1 sysctl -w net.ipv4.conf.veth-gw1-rt1.ignore_routes_with_linkdown=1 >/dev/null
229+
ip netns exec GW1 sysctl -w net.ipv4.conf.veth-gw1-rt2.ignore_routes_with_linkdown=1 >/dev/null
230+
ip netns exec GW1 ip route add 10.10.10.10/32 \
231+
nexthop via 192.168.70.11 dev veth-gw1-rt1 weight 1 \
232+
nexthop via 192.168.70.12 dev veth-gw1-rt2 weight 1
233+
234+
# GW2: Remove bonding and configure ECMP
235+
ip netns exec GW2 ip route del 10.10.10.10/32 via 192.168.70.11 2>/dev/null || true
236+
ip netns exec GW2 ip route del 10.10.10.10/32 via 192.168.70.12 2>/dev/null || true
237+
ip netns exec GW2 ip link set bond0 down 2>/dev/null
238+
ip netns exec GW2 ip link set veth-gw2-rt1 nomaster 2>/dev/null
239+
ip netns exec GW2 ip link set veth-gw2-rt2 nomaster 2>/dev/null
240+
ip netns exec GW2 ip addr del 192.168.70.2/24 dev bond0 2>/dev/null || true
241+
ip netns exec GW2 ip link del bond0 2>/dev/null
242+
ip netns exec GW2 ip addr add 192.168.70.2/24 dev veth-gw2-rt1
243+
ip netns exec GW2 ip addr add 192.168.70.2/24 dev veth-gw2-rt2
244+
ip netns exec GW2 ip link set veth-gw2-rt1 up
245+
ip netns exec GW2 ip link set veth-gw2-rt2 up
246+
ip netns exec GW2 sysctl -w net.ipv4.conf.veth-gw2-rt1.ignore_routes_with_linkdown=1 >/dev/null
247+
ip netns exec GW2 sysctl -w net.ipv4.conf.veth-gw2-rt2.ignore_routes_with_linkdown=1 >/dev/null
248+
ip netns exec GW2 ip route add 10.10.10.10/32 \
249+
nexthop via 192.168.70.11 dev veth-gw2-rt1 weight 1 \
250+
nexthop via 192.168.70.12 dev veth-gw2-rt2 weight 1
251+
252+
echo "Configuration completed!"
253+
254+
```

0 commit comments

Comments
 (0)