LinuxカーネルはどのようにハードウェアTXとRXフィルタリングモードを保存しますか?

LinuxカーネルはどのようにハードウェアTXとRXフィルタリングモードを保存しますか?

私は自分のethtoolバージョンと同様に、特定のネットワークインターフェイスのタイムスタンプ情報を取得するCプログラムを作業しています。私の目標は情報を印刷することです$ ethtool -T myNetIf。それは次のとおりです。

Time stamping parameters for myNetIf:
Capabilities:
    hardware-transmit     (SOF_TIMESTAMPING_TX_HARDWARE)
    software-transmit     (SOF_TIMESTAMPING_TX_SOFTWARE)
    hardware-receive      (SOF_TIMESTAMPING_RX_HARDWARE)
    software-receive      (SOF_TIMESTAMPING_RX_SOFTWARE)
    software-system-clock (SOF_TIMESTAMPING_SOFTWARE)
    hardware-raw-clock    (SOF_TIMESTAMPING_RAW_HARDWARE)
PTP Hardware Clock: 0
Hardware Transmit Timestamp Modes:
    off                   (HWTSTAMP_TX_OFF)
    on                    (HWTSTAMP_TX_ON)
Hardware Receive Filter Modes:
    none                  (HWTSTAMP_FILTER_NONE)
    all                   (HWTSTAMP_FILTER_ALL)

コマンドライン出力のみを取得したくないので、ioctl呼び出しを使用してethtoolからこの情報を照会し、フラグを符号なし整数に戻すことができることがわかりました。

struct ifreq ifr;
memset(&ifr, 0, sizeof(struct ifreq));
struct ethtool_ts_info etsi;
memset(&etsi, 0, sizeof(struct ethtool_ts_info));

etsi.cmd = ETHTOOL_GET_TS_INFO;
strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); // dev is read from stdin
ifr.ifr_data = (void *)&etsi;

ioctl(sock, SIOCETHTOOL, &ifr); // sock is an AF_INET socket

ethtool_ts_info私が望むデータを含む構造が定義されていると思います。ここ。特に、私は、とso_timestampingフィールドtx_typesrx_filters持っています。

so_timestamping同じインタフェース例を使用すると、値は0x5f、またはです0101 1111。一度見てnet_tstamp.h 確認するこれは予想できる兆候です。

しかし、私の問題はtx_typessum値を解釈することですrx_filters。私が仮定する値はtx_types次のとおりです0x30011ここで、3番目のビットはHWTSTAMP_TX_ON、4番目のビットはHWTSTAMP_TX_OFFです)。または、可能な転送モードは次のように定義されているため列挙型4つの値がある場合、結果0100は各int列挙値が2ビットである可能性があります。

そうではありません。tx_types実際の値はです0x7fdd。で「HW_TX_OFFとON」を正確にどのように取得する必要がありますか0x7fdd?私はrx_filtersその価値がさらに混乱していると思います。それはどういう0x664758eb意味ですか?

カーネルのソースコード自体以外に、役に立つ情報がたくさん見つかりませんでした。私はすべてをうまくやっていると思います。結果を理解するのに助けが必要です。

答え1

これは恥ずかしいです。コードを確認したところ、構造の正しく初期化に失敗したことがわかりました。ただ予想した方法ではありませんでした。また、課題の前からゴミの値が残る可能性を排除したと考えていたため、トラブルシューティングに必要な全体的なコンテキストを提供していませんでした。

私が投稿したサンプルコードは、私が定義したインクルードを埋める関数の一部ですethtool_ts_info

typedef struct {
    unsigned int soTimestamping;
    unsigned int txTypes;
    unsigned int rxFilters;
} tsCapsFilters_t;

関数ユーザーはこの構造を直接初期化し、関数はそれを満たすだけです。したがって、予想される使用法は次のとおりです。

tsCapsFilters_t tsInfo; // struct full of junk
if(getTsInfo(nameOfNetIf, &tsInfo, errMsgBuf, ERR_BUF_SZ) < 0) {
    // handle errors in here
}
printf("%x\n", tsInfo.soTimestamping); // struct filled out by getTsInfo

tx_typesしかし、私が犯した間違いは、構造体(私の関数の内部)rx_filtersから構造体(ユーザーに提供されている)にコピーするのを忘れたことです。したがって、私のプログラムはすべてのフィールドを正しく取得しますが、3つの値をすべて返す必要がある場合にのみ関数を返します。ethtool_ts_infotsCapsFilters_tso_timestamping

printf("%x\n", tsInfo.soTimestamping); // printed the expected values
printf("%x\n", tsInfo.txTypes); // printed junk
printf("%x\n", tsInfo.rxFilters); // printed junk

私が言ったように、厄介です。私は賞金を試してみて、将来的に私の構造にもっと注意します。

答え2

struct ethtool_ts_info etsi;

ifr.ifr_data = (void *)&etsi;

~からネットワークタイムスタンプのカーネルドキュメント、あなたのプログラムから呼び出されたioctl(SIOCSHWTSTAMP)は、その型のいくつかの構造を満たす必要があることを理解しています。hwtstamp_config

次のように定義されますstruct hwtstamp_config

struct hwtstamp_config {
    int flags;  /* no flags defined right now, must be zero */
    int tx_type;    /* HWTSTAMP_TX_* */
    int rx_filter;  /* HWTSTAMP_FILTER_* */
};

struct ifreqへのポインタでioctl(SIOCSHWTSTAMP)を呼び出して、目的の動作をカーネルと特定のデバイスに渡します。ifr_dataはhwtstamp_config構造体を指します。...すべてのプロセスは同じ方法でこの構造をioctl(SIOCGHWTSTAMP)に渡すことで実際の構成を読み取ることができます。

プログラムが返されたデータを使用する場合は、次のように定義されていますstruct ethtool_ts_info

struct ethtool_ts_info {
    __u32   cmd;
    __u32   so_timestamping;
    __s32   phc_index;
    __u32   tx_types;
    __u32   tx_reserved[3];
    __u32   rx_filters;
    __u32   rx_reserved[3];
};

これは、あなたのプログラムが3番目のint(具体的には)以上の値を抽出することを意味します。取引タイプそしてrx_filtersあなたが興味を持っているのは)あなたが報告したように…無意味
これ(構成つまり、能力ではありません)取引タイプそしてrx_filtersifr.ifr_dataアドレスから始めて、それぞれ2番目と3番目のintから取得する必要があります。

この場合、構成値は望ましくなく、ioctl-ing(SIOCGHWTSTAMP)は適切なアプローチではありません。

関連情報