pyspaに来ています
Linuxでは一つのネットワークインターフェイスに複数のIPアドレスを紐付ける方法として、
- エイリアスを使う方法 (バージョン2.0からサポート)
- ip(8)コマンドのaddr addサブコマンドを使う方法 (バージョン2.2からサポート)
があるのに、残念なことに前者しか今日まで知らなかったのでそれを書く。
この違いは、
- ioctl(2)によるインターフェイスの操作
- netlink(7)によるインターフェイスの操作
というところにも表れているので、それぞれの方法でeth0のIPアドレスを取得する方法を調べてみた。
ioctlを使う方法:
非常に単純。この方法だと紐づいているIPアドレスを1つしか取得できないことがわかる。
netlinkソケットを使う方法:
なんでこんな複雑なんだろうって思う。ドキュメントがないので結局カーネルのソース読んだし。
途中で調べた事も書いておく。
Linuxにおけるネットワークデバイスとアドレスの表現
ネットワークデバイスはnet_device構造体(linux/netdevice.h
) で表現されている。
struct net_device { char name[IFNAMSIZ]; struct hlist_node name_hlist; char *ifalias; unsigned long mem_end; unsigned long mem_start; unsigned long base_addr; unsigned int irq; unsigned long state; struct list_head dev_list; struct list_head napi_list; struct list_head unreg_list; netdev_features_t features; netdev_features_t hw_features; netdev_features_t wanted_features; netdev_features_t vlan_features; ... struct in_device __rcu *ip_ptr; struct inet6_dev __rcu *ip6_ptr; ... };
IPv4インターフェイスの情報はip_ptrが参照するin_device構造体(linux/inetdevice.h
)に、IPv6インターフェイスの情報はip6_ptrが参照するinet6_dev構造体(include/net/if_inet6.h
)に定義されている。
struct in_device:
struct in_device { struct net_device *dev; atomic_t refcnt; int dead; struct in_ifaddr *ifa_list; /* IP ifaddr chain */ struct ip_mc_list __rcu *mc_list; /* IP multicast filter chain */ int mc_count; /* Number of installed mcasts */ spinlock_t mc_tomb_lock; struct ip_mc_list *mc_tomb; unsigned long mr_v1_seen; unsigned long mr_v2_seen; unsigned long mr_maxdelay; unsigned char mr_qrv; unsigned char mr_gq_running; unsigned char mr_ifc_count; struct timer_list mr_gq_timer; /* general query timer */ struct timer_list mr_ifc_timer; /* interface change timer */ struct neigh_parms *arp_parms; struct ipv4_devconf cnf; struct rcu_head rcu_head; };
struct inet6_dev:
struct inet6_dev { struct net_device *dev; struct list_head addr_list; struct ifmcaddr6 *mc_list; struct ifmcaddr6 *mc_tomb; spinlock_t mc_lock; unsigned char mc_qrv; unsigned char mc_gq_running; unsigned char mc_ifc_count; unsigned long mc_v1_seen; unsigned long mc_maxdelay; struct timer_list mc_gq_timer; /* general query timer */ struct timer_list mc_ifc_timer; /* interface change timer */ struct ifacaddr6 *ac_list; rwlock_t lock; atomic_t refcnt; __u32 if_flags; int dead; ... struct neigh_parms *nd_parms; struct inet6_dev *next; struct ipv6_devconf cnf; struct ipv6_devstat stats; unsigned long tstamp; /* ipv6InterfaceTable update timestamp */ struct rcu_head rcu; };
in_device構造体に紐づいているIPアドレスのリストはifa_listで、inet6_dev構造体に紐づいているIPアドレスのリストはaddr_listで表現されている。