リモート インターフェイスとしての Linux システム (g_ether ドライバーを備えた USB ガジェット)

リモート インターフェイスとしての Linux システム (g_ether ドライバーを備えた USB ガジェット)

私は現在、センサー/モーター制御機能を実行する組み込みLinuxシステムと、ユーザーがシステムを制御できるようにするGUIアプリケーションを作成するプロジェクトに取り組んでいます。将来的には、両方のアプリケーションを1つのシステムで実行する予定ですが、当面は、これを既存のマシンへのアップグレードとしてインストールできるようにしたいと考えています。既存のコントローラーボードには、GUIを設計どおりに実行する機能がないため、別のSBCで実行します(現在は、ODロイドC4Android 9を実行している場合

2 つのシステム間の通信 API を策定し、静的 IP アドレスを使用して 2 つのシステム間で直接イーサネット接続を実行して初期テストを行ってきましたが、Android の展開要件と制限のため、製品の実際の展開には別の接続方法を検討する必要があります。顧客が WiFi またはイーサネット経由で GUI システム上のインターネットに接続できるようにする必要があるため、ODroid のオンボード イーサネット ポートをその目的に使用することはできません。さらに、Android カーネルには、一度に 1 つのネットワーク接続しかアクティブにできないという内部動作があります。

Android のネットワーク優先順位付けルールの例外は、USB ネットワーク インターフェースです。Linux コントローラー システムと Android デバイス自体はどちらも、リモート ホストへのネットワーク インターフェースとして表示される機能を備えています。コントローラー システムでは USB ガジェット ポートが使用可能で、g_etherシステム イメージでカーネル モジュールを有効にしました。GUI システムでは USB OTG ポートがあり、Android システム設定で USB テザリングを有効にできます。

それぞれのインターフェースを使用して、これらのシステムと Windows 開発システムの間で通信を行うことはできましたが、これまでのところ、どちらかのソリューションを他のソリューションと通信させる方法がわかりません。

リモート インターフェイスとしての Linux システム (g_ether ドライバーを備えた USB ガジェット)

  • Linux システムに g_ether カーネル モジュールをロードすると、usb0インターフェイスが作成されます。
# modprobe g_ether
# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.42.128.107  netmask 255.255.255.0  broadcast 10.42.128.255
        inet6 fe80::206:cff:fe01:1027  prefixlen 64  scopeid 0x20<link>
        ether 00:06:0c:01:10:27  txqueuelen 1000  (Ethernet)
        RX packets 500  bytes 54062 (52.7 KiB)
        RX errors 0  dropped 46  overruns 0  frame 0
        TX packets 0  bytes 24423 (23.8 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 0  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

usb0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::24b:5bfc:8a9e:b148  prefixlen 64  scopeid 0x20<link>
        ether 9a:8c:fa:85:ec:a1  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1  bytes 96 (96.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
  • Linux システムのガジェット ポートから Android システムのホスト ポートに USB ケーブルを接続すると、Android 上にインターフェースがすぐに作成され、 Linux 上のインターフェースusb0の IP アドレスが生成されます。usb0

アンドロイド:

odroidc4:/ # ifconfig usb0
usb0      Link encap:Ethernet  HWaddr fa:4c:95:c0:8d:18  Driver cdc_subset
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 TX bytes:0

リナックス:

# ifconfig usb0
usb0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 169.254.119.94  netmask 255.255.0.0  broadcast 169.254.255.255
        inet6 fe80::24b:5bfc:8a9e:b148  prefixlen 64  scopeid 0x20<link>
        ether 9a:8c:fa:85:ec:a1  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1  bytes 96 (96.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
  • Androidシステムでインターフェースを起動してもIPアドレスは割り当てられないので、Linuxシステムが自動割り当てする169.254/16のスペースを使って手動で割り当てる必要があります。
odroidc4:/ # ifconfig usb0 up
odroidc4:/ # ifconfig usb0
usb0      Link encap:Ethernet  HWaddr fa:4c:95:c0:8d:18  Driver cdc_subset
          inet6 addr: fe80::f84c:95ff:fec0:8d18/64 Scope: Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:117 errors:4 dropped:75 overruns:0 frame:4
          TX packets:27 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:5080 TX bytes:4897

odroidc4:/ # ip addr add 169.254.1.1/16 broadcast 169.254.255.255 dev usb0
odroidc4:/ # ifconfig usb0
usb0      Link encap:Ethernet  HWaddr fa:4c:95:c0:8d:18  Driver cdc_subset
          inet addr:169.254.1.1  Bcast:169.254.255.255  Mask:255.255.0.0
          inet6 addr: fe80::f84c:95ff:fec0:8d18/64 Scope: Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:117 errors:4 dropped:75 overruns:0 frame:4
          TX packets:44 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:5080 TX bytes:8528

この時点で 2 つの問題があります。1 つ目は、どちらかのデバイスからもう一方のデバイスに ping を実行しても応答がないことです。Android 側のパケット数を見ると、Linux 側から ping を受信して​​いるものの応答がないように見えますが、これは 2 つ目の問題、つまり Android 側のルーティング テーブルが期待どおりに動作していないことが原因である可能性があります。Android システムでアクティブなインターネット接続があるときにこれを動作させる必要があるため、同時にイーサネットを接続しています。ルーティングを確認すると、次のようになります。

odroidc4:/ # ip route list
169.254.0.0/16 dev usb0 proto kernel scope link src 169.254.1.1
10.42.128.0/24 dev eth0 proto kernel scope link src 10.42.128.166
odroidc4:/ # ip route get 169.254.119.94
169.254.119.94 via 10.42.128.2 dev eth0 table eth0 src 10.42.128.166 uid 0
    cache
odroidc4:/ # ip route show table 0
default via 10.42.128.2 dev eth0 table eth0 proto static
...

リモートインターフェースとしての Android システム (OTG ポートによる USB テザリング)

このシナリオでは、一方向の通信が機能するため、少し近づくことができるようです。

  • Linux イメージに必要なドライバーを追加した後、Android OTG ポートから Linux ホスト ポートにケーブルを接続すると、システムが USB デバイスを認識していることが次のように表示されますdmesg
[  235.710937] usb 1-2.3: new full-speed USB device number 7 using at91_ohci
[  235.862304] rndis_host 1-2.3:1.0 usb0: register 'rndis_host' at usb-at91-2.3, RNDIS device, 32:1d:e8:fc:dd:8
  • インターフェースusb0がすぐに作成され、Linux 側で IP アドレスが割り当てられます。
# ifconfig usb0
usb0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 169.254.249.80  netmask 255.255.0.0  broadcast 169.254.255.255
        inet6 fe80::e341:f9b1:b676:99b7  prefixlen 64  scopeid 0x20<link>
        ether 32:1d:e8:fc:dd:80  txqueuelen 1000  (Ethernet)
        RX packets 69  bytes 13572 (13.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 73  bytes 18251 (17.8 KiB)
        TX errors 8  dropped 0 overruns 0  carrier 0  collisions 0
  • Android 側で設定で USB テザリングが有効になっている場合、usb0 インターフェイスが表示されますが、最初はダウンしています。起動しても IP アドレスは付与されないため、手動で割り当てましたが、最初のシナリオと同様に、ルーティング テーブルは期待どおりに機能していないようです。
odroidc4:/ # ifconfig usb0
usb0      Link encap:Ethernet  HWaddr de:75:5c:41:2a:e6
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 TX bytes:0
odroidc4:/ # ifconfig usb0 up
odroidc4:/ # ifconfig usb0
usb0      Link encap:Ethernet  HWaddr de:75:5c:41:2a:e6
          inet6 addr: fe80::dc75:5cff:fe41:2ae6/64 Scope: Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:10 errors:0 dropped:0 overruns:0 frame:0
          TX packets:12 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:1090 TX bytes:2751
odroidc4:/ # ip addr add 169.254.1.1/16 broadcast 169.254.255.255 dev usb0
odroidc4:/ # ip route
10.42.128.0/24 dev eth0 proto kernel scope link src 10.42.128.166
169.254.0.0/16 dev usb0 proto kernel scope link src 169.254.1.1
odroidc4:/ # ip route get 169.254.249.80
169.254.249.80 via 10.42.128.2 dev eth0 table eth0 src 10.42.128.166 uid 0
    cache
  • ただし、このシナリオでは、インターフェースを手動で指定することで、Android 側からの通信を正常に行うことができます。
odroidc4:/ # ping -c 5 -I usb0 169.254.249.80
PING 169.254.249.80 (169.254.249.80) from 169.254.1.1 usb0: 56(84) bytes of data.
64 bytes from 169.254.249.80: icmp_seq=1 ttl=64 time=1.56 ms
64 bytes from 169.254.249.80: icmp_seq=2 ttl=64 time=1.89 ms
64 bytes from 169.254.249.80: icmp_seq=3 ttl=64 time=1.71 ms
64 bytes from 169.254.249.80: icmp_seq=4 ttl=64 time=1.75 ms
64 bytes from 169.254.249.80: icmp_seq=5 ttl=64 time=1.85 ms

--- 169.254.249.80 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4006ms
2|odroidc4:/ # ping6 -c5 ff02::1%usb0
PING ff02::1%usb0(ff02::1) 56 data bytes
64 bytes from fe80::dc75:5cff:fe41:2ae6: icmp_seq=1 ttl=64 time=0.202 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=1 ttl=64 time=1.91 ms (DUP!)
64 bytes from fe80::dc75:5cff:fe41:2ae6: icmp_seq=2 ttl=64 time=0.196 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=2 ttl=64 time=1.80 ms (DUP!)
64 bytes from fe80::dc75:5cff:fe41:2ae6: icmp_seq=3 ttl=64 time=0.199 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=3 ttl=64 time=1.37 ms (DUP!)
64 bytes from fe80::dc75:5cff:fe41:2ae6: icmp_seq=4 ttl=64 time=0.199 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=4 ttl=64 time=1.85 ms (DUP!)
64 bytes from fe80::dc75:5cff:fe41:2ae6: icmp_seq=5 ttl=64 time=0.205 ms

--- ff02::1%usb0 ping statistics ---
5 packets transmitted, 5 received, +4 duplicates, 0% packet loss, time 4004ms
rtt min/avg/max/mdev = 0.196/0.883/1.914/0.776 ms
  • Linux 側から発信されたトラフィックはまだ機能しません。これはおそらく、Android 側のルーティングの問題により、戻りトラフィックが正しくルーティングされないことが原因です。
# ping -c 5 -I usb0 169.254.1.1
PING 169.254.1.1 (169.254.1.1) from 169.254.249.80 usb0: 56(84) bytes of data.

--- 169.254.1.1 ping statistics ---
5 packets transmitted, 0 received, 100% packet loss, time 4295ms
# ping6 -c 5 ff02::1%usb0
PING ff02::1%usb0(ff02::1) 56 data bytes
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=1 ttl=64 time=0.522 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=2 ttl=64 time=0.302 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=3 ttl=64 time=0.376 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=4 ttl=64 time=0.383 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=5 ttl=64 time=0.385 ms

--- ff02::1%usb0 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4009ms
rtt min/avg/max/mdev = 0.302/0.393/0.522/0.074 ms

どちらのシナリオでも、問題の根本は、Android 側のルーティング テーブルが USB インターフェイスを介してトラフィックを正しくルーティングしていないこと、および Android 側が IP アドレスを自動的に割り当てないのに対し、Linux 側が割り当てることにあるようです。Linux ガジェット インターフェイス/Android ホストの場合、これらの問題はある程度理解できますが、Android OTG ポート テザリング/Linux ホストの場合、Android システムがテザリング接続を制御しているため、正しくルーティングされると予想されます。

答え1

こんにちは、@rdowell、

この問題を解決するには、Android デバイスにメイン ルート テーブルを追加する必要があります。

ip rule add from all lookup main pref 1

関連情報