午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

網(wǎng)絡(luò)設(shè)備的IP地址結(jié)構(gòu) - UNIX Resources Network

 jijo 2009-10-13






====================

(1) 在TCPIP協(xié)議環(huán)境下,
網(wǎng)絡(luò)設(shè)備結(jié)構(gòu)(net_device)具有一個(gè)ip_ptr指針指向IP協(xié)議的設(shè)備參數(shù)塊(in_device),
它包含設(shè)備IP地址結(jié)構(gòu)(in_ifaddr)的鏈表指針(ifa_list).
IP地址結(jié)構(gòu)鏈可以為一個(gè)網(wǎng)絡(luò)設(shè)備配置多個(gè)IP地址,
使得局域網(wǎng)中的單臺(tái)主機(jī)能模擬多臺(tái)主機(jī)的作用.

(2) 設(shè)備IP地址的配置由應(yīng)用程序通過ioctl()系統(tǒng)調(diào)用使用ifreq參數(shù)結(jié)構(gòu)來完成.
同一設(shè)備的不同IP地址用不同的設(shè)備別名來標(biāo)識(shí),
例如"eth0:1"和"eth0:2"分別代表設(shè)備eht0的兩個(gè)地址. 當(dāng)增加一個(gè)別名設(shè)備時(shí),
如果它的地址與已有地址屬于同一子網(wǎng), 則它的地址被標(biāo)記為"從屬"(IFA_F_SECONDARY).
當(dāng)設(shè)備最后一個(gè)別名被刪除時(shí), 設(shè)備的IP參數(shù)塊將被釋放.設(shè)備地址參數(shù)發(fā)生改變時(shí),
將通過地址消息鏈(inetaddr_chain)向有關(guān)子系統(tǒng)發(fā)送通知消息,
例如路由子系統(tǒng)用來刷新轉(zhuǎn)發(fā)表和路由緩沖表.

struct net_device
{
...
void *ip_ptr; /* IPv4 specific data */
...
}
struct in_device
{
struct net_device *dev;
atomic_t refcnt;
rwlock_t lock;
int dead;
struct in_ifaddr *ifa_list; /* IP ifaddr chain */
struct ip_mc_list *mc_list; /* IP multicast filter chain */
unsigned long mr_v1_seen;
struct neigh_parms *arp_parms;
struct ipv4_devconf cnf;
};
struct in_ifaddr
{
struct in_ifaddr *ifa_next;
struct in_device *ifa_dev;
u32 ifa_local; 設(shè)備地址
u32 ifa_address; 點(diǎn)對(duì)點(diǎn)設(shè)備的對(duì)端地址
u32 ifa_mask; 網(wǎng)絡(luò)地址掩碼
u32 ifa_broadcast; 設(shè)備的廣播地址
u32 ifa_anycast;
unsigned char ifa_scope; 設(shè)備地址的尋址范圍
unsigned char ifa_flags; 地址標(biāo)志
unsigned char ifa_prefixlen; 設(shè)備網(wǎng)絡(luò)地址長(zhǎng)度
char ifa_label[IFNAMSIZ]; 設(shè)備IP地址標(biāo)簽
};

/*
* Interface request structure used for socket
* ioctl's. All interface ioctl's must have parameter
* definitions which begin with ifr_name. The
* remainder may be interface specific.
*/

struct ifreq
{
#define IFHWADDRLEN 6
#define IFNAMSIZ 16
union
{
char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */
} ifr_ifrn;

union {
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
struct sockaddr ifru_netmask;
struct sockaddr ifru_hwaddr;
short ifru_flags;
int ifru_ivalue;
int ifru_mtu;
struct ifmap ifru_map;
char ifru_slave[IFNAMSIZ]; /* Just fits the size */
char ifru_newname[IFNAMSIZ];
char * ifru_data;
} ifr_ifru;
};

; net/ipv4/devinet.c:

int devinet_ioctl(unsigned int cmd, void *arg)
{
struct ifreq ifr;
struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
struct in_device *in_dev;
struct in_ifaddr **ifap = NULL;
struct in_ifaddr *ifa = NULL;
struct net_device *dev;
char *colon;
int ret = 0;

/*
* Fetch the caller's info block into kernel space
*/

if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
return -EFAULT;
ifr.ifr_name[IFNAMSIZ-1] = 0;

colon = strchr(ifr.ifr_name, ':'); 從設(shè)備地址標(biāo)簽中取設(shè)備名稱
if (colon)
*colon = 0;

#ifdef CONFIG_KMOD
dev_load(ifr.ifr_name); 加載相應(yīng)名稱的設(shè)備驅(qū)動(dòng)模塊
#endif

switch(cmd) {
case SIOCGIFADDR: /* Get interface address */
case SIOCGIFBRDADDR: /* Get the broadcast address */
case SIOCGIFDSTADDR: /* Get the destination address */
case SIOCGIFNETMASK: /* Get the netmask for the interface */
/* Note that this ioctls will not sleep,
so that we do not impose a lock.
One day we will be forced to put shlock here (I mean SMP)
*/
memset(sin, 0, sizeof(*sin));
sin->sin_family = AF_INET;
break;

case SIOCSIFFLAGS:
if (!capable(CAP_NET_ADMIN))
return -EACCES;
break;
case SIOCSIFADDR: /* Set interface address (and family) */
case SIOCSIFBRDADDR: /* Set the broadcast address */
case SIOCSIFDSTADDR: /* Set the destination address */
case SIOCSIFNETMASK: /* Set the netmask for the interface */
if (!capable(CAP_NET_ADMIN))
return -EACCES;
if (sin->sin_family != AF_INET)
return -EINVAL;
break;
default:
return -EINVAL;
}

dev_probe_lock();
rtnl_lock();

if ((dev = __dev_get_by_name(ifr.ifr_name)) == NULL) { 取設(shè)備結(jié)構(gòu)
ret = -ENODEV;
goto done;
}

if (colon)
*colon = ':'; 恢復(fù)用戶地址標(biāo)簽

if ((in_dev=__in_dev_get(dev)) != NULL) { 取IP設(shè)備塊
for (ifap=&in_dev->ifa_list; (ifa=*ifap) != NULL; ifap=&ifa->ifa_next)
if (strcmp(ifr.ifr_name, ifa->ifa_label) == 0)
break; 取用戶地址標(biāo)簽對(duì)應(yīng)的設(shè)備地址結(jié)構(gòu)
}

if (ifa == NULL && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS) {
除了設(shè)置地址和設(shè)置標(biāo)志
ret = -EADDRNOTAVAIL;
goto done;
}

switch(cmd) {
case SIOCGIFADDR: /* Get interface address */
sin->sin_addr.s_addr = ifa->ifa_local; 取設(shè)備IP地址
goto rarok;

case SIOCGIFBRDADDR: /* Get the broadcast address */
sin->sin_addr.s_addr = ifa->ifa_broadcast; 取設(shè)備IP廣播地址
goto rarok;

case SIOCGIFDSTADDR: /* Get the destination address */
sin->sin_addr.s_addr = ifa->ifa_address; 取點(diǎn)對(duì)點(diǎn)設(shè)備的對(duì)端IP地址
goto rarok;

case SIOCGIFNETMASK: /* Get the netmask for the interface */
sin->sin_addr.s_addr = ifa->ifa_mask; 取設(shè)備的IP地址掩碼
goto rarok;

case SIOCSIFFLAGS: 設(shè)置設(shè)備標(biāo)志
if (colon) {
if (ifa == NULL) {
ret = -EADDRNOTAVAIL;
break;
}
if (!(ifr.ifr_flags&IFF_UP)) 如果標(biāo)志為關(guān)閉設(shè)備
inet_del_ifa(in_dev, ifap, 1); 破環(huán)性刪除該地址結(jié)構(gòu)
break;
}
ret = dev_change_flags(dev, ifr.ifr_flags);
break;

case SIOCSIFADDR: /* Set interface address (and family) */
if (inet_abc_len(sin->sin_addr.s_addr) < 0) { 取網(wǎng)絡(luò)地址位長(zhǎng)
ret = -EINVAL;
break;
}

if (!ifa) { 如果設(shè)備尚無地址結(jié)構(gòu)
if ((ifa = inet_alloc_ifa()) == NULL) { 分配地址結(jié)構(gòu)
ret = -ENOBUFS;
break;
}
if (colon) 如果地址標(biāo)簽為設(shè)備別名標(biāo)簽
memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
else
memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
} else { 如果修改設(shè)備地址
ret = 0;
if (ifa->ifa_local == sin->sin_addr.s_addr)
break;
inet_del_ifa(in_dev, ifap, 0); 從鏈接中刪除該地址結(jié)構(gòu)
ifa->ifa_broadcast = 0;
ifa->ifa_anycast = 0;
}

ifa->ifa_address =
ifa->ifa_local = sin->sin_addr.s_addr; 將設(shè)備地址和對(duì)端地址設(shè)置為新地址

if (!(dev->flags&IFF_POINTOPOINT)) { 如果非點(diǎn)對(duì)點(diǎn)設(shè)備
ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address); 取地址的網(wǎng)絡(luò)地址長(zhǎng)度
ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen); 求網(wǎng)絡(luò)掩碼
if ((dev->flags&IFF_BROADCAST) && ifa->ifa_prefixlen < 31)
ifa->ifa_broadcast = ifa->ifa_address|~ifa->ifa_mask; 設(shè)置標(biāo)準(zhǔn)廣播地址
} else { 如果是點(diǎn)對(duì)點(diǎn)設(shè)備
ifa->ifa_prefixlen = 32; 網(wǎng)絡(luò)地址長(zhǎng)度為32
ifa->ifa_mask = inet_make_mask(32);
}
ret = inet_set_ifa(dev, ifa); 添加設(shè)備地址
break;

case SIOCSIFBRDADDR: /* Set the broadcast address */
if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
inet_del_ifa(in_dev, ifap, 0);
ifa->ifa_broadcast = sin->sin_addr.s_addr;
inet_insert_ifa(ifa);
}
break;

case SIOCSIFDSTADDR: /* Set the destination address */
if (ifa->ifa_address != sin->sin_addr.s_addr) {
if (inet_abc_len(sin->sin_addr.s_addr) < 0) {
ret = -EINVAL;
break;
}
inet_del_ifa(in_dev, ifap, 0);
ifa->ifa_address = sin->sin_addr.s_addr;
inet_insert_ifa(ifa);
}
break;

case SIOCSIFNETMASK: /* Set the netmask for the interface */

/*
* The mask we set must be legal.
*/
if (bad_mask(sin->sin_addr.s_addr, 0)) {
ret = -EINVAL;
break;
}

if (ifa->ifa_mask != sin->sin_addr.s_addr) {
inet_del_ifa(in_dev, ifap, 0);
ifa->ifa_mask = sin->sin_addr.s_addr;
ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
inet_insert_ifa(ifa);
}
break;
}
done:
rtnl_unlock();
dev_probe_unlock();
return ret;

rarok:
rtnl_unlock();
dev_probe_unlock();
if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
return -EFAULT;
return 0;
}
static int
inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
{
struct in_device *in_dev = __in_dev_get(dev);

ASSERT_RTNL();

if (in_dev == NULL) { 如果IP設(shè)備塊不存在
in_dev = inetdev_init(dev); 分配IP設(shè)備塊
if (in_dev == NULL) {
inet_free_ifa(ifa);
return -ENOBUFS;
}
}
if (ifa->ifa_dev != in_dev) {
BUG_TRAP(ifa->ifa_dev==NULL);
in_dev_hold(in_dev);
ifa->ifa_dev=in_dev; 將地址結(jié)構(gòu)綁定到IP設(shè)備塊上
}
if (LOOPBACK(ifa->ifa_local)) 如果設(shè)備地址是回送地址
ifa->ifa_scope = RT_SCOPE_HOST; 地址的尋址范圍為主機(jī)內(nèi)部
return inet_insert_ifa(ifa);
}
static int
inet_insert_ifa(struct in_ifaddr *ifa)
{
struct in_device *in_dev = ifa->ifa_dev;
struct in_ifaddr *ifa1, **ifap, **last_primary;

ASSERT_RTNL();

if (ifa->ifa_local == 0) {
inet_free_ifa(ifa);
return 0;
}

ifa->ifa_flags &= ~IFA_F_SECONDARY; 清除地址結(jié)構(gòu)的從屬標(biāo)志
last_primary = &in_dev->ifa_list; 取IP設(shè)備塊地址鏈表指針地址

for (ifap=&in_dev->ifa_list; (ifa1=*ifap)!=NULL; ifap=&ifa1->ifa_next) {
掃描IP設(shè)備塊上的地址鏈
if (!(ifa1->ifa_flags&IFA_F_SECONDARY) && ifa->ifa_scope <= ifa1->ifa_scope)
last_primary = &ifa1->ifa_next;
if (ifa1->ifa_mask == ifa->ifa_mask && inet_ifa_match(ifa1->ifa_address, ifa)) {
; 如果與鏈中某個(gè)地址具有相同的網(wǎng)絡(luò)地址
if (ifa1->ifa_local == ifa->ifa_local) { 如果兩者地址相同
inet_free_ifa(ifa);
return -EEXIST;
}
if (ifa1->ifa_scope != ifa->ifa_scope) { 如果兩者尋址范圍不同
inet_free_ifa(ifa);
return -EINVAL;
}
ifa->ifa_flags |= IFA_F_SECONDARY; 標(biāo)記為從屬地址
}
}

if (!(ifa->ifa_flags&IFA_F_SECONDARY)) {
net_srandom(ifa->ifa_local);
ifap = last_primary;
}

ifa->ifa_next = *ifap;
write_lock_bh(&in_dev->lock);
*ifap = ifa;
write_unlock_bh(&in_dev->lock);

/* Send message first, then call notifier.
Notifier will trigger FIB update, so that
listeners of netlink will know about new ifaddr */
rtmsg_ifa(RTM_NEWADDR, ifa);
notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa); 發(fā)布設(shè)備啟動(dòng)消息

return 0;
}
static void
inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy)
{
struct in_ifaddr *ifa1 = *ifap; 取要?jiǎng)h除地址結(jié)構(gòu)的地址

ASSERT_RTNL();

/* 1. Deleting primary ifaddr forces deletion all secondaries */

if (!(ifa1->ifa_flags&IFA_F_SECONDARY)) { 如果刪除的是設(shè)備主地址結(jié)構(gòu)
struct in_ifaddr *ifa;
struct in_ifaddr **ifap1 = &ifa1->ifa_next; 取下一地址指針的地址

while ((ifa=*ifap1) != NULL) {
if (!(ifa->ifa_flags&IFA_F_SECONDARY) || 如果為主地址
ifa1->ifa_mask != ifa->ifa_mask ||
!inet_ifa_match(ifa1->ifa_address, ifa)) {
ifap1 = &ifa->ifa_next;
continue;
}
write_lock_bh(&in_dev->lock);
*ifap1 = ifa->ifa_next;
write_unlock_bh(&in_dev->lock);

rtmsg_ifa(RTM_DELADDR, ifa);
notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa); 發(fā)布設(shè)備停機(jī)消息
inet_free_ifa(ifa);
}
}

/* 2. Unlink it */

write_lock_bh(&in_dev->lock);
*ifap = ifa1->ifa_next; 從設(shè)備地址鏈中刪除該地址標(biāo)簽
write_unlock_bh(&in_dev->lock);

/* 3. Announce address deletion */

/* Send message first, then call notifier.
At first sight, FIB update triggered by notifier
will refer to already deleted ifaddr, that could confuse
netlink listeners. It is not true: look, gated sees
that route deleted and if it still thinks that ifaddr
is valid, it will try to restore deleted routes... Grr.
So that, this order is correct.
*/
rtmsg_ifa(RTM_DELADDR, ifa1);
notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
if (destroy) {
inet_free_ifa(ifa1);

if (in_dev->ifa_list == NULL)
inetdev_destroy(in_dev);
}
}
static void inetdev_destroy(struct in_device *in_dev)
{
struct in_ifaddr *ifa;

ASSERT_RTNL();

in_dev->dead = 1;

ip_mc_destroy_dev(in_dev);

while ((ifa = in_dev->ifa_list) != NULL) {
inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
inet_free_ifa(ifa);
}

#ifdef CONFIG_SYSCTL
devinet_sysctl_unregister(&in_dev->cnf);
#endif
write_lock_bh(&inetdev_lock);
in_dev->dev->ip_ptr = NULL;
/* in_dev_put following below will kill the in_device */
write_unlock_bh(&inetdev_lock);


neigh_parms_release(&arp_tbl, in_dev->arp_parms);
in_dev_put(in_dev);
}
struct in_device *inetdev_init(struct net_device *dev)
{
struct in_device *in_dev;

ASSERT_RTNL();

in_dev = kmalloc(sizeof(*in_dev), GFP_KERNEL);
if (!in_dev)
return NULL;
memset(in_dev, 0, sizeof(*in_dev));
in_dev->lock = RW_LOCK_UNLOCKED;
memcpy(&in_dev->cnf, &ipv4_devconf_dflt, sizeof(in_dev->cnf));
in_dev->cnf.sysctl = NULL;
in_dev->dev = dev;
if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL) {
kfree(in_dev);
return NULL;
}
inet_dev_count++;
/* Reference in_dev->dev */
dev_hold(dev);
#ifdef CONFIG_SYSCTL
neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4");
#endif
write_lock_bh(&inetdev_lock);
dev->ip_ptr = in_dev;
/* Account for reference dev->ip_ptr */
in_dev_hold(in_dev);
write_unlock_bh(&inetdev_lock);
#ifdef CONFIG_SYSCTL
devinet_sysctl_register(in_dev, &in_dev->cnf);
#endif
if (dev->flags&IFF_UP)
ip_mc_up(in_dev);
return in_dev;
}
static __inline__ void inet_free_ifa(struct in_ifaddr *ifa)
{
if (ifa->ifa_dev)
__in_dev_put(ifa->ifa_dev);
kfree(ifa);
inet_ifa_count--;
}
static struct in_ifaddr * inet_alloc_ifa(void)
{
struct in_ifaddr *ifa;

ifa = kmalloc(sizeof(*ifa), GFP_KERNEL);
if (ifa) {
memset(ifa, 0, sizeof(*ifa));
inet_ifa_count++;
}

return ifa;
}
extern __inline__ struct in_device *
in_dev_get(const struct net_device *dev)
{
struct in_device *in_dev;

read_lock(&inetdev_lock);
in_dev = dev->ip_ptr;
if (in_dev)
atomic_inc(&in_dev->refcnt);
read_unlock(&inetdev_lock);
return in_dev;
}

extern __inline__ struct in_device *
__in_dev_get(const struct net_device *dev)
{
return (struct in_device*)dev->ip_ptr;
}

extern __inline__ void
in_dev_put(struct in_device *idev)
{
if (atomic_dec_and_test(&idev->refcnt))
in_dev_finish_destroy(idev);
}
void in_dev_finish_destroy(struct in_device *idev)
{
struct net_device *dev = idev->dev;

BUG_TRAP(idev->ifa_list==NULL);
BUG_TRAP(idev->mc_list==NULL);
#ifdef NET_REFCNT_DEBUG
printk(KERN_DEBUG "in_dev_finish_destroy: %p=%s ", idev, dev ? dev->name : "NIL");
#endif
dev_put(dev);
if (!idev->dead) {
printk("Freeing alive in_device %p ", idev);
return;
}
inet_dev_count--;
kfree(idev);
}


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多